use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class AbstractBackendEntityEnricher method enrichTrace.
// At trace level, based on the next span to identify if a backend entity is actually a service
// entity.
@Override
public void enrichTrace(StructuredTrace trace) {
try {
StructuredTraceGraph structuredTraceGraph = buildGraph(trace);
trace.getEventList().stream().filter(event -> EnrichedSpanUtils.isExitSpan(event) && SpanAttributeUtils.isLeafSpan(structuredTraceGraph, event) && canResolveBackend(structuredTraceGraph, event)).map(event -> Pair.of(event, resolve(event, trace, structuredTraceGraph))).filter(pair -> pair.getRight().isPresent()).filter(pair -> isValidBackendEntity(trace, pair.getLeft(), pair.getRight().get())).forEach(pair -> decorateWithBackendEntity(pair.getRight().get(), pair.getLeft(), trace));
} catch (Exception ex) {
LOGGER.error("An error occurred while enriching backend", ex);
}
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph 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.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class ApiTraceGraph method buildApiTraceGraph.
private void buildApiTraceGraph() {
StructuredTraceGraph graph = StructuredTraceGraphBuilder.buildGraph(trace);
buildApiNodes(graph);
// optimization
buildApiNodeToIndexMap();
buildApiNodeEdges(graph);
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class StructuredTraceGraphBuilder method buildGraph.
public static StructuredTraceGraph buildGraph(StructuredTrace trace) {
StructuredTrace cachedTrace = cachedTraceThreadLocal.get();
StructuredTraceGraph cachedGraph = cachedGraphThreadLocal.get();
boolean shouldRebuildTraceEventsGraph = GraphBuilderUtil.isTraceEventsChanged(cachedTrace, trace);
boolean shouldRebuildTraceEntitiesGraph = GraphBuilderUtil.isTraceEntitiesChanged(cachedTrace, trace);
if (null == cachedGraph || GraphBuilderUtil.isDifferentTrace(cachedTrace, trace) || (shouldRebuildTraceEventsGraph && shouldRebuildTraceEntitiesGraph)) {
Instant start = Instant.now();
StructuredTraceGraph graph = new StructuredTraceGraph(trace);
if (LOG.isDebugEnabled()) {
LOG.debug("Time taken in building StructuredTraceGraph, duration_millis:{} for tenantId:{}", Duration.between(start, Instant.now()).toMillis(), trace.getCustomerId());
}
cachedTraceThreadLocal.set(StructuredTrace.newBuilder(trace).build());
cachedGraphThreadLocal.set(graph);
debugGraph("Case: Rebuilding the graph.", graph, trace);
return graph;
}
if (shouldRebuildTraceEventsGraph || shouldRebuildTraceEntitiesGraph) {
Instant start = Instant.now();
if (shouldRebuildTraceEventsGraph) {
cachedGraph.reCreateTraceEventsGraph(trace);
} else {
cachedGraph.reCreateTraceEntitiesGraph(trace);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Time taken in building TraceEventsGraph, duration_millis:{} for tenantId:{}", Duration.between(start, Instant.now()).toMillis(), trace.getCustomerId());
}
cachedTraceThreadLocal.set(StructuredTrace.newBuilder(trace).build());
cachedGraphThreadLocal.set(cachedGraph);
debugGraph("Case: Partially building the graph.", cachedGraph, trace);
return cachedGraph;
}
debugGraph("Case: Not building the graph.", cachedGraphThreadLocal.get(), trace);
return cachedGraph;
}
use of org.hypertrace.core.datamodel.shared.StructuredTraceGraph in project hypertrace-ingester by hypertrace.
the class StructuredTraceGraphBuilder method debugGraph.
private static void debugGraph(String logPrefix, StructuredTraceGraph graph, StructuredTrace trace) {
if (null != graph && (null == graph.getTraceEntitiesGraph() || null == graph.getTraceEventsGraph())) {
LOG.info(logPrefix + "StructuredTraceGraph is not built correctly, trace {}, Is events graph non-null: {}." + " Is entities graph non-null: {}", trace, (null != graph.getTraceEventsGraph()), (null != graph.getTraceEntitiesGraph()));
// build the graph again and check
StructuredTraceGraph tempGraph = new StructuredTraceGraph(trace);
LOG.info(logPrefix + "Recreating StructuredTraceGraph. Is events graph non-null: {}." + " Is entities graph non-null: {}", (null != tempGraph.getTraceEventsGraph()), (null != tempGraph.getTraceEntitiesGraph()));
tempGraph.reCreateTraceEventsGraph(trace);
LOG.info(logPrefix + "Recreating events graph. Is events graph non-null: {}." + " Is entities graph non-null: {}", (null != tempGraph.getTraceEventsGraph()), (null != tempGraph.getTraceEntitiesGraph()));
tempGraph.reCreateTraceEntitiesGraph(trace);
LOG.info(logPrefix + "Recreating entities graph. Is events graph non-null: {}." + " Is entities graph non-null: {}", (null != tempGraph.getTraceEventsGraph()), (null != tempGraph.getTraceEntitiesGraph()));
}
}
Aggregations