Search in sources :

Example 1 with ApiNodeEventEdge

use of org.hypertrace.core.datamodel.ApiNodeEventEdge 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 ApiNodeEventEdge

use of org.hypertrace.core.datamodel.ApiNodeEventEdge 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 ApiNodeEventEdge

use of org.hypertrace.core.datamodel.ApiNodeEventEdge in project hypertrace-ingester by hypertrace.

the class ExitCallsEnricher method computeApiExitCallCount.

/**
 * An api_node represents an api call in the trace It consists of api_entry span and multiple
 * api_exit and internal spans
 *
 * <p>This method computes the count & breakup of exit calls for any given api (identified by
 * api_entry_span) This count is a composition of 2 things
 *
 * <ul>
 *   <li>1. link between api_exit_span in api_node to api_entry_span (child of api_exit_span) in
 *       another api_node
 *   <li>2. exit calls to backend from api_exit_span in api_node
 * </ul>
 */
Map<ByteBuffer, ApiExitCallInfo> computeApiExitCallCount(StructuredTrace trace) {
    ApiTraceGraph apiTraceGraph = ApiTraceGraphBuilder.buildGraph(trace);
    // event -> api exit call count for the corresponding api_node
    Map<ByteBuffer, ApiExitCallInfo> eventToExitInfo = Maps.newHashMap();
    int totalTraceExitCallCount = 0;
    for (ApiNode<Event> apiNode : apiTraceGraph.getApiNodeList()) {
        List<Event> backendExitEvents = apiTraceGraph.getExitBoundaryEventsWithNoOutboundEdgeForApiNode(apiNode);
        List<ApiNodeEventEdge> edges = apiTraceGraph.getOutboundEdgesForApiNode(apiNode);
        int totalExitCallCount = backendExitEvents.size() + edges.size();
        ApiExitCallInfo apiExitCallInfo = new ApiExitCallInfo().withExitCallCount(totalExitCallCount);
        totalTraceExitCallCount += totalExitCallCount;
        edges.forEach(edge -> apiExitCallInfo.handleApiNodeEdge(trace, edge));
        backendExitEvents.forEach(apiExitCallInfo::handleBackend);
        apiNode.getEvents().forEach(e -> eventToExitInfo.put(e.getEventId(), apiExitCallInfo));
    }
    addApiExitCallsCountTraceAttribute(trace, totalTraceExitCallCount);
    return eventToExitInfo;
}
Also used : ApiNodeEventEdge(org.hypertrace.core.datamodel.ApiNodeEventEdge) Event(org.hypertrace.core.datamodel.Event) ApiTraceGraph(org.hypertrace.traceenricher.trace.util.ApiTraceGraph) ByteBuffer(java.nio.ByteBuffer)

Aggregations

ApiNodeEventEdge (org.hypertrace.core.datamodel.ApiNodeEventEdge)3 ByteBuffer (java.nio.ByteBuffer)2 Edge (org.hypertrace.core.datamodel.Edge)2 Event (org.hypertrace.core.datamodel.Event)2 AvroBuilderCache.fastNewBuilder (org.hypertrace.core.datamodel.shared.AvroBuilderCache.fastNewBuilder)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 ArrayList (java.util.ArrayList)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 Optional (java.util.Optional)1 Queue (java.util.Queue)1 Set (java.util.Set)1 Collectors (java.util.stream.Collectors)1