use of org.hypertrace.core.datamodel.Event in project hypertrace-ingester by hypertrace.
the class RawSpansGrouperTest method whenRawSpansAreReceivedWithInactivityExpectTraceToBeOutput.
@Test
@SetEnvironmentVariable(key = "SERVICE_NAME", value = "raw-spans-grouper")
public void whenRawSpansAreReceivedWithInactivityExpectTraceToBeOutput(@TempDir Path tempDir) {
File file = tempDir.resolve("state").toFile();
RawSpansGrouper underTest = new RawSpansGrouper(ConfigClientFactory.getClient());
Config config = ConfigFactory.parseURL(getClass().getClassLoader().getResource("configs/raw-spans-grouper/application.conf"));
Map<String, Object> baseProps = underTest.getBaseStreamsConfig();
Map<String, Object> streamsProps = underTest.getStreamsConfig(config);
baseProps.forEach(streamsProps::put);
Map<String, Object> mergedProps = streamsProps;
mergedProps.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, SpecificAvroSerde.class);
mergedProps.put(RawSpanGrouperConstants.RAW_SPANS_GROUPER_JOB_CONFIG, config);
mergedProps.put(StreamsConfig.STATE_DIR_CONFIG, file.getAbsolutePath());
StreamsBuilder streamsBuilder = underTest.buildTopology(mergedProps, new StreamsBuilder(), new HashMap<>());
Properties props = new Properties();
mergedProps.forEach(props::put);
Serde defaultValueSerde = new StreamsConfig(mergedProps).defaultValueSerde();
Serde<TraceIdentity> traceIdentitySerde = new StreamsConfig(mergedProps).defaultKeySerde();
TopologyTestDriver td = new TopologyTestDriver(streamsBuilder.build(), props);
TestInputTopic<TraceIdentity, RawSpan> inputTopic = td.createInputTopic(config.getString(RawSpanGrouperConstants.INPUT_TOPIC_CONFIG_KEY), traceIdentitySerde.serializer(), defaultValueSerde.serializer());
TestOutputTopic outputTopic = td.createOutputTopic(config.getString(RawSpanGrouperConstants.OUTPUT_TOPIC_CONFIG_KEY), Serdes.String().deserializer(), defaultValueSerde.deserializer());
String tenantId = "tenant1";
// create spans for trace-1 of tenant1
RawSpan span1 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-1".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-1", "tenant1")).build();
RawSpan span2 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-1".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-2", "tenant1")).build();
RawSpan span3 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-1".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-3", "tenant1")).build();
// create spans for trace-2 of tenant1
RawSpan span4 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-2".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-4", "tenant1")).build();
RawSpan span5 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-2".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-5", "tenant1")).build();
// create spans for trace-3 of tenant1
RawSpan span6 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-6", "tenant1")).build();
RawSpan span7 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-7", "tenant1")).build();
RawSpan span8 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-8", "tenant1")).build();
RawSpan span9 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-9", "tenant1")).build();
RawSpan span10 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-10", "tenant1")).build();
RawSpan span11 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-3".getBytes())).setCustomerId("tenant1").setEvent(createEvent("event-11", "tenant1")).build();
// create 8 spans for tenant-2 for trace-4
String tenant2 = "tenant2";
RawSpan span12 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-12", tenant2)).build();
RawSpan span13 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-13", tenant2)).build();
RawSpan span14 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-14", tenant2)).build();
RawSpan span15 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-15", tenant2)).build();
RawSpan span16 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-16", tenant2)).build();
RawSpan span17 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-17", tenant2)).build();
RawSpan span18 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-18", tenant2)).build();
RawSpan span19 = RawSpan.newBuilder().setTraceId(ByteBuffer.wrap("trace-4".getBytes())).setCustomerId(tenant2).setEvent(createEvent("event-19", tenant2)).build();
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-1"), span1);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-2"), span4);
td.advanceWallClockTime(Duration.ofSeconds(1));
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-1"), span2);
// select a value < 30s (groupingWindowTimeoutInMs)
// this shouldn't trigger a punctuate call
td.advanceWallClockTime(Duration.ofMillis(200));
assertTrue(outputTopic.isEmpty());
// the next advance should trigger a punctuate call and emit a trace with 2 spans
td.advanceWallClockTime(Duration.ofSeconds(32));
// trace1 should have 2 span span1, span2
StructuredTrace trace = (StructuredTrace) outputTopic.readValue();
assertEquals(2, trace.getEventList().size());
Set<String> traceEventIds = trace.getEventList().stream().map(id -> new String(id.getEventId().array())).collect(Collectors.toSet());
assertTrue(traceEventIds.contains("event-1"));
assertTrue(traceEventIds.contains("event-2"));
// trace2 should have 1 span span3
trace = (StructuredTrace) outputTopic.readValue();
assertEquals(1, trace.getEventList().size());
assertEquals("event-4", new String(trace.getEventList().get(0).getEventId().array()));
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-1"), span3);
td.advanceWallClockTime(Duration.ofSeconds(45));
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-2"), span5);
// the next advance should trigger a punctuate call and emit a trace with 2 spans
td.advanceWallClockTime(Duration.ofSeconds(35));
// trace1 should have 1 span i.e. span3
trace = (StructuredTrace) outputTopic.readValue();
assertEquals(1, trace.getEventList().size());
assertEquals("event-3", new String(trace.getEventList().get(0).getEventId().array()));
// trace2 should have 1 span i.e. span4
trace = (StructuredTrace) outputTopic.readValue();
assertEquals(1, trace.getEventList().size());
assertEquals("event-5", new String(trace.getEventList().get(0).getEventId().array()));
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span6);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span7);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span8);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span9);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span10);
inputTopic.pipeInput(createTraceIdentity(tenantId, "trace-3"), span11);
td.advanceWallClockTime(Duration.ofSeconds(35));
// trace should be truncated with 5 spans
trace = (StructuredTrace) outputTopic.readValue();
assertEquals(5, trace.getEventList().size());
// input 8 spans of trace-4 for tenant2, as there is global upper limit apply, it will emit only
// 6
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span12);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span13);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span14);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span15);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span16);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span17);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span18);
inputTopic.pipeInput(createTraceIdentity(tenant2, "trace-4"), span19);
td.advanceWallClockTime(Duration.ofSeconds(35));
trace = (StructuredTrace) outputTopic.readValue();
assertEquals(6, trace.getEventList().size());
}
use of org.hypertrace.core.datamodel.Event in project hypertrace-ingester by hypertrace.
the class RawServiceViewGenerator method generateView.
@Override
List<RawServiceView> generateView(StructuredTrace structuredTrace, Map<String, Entity> entityMap, Map<ByteBuffer, Event> eventMap, Map<ByteBuffer, List<ByteBuffer>> parentToChildrenEventIds, Map<ByteBuffer, ByteBuffer> childToParentEventIds) {
List<RawServiceView> list = new ArrayList<>();
// Construct ApiTraceGraph and look at all the head spans within each ApiNode
ApiTraceGraph apiTraceGraph = ViewGeneratorState.getApiTraceGraph(structuredTrace);
List<ApiNode<Event>> apiNodes = apiTraceGraph.getApiNodeList();
for (ApiNode<Event> apiNode : apiNodes) {
Event event = apiNode.getHeadEvent();
if (EnrichedSpanUtils.containsServiceId(event)) {
RawServiceView.Builder builder = fastNewBuilder(RawServiceView.Builder.class);
builder.setTenantId(structuredTrace.getCustomerId());
builder.setTraceId(structuredTrace.getTraceId());
builder.setSpanId(event.getEventId());
builder.setParentSpanId(childToParentEventIds.get(event.getEventId()));
builder.setServiceName(EnrichedSpanUtils.getServiceName(event));
builder.setServiceId(EnrichedSpanUtils.getServiceId(event));
builder.setApiName(EnrichedSpanUtils.getApiName(event));
builder.setApiId(EnrichedSpanUtils.getApiId(event));
builder.setApiDiscoveryState(EnrichedSpanUtils.getApiDiscoveryState(event));
builder.setStartTimeMillis(event.getStartTimeMillis());
builder.setEndTimeMillis(event.getEndTimeMillis());
builder.setDurationMillis(event.getEndTimeMillis() - event.getStartTimeMillis());
builder.setTransactionName(getTransactionName(structuredTrace));
String spanType = EnrichedSpanUtils.getSpanType(event);
if (spanType != null) {
builder.setSpanKind(spanType);
}
Protocol protocol = EnrichedSpanUtils.getProtocol(event);
if (protocol == null || protocol == Protocol.PROTOCOL_UNSPECIFIED) {
/* In the view, we want to replace unknown with empty string instead
* for better representation in the UI and easier to filter */
builder.setProtocolName(EMPTY_STRING);
} else {
builder.setProtocolName(protocol.name());
}
builder.setStatusCode(EnrichedSpanUtils.getStatusCode(event));
// If this is an API entry boundary span, copy the error count from the event to the view
// because we want only API or service errors to be present in the view.
MetricValue errorMetric = event.getMetrics().getMetricMap().get(EnrichedSpanConstants.getValue(ErrorMetrics.ERROR_METRICS_ERROR_COUNT));
if (errorMetric != null && errorMetric.getValue() > 0.0d) {
builder.setErrorCount((int) errorMetric.getValue().doubleValue());
}
// Copy the exception count metric to view directly.
MetricValue exceptionMetric = event.getMetrics().getMetricMap().get(EnrichedSpanConstants.getValue(ErrorMetrics.ERROR_METRICS_EXCEPTION_COUNT));
if (exceptionMetric != null && exceptionMetric.getValue() > 0.0d) {
builder.setExceptionCount((int) exceptionMetric.getValue().doubleValue());
}
if (EnrichedSpanUtils.isEntrySpan(event)) {
builder.setNumCalls(1);
}
builder.setSpaceIds(EnrichedSpanUtils.getSpaceIds(event));
list.add(builder.build());
}
}
return list;
}
use of org.hypertrace.core.datamodel.Event in project hypertrace-ingester by hypertrace.
the class RawTraceViewGenerator method generateView.
@Override
List<RawTraceView> generateView(StructuredTrace structuredTrace, Map<String, Entity> entityMap, Map<ByteBuffer, Event> eventMap, Map<ByteBuffer, List<ByteBuffer>> parentToChildrenEventIds, Map<ByteBuffer, ByteBuffer> childToParentEventIds) {
RawTraceView.Builder builder = fastNewBuilder(RawTraceView.Builder.class);
builder.setTenantId(structuredTrace.getCustomerId());
builder.setTraceId(structuredTrace.getTraceId());
String transactionName = getTransactionName(structuredTrace);
if (transactionName != null) {
builder.setTransactionName(transactionName);
}
builder.setStartTimeMillis(structuredTrace.getStartTimeMillis());
builder.setEndTimeMillis(structuredTrace.getEndTimeMillis());
builder.setDurationMillis(structuredTrace.getEndTimeMillis() - structuredTrace.getStartTimeMillis());
Set<String> services = new HashSet<>();
for (Event event : structuredTrace.getEventList()) {
String serviceName = EnrichedSpanUtils.getServiceName(event);
if (serviceName != null) {
services.add(serviceName);
}
}
builder.setNumSpans(structuredTrace.getEventList().size());
builder.setNumServices(services.size());
builder.setServices(new ArrayList<>(services));
builder.setSpaceIds(getSpaceIdsFromTrace(structuredTrace));
return Lists.newArrayList(builder.build());
}
use of org.hypertrace.core.datamodel.Event in project hypertrace-ingester by hypertrace.
the class SpanEventViewGenerator method getDisplayEntityName.
/**
* The entity(service or backend) name to be displayed on the UI. For an entry or internal(not
* entry or exit) span it will be the same as the span's service_name. for an exit span: - if the
* span maps to an api entry span in {@code exitSpanToCalleeApiEntrySpanMap} api entry service
* name - if backend name is set, we return the backend name - if the backend name is not set, we
* return the span's service name
*/
String getDisplayEntityName(Event span, Map<ByteBuffer, Event> exitSpanToCalleeApiEntrySpanMap) {
if (!EnrichedSpanUtils.isExitSpan(span)) {
// Not an EXIT span(ENTRY or INTERNAL)
return EnrichedSpanUtils.getServiceName(span);
}
// Exit span with a callee API entry
Event apiEntrySpan = exitSpanToCalleeApiEntrySpanMap.get(span.getEventId());
if (apiEntrySpan != null) {
// Use Callee service name
return EnrichedSpanUtils.getServiceName(apiEntrySpan);
}
// Backend exit span.
String backendName = EnrichedSpanUtils.getBackendName(span);
if (backendName != null && !backendName.isEmpty()) {
// Backend name if it's not empty
return backendName;
}
// Use the span's service name if for some reason the backend is unknown
return EnrichedSpanUtils.getServiceName(span);
}
use of org.hypertrace.core.datamodel.Event in project hypertrace-ingester by hypertrace.
the class SpanEventViewGenerator method generateViewBuilder.
private SpanEventView.Builder generateViewBuilder(Event event, ByteBuffer traceId, Map<ByteBuffer, Event> eventMap, Map<ByteBuffer, ByteBuffer> childToParentEventIds, Map<ByteBuffer, Event> exitSpanToCalleeApiEntrySpanMap) {
SpanEventView.Builder builder = fastNewBuilder(SpanEventView.Builder.class);
builder.setTenantId(event.getCustomerId());
builder.setSpanId(event.getEventId());
builder.setEventName(event.getEventName());
// api_trace_id
ByteBuffer apiEntrySpanId = EnrichedSpanUtils.getApiEntrySpanId(event, eventMap, childToParentEventIds);
builder.setApiTraceId(apiEntrySpanId);
if (event.getEventId().equals(apiEntrySpanId)) {
// set this count to 1 only if this span is the head of the Api Trace
builder.setApiTraceCount(1);
if (SpanAttributeUtils.containsAttributeKey(event, EnrichedSpanConstants.API_CALLEE_NAME_COUNT_ATTRIBUTE)) {
builder.setApiCalleeNameCount(SpanAttributeUtils.getAttributeValue(event, EnrichedSpanConstants.API_CALLEE_NAME_COUNT_ATTRIBUTE).getValueMap());
}
} else {
builder.setApiTraceCount(0);
}
// span_type
String spanType = getStringAttribute(event, EnrichedSpanConstants.getValue(CommonAttribute.COMMON_ATTRIBUTE_SPAN_TYPE));
if (spanType != null) {
builder.setSpanKind(spanType);
}
// parent_span_id
ByteBuffer parentEventId = childToParentEventIds.get(event.getEventId());
if (parentEventId != null) {
builder.setParentSpanId(parentEventId);
}
// trace_id
builder.setTraceId(traceId);
// service_id, service_name
builder.setServiceId(EnrichedSpanUtils.getServiceId(event));
builder.setServiceName(EnrichedSpanUtils.getServiceName(event));
// api_id, api_name, api_discovery_state
builder.setApiId(EnrichedSpanUtils.getApiId(event));
builder.setApiName(EnrichedSpanUtils.getApiName(event));
builder.setApiDiscoveryState(EnrichedSpanUtils.getApiDiscoveryState(event));
// entry_api_id
Event entryApiSpan = EnrichedSpanUtils.getApiEntrySpan(event, eventMap, childToParentEventIds);
if (entryApiSpan != null) {
builder.setEntryApiId(EnrichedSpanUtils.getApiId(entryApiSpan));
}
// display entity and span names
builder.setDisplayEntityName(getDisplayEntityName(event, exitSpanToCalleeApiEntrySpanMap));
builder.setDisplaySpanName(getDisplaySpanName(event, exitSpanToCalleeApiEntrySpanMap));
// protocol_name
Protocol protocol = EnrichedSpanUtils.getProtocol(event);
if (protocol == null || protocol == Protocol.PROTOCOL_UNSPECIFIED) {
/* In the view, we want to replace unknown with empty string instead
* for better representation in the UI and easier to filter */
builder.setProtocolName(EMPTY_STRING);
} else {
builder.setProtocolName(EnrichedSpanConstants.getValue(protocol));
}
builder.setTags(getAttributeMap(event.getAttributes()));
// request_url
builder.setRequestUrl(getRequestUrl(event, protocol));
// status_code
builder.setStatusCode(EnrichedSpanUtils.getStatusCode(event));
builder.setStatus(EnrichedSpanUtils.getStatus(event));
builder.setStatusMessage(EnrichedSpanUtils.getStatusMessage(event));
// set boundary type with default value as empty string to avoid null value
builder.setApiBoundaryType(getStringAttribute(event, EnrichedSpanConstants.getValue(Api.API_BOUNDARY_TYPE)));
// start_time_millis, end_time_millis, duration_millis
builder.setStartTimeMillis(event.getStartTimeMillis());
builder.setEndTimeMillis(event.getEndTimeMillis());
builder.setDurationMillis(event.getEndTimeMillis() - event.getStartTimeMillis());
// error count
MetricValue errorMetric = event.getMetrics().getMetricMap().get(ERROR_COUNT_CONSTANT);
if (errorMetric != null && errorMetric.getValue() > 0.0d) {
builder.setErrorCount((int) errorMetric.getValue().doubleValue());
}
builder.setSpans(1);
MetricValue exceptionMetric = event.getMetrics().getMetricMap().get(EXCEPTION_COUNT_CONSTANT);
if (exceptionMetric != null && exceptionMetric.getValue() > 0.0d) {
builder.setExceptionCount((int) exceptionMetric.getValue().doubleValue());
}
builder.setSpaceIds(EnrichedSpanUtils.getSpaceIds(event));
builder.setApiExitCalls(Integer.parseInt(SpanAttributeUtils.getStringAttributeWithDefault(event, EnrichedSpanConstants.API_EXIT_CALLS_ATTRIBUTE, "0")));
builder.setApiTraceErrorSpanCount(Integer.parseInt(SpanAttributeUtils.getStringAttributeWithDefault(event, EnrichedSpanConstants.API_TRACE_ERROR_SPAN_COUNT_ATTRIBUTE, "0")));
return builder;
}
Aggregations