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);
}
}
}
}
}
}
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();
}
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;
}
Aggregations