Skip to content

Commit

Permalink
Merge pull request #160 from ruromero/client-name
Browse files Browse the repository at this point in the history
feat: Enhance telemetry data
  • Loading branch information
ruromero authored Sep 19, 2023
2 parents d201693 + 329c200 commit f1e6e93
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 34 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,12 @@ The possible responses are:

## Telemetry

API Clients are expected to send a `rhda-token` HTTP Header that will be used to correlate
different events related to the same user.
If the header is not provided an anonymous event with a generated UUID will be sent instead.
API Clients are expected to send the following HTTP Headers in order to help observe the use of the Backend service:

- `rhda-token` HTTP Header that will be used to correlate different events related to the same user. If the header
is not provided an anonymous event with a generated UUID will be sent instead.
- `rhda-source` The client consuming the Exhort API. It will default to the `User-Agent` HTTP Header
- `rhda-operation-type` When performing an analysis, clients might specify whether it is a component-analysis or a stack-analysis

Telemetry connects to [Segment](https://segment.com/) for sending events.
The connection can be configured with the following properties.
Expand Down
83 changes: 54 additions & 29 deletions src/main/java/com/redhat/exhort/analytics/AnalyticsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.concurrent.atomic.AtomicLong;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
Expand All @@ -51,7 +52,11 @@ public class AnalyticsService {

private static final Logger LOGGER = LoggerFactory.getLogger(AnalyticsService.class);

private static final String RHDA_TOKEN = "rhda-token";
private static final String RHDA_TOKEN_HEADER = "rhda-token";
private static final String RHDA_SOURCE_HEADER = "rhda-source";
private static final String RHDA_OPERATION_TYPE_HEADER = "rhda-operation-type";
private static final String USER_AGENT_HEADER = "User-Agent";

private static final String ANONYMOUS_ID = "telemetry-anonymous-id";
private static final String ANALYSIS_EVENT = "rhda.exhort.analysis";
private static final String TOKEN_EVENT = "rhda.exhort.token";
Expand All @@ -78,35 +83,36 @@ public void identify(Exchange exchange) {
return;
}

String userId = exchange.getIn().getHeader(RHDA_TOKEN, String.class);
String userId = exchange.getIn().getHeader(RHDA_TOKEN_HEADER, String.class);
Map<String, String> traits = new HashMap<>();
traits.put("serverName", projectName);
traits.put("serverVersion", projectVersion);
traits.put("serverBuild", projectBuild);

IdentifyEvent.Builder builder =
new IdentifyEvent.Builder()
.context(
new Context(new Library(projectId, projectVersion), getSource(exchange.getIn())))
.traits(traits);

if (userId == null) {
String anonymousId = UUID.randomUUID().toString();
Map<String, String> traits = new HashMap<>();
traits.put("serverName", projectName);
traits.put("serverVersion", projectVersion);
traits.put("serverBuild", projectBuild);
IdentifyEvent event =
new IdentifyEvent.Builder()
.context(new Context(new Library(projectId, projectVersion)))
.anonymousId(anonymousId)
.traits(traits)
.build();
try {
Response response = segmentService.identify(event);
if (response.getStatus() >= 400) {
LOGGER.warn(
String.format(
"Unable to send event to segment: %d - %s",
response.getStatus(), response.getStatusInfo()));
}
} catch (Exception e) {
LOGGER.warn("Unable to send event to segment", e);
}
builder.anonymousId(anonymousId);
exchange.setProperty(ANONYMOUS_ID, anonymousId);
} else {
// no need to IDENTIFY as we expect the caller to have done that already
exchange.setProperty(RHDA_TOKEN, userId);
exchange.getIn().removeHeader(RHDA_TOKEN);
builder.userId(userId);
exchange.setProperty(RHDA_TOKEN_HEADER, userId);
}
try {
Response response = segmentService.identify(builder.build());
if (response.getStatus() >= 400) {
LOGGER.warn(
String.format(
"Unable to send event to segment: %d - %s",
response.getStatus(), response.getStatusInfo()));
}
} catch (Exception e) {
LOGGER.warn("Unable to send event to segment", e);
}
}

Expand All @@ -132,6 +138,10 @@ public void trackAnalysis(Exchange exchange) {
snykReport.put("remediations", countRemediations(report));
providers.put(Constants.SNYK_PROVIDER, snykReport);
properties.put("providers", providers);
String operationType = exchange.getIn().getHeader(RHDA_OPERATION_TYPE_HEADER, String.class);
if (operationType != null) {
properties.put("operationType", operationType);
}
}
try {
Response response = segmentService.track(builder.properties(properties).build());
Expand Down Expand Up @@ -168,16 +178,31 @@ public void trackToken(Exchange exchange) {
}
}

private String getSource(Message message) {
String customSource = message.getHeader(RHDA_SOURCE_HEADER, String.class);
if (customSource != null) {
return customSource;
}
String userAgent = message.getHeader(USER_AGENT_HEADER, String.class);
if (userAgent != null) {
return userAgent;
}
return null;
}

private TrackEvent.Builder prepareTrackEvent(Exchange exchange, String eventName) {
TrackEvent.Builder builder = new TrackEvent.Builder(eventName);
String userId = exchange.getProperty(RHDA_TOKEN, String.class);
TrackEvent.Builder builder =
new TrackEvent.Builder(eventName)
.context(
new Context(new Library(projectId, projectVersion), getSource(exchange.getIn())));
String userId = exchange.getProperty(RHDA_TOKEN_HEADER, String.class);
if (userId != null) {
builder.userId(userId);
} else {
String anonymousId = exchange.getProperty(ANONYMOUS_ID, String.class);
builder.anonymousId(anonymousId);
}
return builder.context(new Context(new Library(projectId, projectVersion)));
return builder;
}

private long countRemediations(AnalysisReport report) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@

package com.redhat.exhort.analytics.segment;

public record Context(Library library) {}
import static com.fasterxml.jackson.annotation.JsonInclude.Include;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(Include.NON_NULL)
public record Context(Library library, String source) {}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,6 @@ private void cleanUpHeaders(Exchange exchange) {
msg.removeHeaders("ex-.*-user");
msg.removeHeaders("ex-.*-token");
msg.removeHeader("Authorization");
msg.removeHeader(Constants.RHDA_TOKEN_HEADER);
msg.removeHeaders("rhda-.*");
}
}

0 comments on commit f1e6e93

Please sign in to comment.