Search in sources :

Example 1 with Edge

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);
                    }
                }
            }
        }
    }
}
Also used : EnrichedSpanUtils(org.hypertrace.traceenricher.enrichedspan.constants.utils.EnrichedSpanUtils) AttributeValue(org.hypertrace.traceenricher.enrichedspan.constants.v1.AttributeValue) AvroBuilderCache.fastNewBuilder(org.hypertrace.core.datamodel.shared.AvroBuilderCache.fastNewBuilder) LoggerFactory(org.slf4j.LoggerFactory) HashBasedTable(com.google.common.collect.HashBasedTable) Edge(org.hypertrace.core.datamodel.Edge) StringUtils(org.apache.commons.lang3.StringUtils) ByteBuffer(java.nio.ByteBuffer) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) StructuredTraceGraph(org.hypertrace.core.datamodel.shared.StructuredTraceGraph) ApiNode(org.hypertrace.core.datamodel.shared.ApiNode) Lists(com.google.common.collect.Lists) Map(java.util.Map) EnrichedSpanConstants(org.hypertrace.traceenricher.enrichedspan.constants.EnrichedSpanConstants) HexUtils(org.hypertrace.core.datamodel.shared.HexUtils) LinkedList(java.util.LinkedList) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Logger(org.slf4j.Logger) ApiNodeEventEdge(org.hypertrace.core.datamodel.ApiNodeEventEdge) Event(org.hypertrace.core.datamodel.Event) Set(java.util.Set) Maps(com.google.common.collect.Maps) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) List(java.util.List) Optional(java.util.Optional) Queue(java.util.Queue) Table(com.google.common.collect.Table) Collections(java.util.Collections) ApiNodeEventEdge(org.hypertrace.core.datamodel.ApiNodeEventEdge) Event(org.hypertrace.core.datamodel.Event)

Example 2 with Edge

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();
}
Also used : ApiNodeEventEdge(org.hypertrace.core.datamodel.ApiNodeEventEdge) AvroBuilderCache.fastNewBuilder(org.hypertrace.core.datamodel.shared.AvroBuilderCache.fastNewBuilder) Edge(org.hypertrace.core.datamodel.Edge) ApiNodeEventEdge(org.hypertrace.core.datamodel.ApiNodeEventEdge)

Example 3 with Edge

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);
}
Also used : Entity(org.hypertrace.core.datamodel.Entity) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Event(org.hypertrace.core.datamodel.Event) Edge(org.hypertrace.core.datamodel.Edge) Test(org.junit.jupiter.api.Test)

Example 4 with Edge

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);
        }
    }
}
Also used : Entity(org.hypertrace.core.datamodel.Entity) StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) Event(org.hypertrace.core.datamodel.Event) StructuredTraceGraph(org.hypertrace.core.datamodel.shared.StructuredTraceGraph) Edge(org.hypertrace.core.datamodel.Edge) Test(org.junit.jupiter.api.Test)

Example 5 with Edge

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;
}
Also used : StructuredTrace(org.hypertrace.core.datamodel.StructuredTrace) ArrayList(java.util.ArrayList) Edge(org.hypertrace.core.datamodel.Edge)

Aggregations

Edge (org.hypertrace.core.datamodel.Edge)9 Event (org.hypertrace.core.datamodel.Event)7 StructuredTrace (org.hypertrace.core.datamodel.StructuredTrace)7 Entity (org.hypertrace.core.datamodel.Entity)6 Test (org.junit.jupiter.api.Test)5 ArrayList (java.util.ArrayList)2 ApiNodeEventEdge (org.hypertrace.core.datamodel.ApiNodeEventEdge)2 AvroBuilderCache.fastNewBuilder (org.hypertrace.core.datamodel.shared.AvroBuilderCache.fastNewBuilder)2 StructuredTraceGraph (org.hypertrace.core.datamodel.shared.StructuredTraceGraph)2 HashBasedTable (com.google.common.collect.HashBasedTable)1 Lists (com.google.common.collect.Lists)1 Maps (com.google.common.collect.Maps)1 Sets (com.google.common.collect.Sets)1 Table (com.google.common.collect.Table)1 ByteBuffer (java.nio.ByteBuffer)1 Collections (java.util.Collections)1 HashSet (java.util.HashSet)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1