use of org.hypertrace.core.datamodel.Edge in project hypertrace-ingester by hypertrace.
the class ApiTraceGraph method buildApiNodeEdges.
private void buildApiNodeEdges(StructuredTraceGraph graph) {
// 4. connect the exit boundary and entry boundary of different api node with an edge
for (ApiNode<Event> apiNode : apiNodeList) {
// exit boundary events of api node
List<Event> exitBoundaryEvents = apiNode.getExitApiBoundaryEvents();
for (Event exitBoundaryEvent : exitBoundaryEvents) {
List<Event> exitBoundaryEventChildren = graph.getChildrenEvents(exitBoundaryEvent);
if (exitBoundaryEventChildren != null) {
for (Event exitBoundaryEventChild : exitBoundaryEventChildren) {
// always!
if (EnrichedSpanUtils.isEntryApiBoundary(exitBoundaryEventChild)) {
// get the api node exit boundary event is connecting to
ApiNode<Event> destinationApiNode = entryApiBoundaryEventIdToApiNode.get(exitBoundaryEventChild.getEventId());
Optional<ApiNodeEventEdge> edgeBetweenApiNodes = createEdgeBetweenApiNodes(apiNode, destinationApiNode, exitBoundaryEvent, exitBoundaryEventChild);
edgeBetweenApiNodes.ifPresent(edge -> {
apiNodeEventEdgeList.add(edge);
apiExitBoundaryEventIdxWithOutgoingEdge.add(edge.getSrcEventIndex());
apiEntryBoundaryEventIdxWithIncomingEdge.add(edge.getTgtEventIndex());
apiNodeIdxToEdges.computeIfAbsent(apiNodeHeadEventIdToIndex.get(apiNode.getHeadEvent().getEventId()), v -> Sets.newHashSet()).add(apiNodeEventEdgeList.size() - 1);
});
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Exit boundary event with eventId: {}, eventName: {}, serviceName: {}," + " can only have entry boundary event as child. Non-entry child:" + " childEventId: {}, childEventName: {}, childServiceName: {}." + " traceId for events: {}", HexUtils.getHex(exitBoundaryEvent.getEventId()), exitBoundaryEvent.getEventName(), exitBoundaryEvent.getServiceName(), HexUtils.getHex(exitBoundaryEventChild.getEventId()), exitBoundaryEventChild.getEventName(), exitBoundaryEventChild.getServiceName(), HexUtils.getHex(trace.getTraceId()));
}
}
}
}
}
// Sometimes an exit span might be missing for services like Istio, Kong.
// Only Entry spans will be populated for these services,
// an edge must be created between these services as well.
// 1. get entry boundary event from an api node.
// 2. find all the children of entry boundary event, which will be entry boundary nodes of
// different api nodes
// 3. Check both parent span and child belong to different service as well.
// 4. connect the entry boundary of different api nodes with an edge.
Optional<Event> entryBoundaryEvent = apiNode.getEntryApiBoundaryEvent();
if (entryBoundaryEvent.isPresent()) {
List<Event> children = graph.getChildrenEvents(entryBoundaryEvent.get());
if (children != null) {
for (Event child : children) {
// which can happen if exit span missing and both belongs to different services.
if (EnrichedSpanUtils.isEntryApiBoundary(child) && EnrichedSpanUtils.areBothSpansFromDifferentService(child, entryBoundaryEvent.get())) {
ApiNode<Event> destinationApiNode = entryApiBoundaryEventIdToApiNode.get(child);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Edge between entry boundaries servicename: {} span: {} to servicename: {} span: {} of trace {}", entryBoundaryEvent.get().getServiceName(), HexUtils.getHex(entryBoundaryEvent.get().getEventId()), child.getServiceName(), HexUtils.getHex(child.getEventId()), HexUtils.getHex(trace.getTraceId()));
}
Optional<ApiNodeEventEdge> edgeBetweenApiNodes = createEdgeBetweenApiNodes(apiNode, destinationApiNode, entryBoundaryEvent.get(), child);
edgeBetweenApiNodes.ifPresent(apiNodeEventEdgeList::add);
}
}
}
}
}
}
use of org.hypertrace.core.datamodel.Edge in project hypertrace-ingester by hypertrace.
the class ApiTraceGraph method createEdgeBetweenApiNodes.
private Optional<ApiNodeEventEdge> createEdgeBetweenApiNodes(ApiNode<Event> srcApiNode, ApiNode<Event> destinationApiNode, Event exitBoundaryEventFromSrcApiNode, Event entryBoundaryEventOfDestinationApiNode) {
if (destinationApiNode != null) {
// get the indexes in apiNodes list to create an edge
Integer srcIndex = apiNodeHeadEventIdToIndex.get(srcApiNode.getHeadEvent().getEventId());
Integer targetIndex = apiNodeHeadEventIdToIndex.get(destinationApiNode.getHeadEvent().getEventId());
// Get the actual edge from trace connecting exitBoundaryEvent and child
Integer srcIndexInTrace = eventIdToIndexInTrace.get(exitBoundaryEventFromSrcApiNode.getEventId());
Integer targetIndexInTrace = eventIdToIndexInTrace.get(entryBoundaryEventOfDestinationApiNode.getEventId());
Edge edgeInTrace = traceEdgeTable.get(srcIndexInTrace, targetIndexInTrace);
if (null == edgeInTrace) {
LOGGER.warn("There should be an edge between src event {} and target event {}", exitBoundaryEventFromSrcApiNode, entryBoundaryEventOfDestinationApiNode);
} else {
ApiNodeEventEdge apiNodeEventEdge = fastNewBuilder(ApiNodeEventEdge.Builder.class).setSrcApiNodeIndex(srcIndex).setTgtApiNodeIndex(targetIndex).setSrcEventIndex(srcIndexInTrace).setTgtEventIndex(targetIndexInTrace).setAttributes(edgeInTrace.getAttributes()).setMetrics(edgeInTrace.getMetrics()).setStartTimeMillis(edgeInTrace.getStartTimeMillis()).setEndTimeMillis(edgeInTrace.getEndTimeMillis()).build();
return Optional.of(apiNodeEventEdge);
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Strange! Entry boundary event {} should already have been discovered as an api node", entryBoundaryEventOfDestinationApiNode);
}
}
return Optional.empty();
}
use of org.hypertrace.core.datamodel.Edge in project hypertrace-ingester by hypertrace.
the class GraphBuilderUtilTest method testIsStructuredTraceChangedForSizeCondition.
@Test
public void testIsStructuredTraceChangedForSizeCondition() {
Entity entity = mock(Entity.class);
Event parent = mock(Event.class);
Event child = mock(Event.class);
Edge eventEdge = mock(Edge.class);
// same size
StructuredTrace cachedTrace = mock(StructuredTrace.class);
when(cachedTrace.getCustomerId()).thenReturn("__defaultTenant");
when(cachedTrace.getTraceId()).thenReturn(ByteBuffer.wrap("2ebbc19b6428510f".getBytes()));
when(cachedTrace.getEntityList()).thenReturn(List.of(entity));
when(cachedTrace.getEventList()).thenReturn(List.of(parent, child));
when(cachedTrace.getEntityEdgeList()).thenReturn(List.of());
when(cachedTrace.getEntityEventEdgeList()).thenReturn(List.of());
when(cachedTrace.getEventEdgeList()).thenReturn(List.of(eventEdge));
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));
boolean result = GraphBuilderUtil.isStructuredTraceChanged(cachedTrace, underTestTrace);
Assertions.assertFalse(result);
}
use of org.hypertrace.core.datamodel.Edge 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.Edge in project hypertrace-ingester by hypertrace.
the class TestUtils method createTraceWithEventsAndEdges.
public static StructuredTrace createTraceWithEventsAndEdges(Event[] events, Map<Integer, int[]> adjList) {
StructuredTrace trace = createStructuredTrace(events);
List<Edge> eventEdgeList = new ArrayList<>();
adjList.forEach((src, list) -> {
for (int target : list) {
eventEdgeList.add(Edge.newBuilder().setSrcIndex(src).setTgtIndex(target).setEdgeType(EdgeType.EVENT_EVENT).build());
}
});
trace.setEventEdgeList(eventEdgeList);
return trace;
}
Aggregations