/** * Builds the {@link #lookupMap} map of the given tree. This allows direct access to the tree * elements via data objects. * * @param tree * the tree * @return the lookup map for the given tree */ public static Map<Object, InvocationTreeElement> buildLookupMap(InvocationTreeElement tree) { return InvocationTreeUtil.getRoot(tree).asStream().collect(Collectors.toMap(e -> calculateLookupKey(e.getDataElement()), Function.identity())); }
/** * Returns all data elements (of type {@link InvocationSequenceData} or {@link Span}) which are * contained in the given {@link InvocationTreeElement} or in its child nodes. * {@link InvocationTreeElement} of type * {@link InvocationTreeElement.TreeElementType#MISSING_SPAN} will be ignored. * <p> * Note: If <code>includeNestedInvocationSequences</code> is set to false, all nested invocation * sequences will be ignored and not added to the resulting list, thus, the invocation sequences * in the returned list will be only the root invocation sequences. * * @param tree * the top element of the tree to extract the data * @param includeNestedInvocationSequences * whether nested invocation sequences should also be referenced in the returned list * @return {@link List} of {@link InvocationSequenceData} and {@link Span} */ public static List<Object> getDataElements(InvocationTreeElement tree, boolean includeNestedInvocationSequences) { if (tree == null) { return Collections.emptyList(); } return tree.asStream().filter(e -> e.getType() != TreeElementType.MISSING_SPAN).map(InvocationTreeElement::getDataElement) .filter(o -> includeNestedInvocationSequences || (o instanceof Span) || (((InvocationSequenceData) o).getParentSequence() == null)).collect(Collectors.toList()); }
/** * Returns all {@link InvocationSequenceData} which is contained in the given * {@link InvocationTreeElement} or in its child nodes. {@link InvocationTreeElement} of type * {@link InvocationTreeElement.TreeElementType#MISSING_SPAN} or * {@link InvocationTreeElement.TreeElementType#SPAN} will be ignored. * <p> * Note: the returned list will contain only root invocation sequences * * @param tree * the top element of the tree to extract the data * @return {@link List} of {@link InvocationSequenceData} */ public static List<InvocationSequenceData> getInvocationSequences(InvocationTreeElement tree) { if (tree == null) { return Collections.emptyList(); } return tree.asStream().filter(e -> e.getType() == TreeElementType.INVOCATION_SEQUENCE).map(e -> (InvocationSequenceData) e.getDataElement()).filter(i -> i.getParentSequence() == null) .collect(Collectors.toList()); }
/** * Resolve the span details (like has nested exceptions, has SQL statement..). */ private void resolveSpanDetails() { // Load invocation sequences for calculating span details. We are doing this here again, // because we did not loaded any invocations at the beginning because we don't needed them // to build the tree. if (mode == Mode.ONLY_SPANS_WITH_SDK) { invocationSequences = loadInvocationSequences(); } // Creating a mapping from span ids to invocation sequences in order to prevent a continuous // iteration over the invocation sequences - when two spans refers the same // trace, we are trying to return the invocation sequence which follows the span (= is a // root span). Map<Long, InvocationSequenceData> spanToInvocationSequenceMap = InvocationSequenceDataHelper.asStream(invocationSequences).filter(InvocationSequenceDataHelper::hasSpanIdent) .collect(Collectors.toMap(i -> i.getSpanIdent().getId(), Function.identity(), (i1, i2) -> InvocationSequenceDataHelper.isRootElementInSequence(i1) ? i1 : i2)); // now we actually resolves the span details (like has nested exceptions..) tree.asStream().filter(e -> e.getType() == TreeElementType.SPAN).forEach(e -> resolveSpanDetails(e, spanToInvocationSequenceMap)); }