use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class DefaultServiceEntityEnricher method enrichEvent.
@Override
public void enrichEvent(StructuredTrace trace, Event event) {
// Nothing to do if the span already has service id on it
if (EnrichedSpanUtils.getServiceId(event) != null) {
return;
}
// If there is serviceName present in the span, just go ahead and create a service
// entity with those details. This is to support BareMetal case.
String serviceName = event.getServiceName();
if (serviceName != null) {
// Check if the exit span's jaeger_svcname is different from the parent span's jaeger_svcname
// If it is then use the parent span's jaeger_svcname as the exit span's jaeger svc name else
// just use the jaeger svc name as is.
// This will give us 2 things:
// 1. No service corresponding to exit span will be registered
// (Typically this is an example where a facade service is created for a backend.
// See redis and mysql in HotROD app for an example).
// The actual service name on the exit span will instead be registered
// as a backend by the {@link ClientSpanEndpointResolver}
// 2. Enrich the exit span with the parent span's service entity.
// This will enable creating an edge between the exit span and the backend
StructuredTraceGraph graph = buildGraph(trace);
if (EnrichedSpanUtils.isExitSpan(event) && SpanAttributeUtils.isLeafSpan(graph, event)) {
String parentSvcName = findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService(event, serviceName, graph).orElse(null);
if (parentSvcName != null) {
serviceName = parentSvcName;
} else {
// create backend entity at {@link ClientSpanEndpointResolver} if service and peer service
// are same
String peerServiceName = SpanSemanticConventionUtils.getPeerServiceName(event);
if (peerServiceName != null && peerServiceName.equals(serviceName)) {
return;
}
}
}
Map<String, String> attributes = Map.of(SPAN_ID_KEY, HexUtils.getHex(event.getEventId()), TRACE_ID_KEY, HexUtils.getHex(trace.getTraceId()));
org.hypertrace.entity.data.service.v1.Entity entity = factory.getService(event.getCustomerId(), serviceName, ServiceType.JAEGER_SERVICE.name(), attributes);
org.hypertrace.core.datamodel.Entity avroEntity = EntityAvroConverter.convertToAvroEntity(entity, false);
if (avroEntity != null) {
addEntity(trace, event, avroEntity);
addEnrichedAttribute(event, SERVICE_ID_ATTR_NAME, AttributeValueCreator.create(avroEntity.getEntityId()));
addEnrichedAttribute(event, SERVICE_NAME_ATTR_NAME, AttributeValueCreator.create(avroEntity.getEntityName()));
}
}
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class StructuredTraceGraphBuilderTest method testBuildGraph.
@Test
void testBuildGraph() {
Entity entity = mock(Entity.class);
Event parent = mock(Event.class);
Event child = mock(Event.class);
Edge eventEdge = mock(Edge.class);
StructuredTrace underTestTrace = mock(StructuredTrace.class);
when(underTestTrace.getCustomerId()).thenReturn("__defaultTenant");
when(underTestTrace.getTraceId()).thenReturn(ByteBuffer.wrap("2ebbc19b6428510f".getBytes()));
when(underTestTrace.getEntityList()).thenReturn(List.of(entity));
when(underTestTrace.getEventList()).thenReturn(List.of(parent, child));
when(underTestTrace.getEntityEdgeList()).thenReturn(List.of());
when(underTestTrace.getEntityEventEdgeList()).thenReturn(List.of());
when(underTestTrace.getEventEdgeList()).thenReturn(List.of(eventEdge));
try (MockedStatic<StructuredTrace> builderMockedStatic = mockStatic(StructuredTrace.class)) {
StructuredTrace.Builder builder = mock(StructuredTrace.Builder.class);
when(builder.build()).thenReturn(underTestTrace);
builderMockedStatic.when(() -> StructuredTrace.newBuilder(underTestTrace)).thenReturn(builder);
try (MockedConstruction<StructuredTraceGraph> mocked = mockConstruction(StructuredTraceGraph.class)) {
// calls first time
StructuredTraceGraph actual = StructuredTraceGraphBuilder.buildGraph(underTestTrace);
// calls second time, this time it returns from cache
StructuredTraceGraph cached = StructuredTraceGraphBuilder.buildGraph(underTestTrace);
Assertions.assertEquals(actual, cached);
}
}
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class TraceUI method build.
public static TraceUI build(StructuredTrace trace) {
StructuredTraceGraph graph = new StructuredTraceGraph(trace);
Set<Event> roots = findRootEvents(trace);
Set<JSONObject> rootJsons = new HashSet<>();
for (Event root : roots) {
JSONObject jsonObject = new JSONObject();
rootJsons.add(jsonObject);
Queue<Pair<Event, List<Integer>>> q = new LinkedList<>();
q.add(Pair.of(root, new ArrayList<>()));
jsonObject.put("id", HexUtils.getHex(root.getEventId()));
jsonObject.put("name", root.getEventName());
jsonObject.put("parent", "null");
jsonObject.put("attributes", flattenAttributes(root));
jsonObject.put("children", new JSONArray());
while (!q.isEmpty()) {
Pair<Event, List<Integer>> p = q.remove();
Event e = p.getLeft();
List<Integer> list = p.getRight();
List<Event> children = graph.getChildrenEvents(e);
if (children != null) {
for (int i = 0; i < children.size(); i++) {
Event child = children.get(i);
JSONArray jsonArray = jsonObject.getJSONArray("children");
for (Integer index : list) {
JSONObject childJsonObject = jsonArray.getJSONObject(index);
jsonArray = childJsonObject.getJSONArray("children");
}
JSONObject childJsonObject = new JSONObject();
childJsonObject.put("id", HexUtils.getHex(child.getEventId()));
childJsonObject.put("name", child.getEventName());
childJsonObject.put("parent", HexUtils.getHex(e.getEventId()));
childJsonObject.put("attributes", flattenAttributes(child));
childJsonObject.put("children", new JSONArray());
jsonArray.put(childJsonObject);
ArrayList<Integer> indexesList = new ArrayList<>(list);
indexesList.add(i);
Pair<Event, List<Integer>> pairForChild = Pair.of(child, indexesList);
q.add(pairForChild);
}
}
}
}
return new TraceUI(trace, rootJsons);
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class DefaultServiceEntityEnricherTest method test_case6_findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService.
@Test
public void test_case6_findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService() {
// Case 6: sampleapp (entry) -> sampleapp (entry) -> sampleapp (exit)
Event parent1 = createEvent(TENANT_ID, "parent1", Map.of("span.kind", "server"), Map.of(API_BOUNDARY_TYPE_ATTR, "ENTRY", "SERVICE_NAME", "sampleapp"), null, "sampleapp");
Event parent2 = createEvent(TENANT_ID, "parent2", Map.of("span.kind", "client"), Map.of(API_BOUNDARY_TYPE_ATTR, "ENTRY", "SERVICE_NAME", "sampleapp"), ByteBuffer.wrap("parent1".getBytes()), "sampleapp");
Event current = createEvent(TENANT_ID, "current", Map.of("span.kind", "client"), Map.of(API_BOUNDARY_TYPE_ATTR, "EXIT"), ByteBuffer.wrap("parent2".getBytes()), "sampleapp");
StructuredTraceGraph graph = mock(StructuredTraceGraph.class);
when(graph.getParentEvent(current)).thenReturn(parent2);
String actual = enricher.findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService(current, "sampleapp", graph).orElse(null);
String expected = null;
assertEquals(expected, actual);
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class DefaultServiceEntityEnricherTest method test_case5_findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService.
@Test
public void test_case5_findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService() {
// Case 4: sampleapp (exit)
Event current = createEvent(TENANT_ID, "current", Map.of("span.kind", "client"), Map.of(API_BOUNDARY_TYPE_ATTR, "EXIT"), null, "sampleapp");
StructuredTraceGraph graph = mock(StructuredTraceGraph.class);
when(graph.getParentEvent(current)).thenReturn(null);
String actual = enricher.findServiceNameOfFirstAncestorThatIsNotAnExitSpanAndBelongsToADifferentService(current, "sampleapp", graph).orElse(null);
String expected = null;
assertEquals(expected, actual);
}
Aggregations