/** * If invocation has span ident connected. * * @param data * InvocationSequenceData * @return <code>true</code> if span ident exists in this invocation. */ public static boolean hasSpanIdent(InvocationSequenceData data) { return null != data.getSpanIdent(); }
/** * Searches the {@link InvocationSequenceData} list for the given span ident based on current * input and returns the first invocation containing the span ident. * * @param input * Root invocations. * @param spanIdent * ident * @return Found data or <code>null</code> */ protected InvocationSequenceData getForSpanIdent(List<InvocationSequenceData> input, SpanIdent spanIdent) { for (InvocationSequenceData invoc : input) { if (Objects.equals(spanIdent, invoc.getSpanIdent())) { return invoc; } InvocationSequenceData containing = getForSpanIdent(invoc.getNestedSequences(), spanIdent); if (null != containing) { return containing; } } return null; }
/** * Loads all the data which is required for building the tree. */ private void prepare() { if (mode == Mode.SINGLE) { invocationSequences = Arrays.asList(invocationSequence); // loading all spans related to the set invocation sequence if (spanService != null) { Stream<InvocationSequenceData> invocationStream = InvocationSequenceDataHelper.asStream(invocationSequence); spans = invocationStream.map(i -> i.getSpanIdent()).filter(Objects::nonNull).map(spanService::get).filter(Objects::nonNull).collect(Collectors.toList()); } else { spans = new ArrayList<>(); } } else { if (traceId == null) { throw new IllegalStateException("A trace id have to be specified when a span tree has to be build and the mode is not set to SINGLE."); } spans = loadSpans(); if (mode == Mode.ALL) { invocationSequences = loadInvocationSequences(); } } if (mode != Mode.ONLY_SPANS_WITH_SDK) { spans.removeIf(s -> (s.getPropagationType() == null) && !s.isRoot()); } }
/** * 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)); }
/** * Returns if the given {@link InvocationSequenceData} should be removed due to no data. Can be * in case of * <ul> * <li>the wrapping of the prepared SQL statements. * <li>having an empty logging element (if the logging occurred with a lower logging level than * the configuration) * <li>running remote sensor that provided no span * <li>having invocation sensor without any other sensor on the method * </ul> * * @param invocationSequenceData * {@link InvocationSequenceData} to check. * * @return True if the invocation should be removed. */ private boolean removeDueToNoData(InvocationSequenceData invocationSequenceData) { return (null == invocationSequenceData.getTimerData()) && (null == invocationSequenceData.getSqlStatementData()) && (null == invocationSequenceData.getLoggingData()) && (null == invocationSequenceData.getSpanIdent()) && CollectionUtils.isEmpty(invocationSequenceData.getExceptionSensorDataObjects()); }
Optional span = getSpan(rootSequence.getSpanIdent()); rootDataElement = span.orElse(rootSequence); } else {
assertThat(invocation.getNestedSequences(), is(empty())); assertThat(invocation.getChildCount(), is(0L)); assertThat(invocation.getSpanIdent(), is(SpanContextTransformer.transformSpanContext(context)));
assertThat(invocation.getNestedSequences(), is(empty())); assertThat(invocation.getChildCount(), is(0L)); assertThat(invocation.getSpanIdent(), is(SpanContextTransformer.transformSpanContext(context)));
assertThat(invocation.getNestedSequences(), is(empty())); assertThat(invocation.getChildCount(), is(0L)); assertThat(invocation.getSpanIdent(), is(spanIdent));
assertThat(invocation.getTimerData(), is(timerData)); assertThat(invocation.getSqlStatementData(), is(sqlStatementData)); assertThat(invocation.getSpanIdent(), is(nullValue()));
assertThat(invocation.getNestedSequences(), hasSize(1)); assertThat(invocation.getChildCount(), is(1L)); assertThat(invocation.getSpanIdent(), is(nullValue())); InvocationSequenceData child = invocation.getNestedSequences().iterator().next(); assertThat(child.getPlatformIdent(), is(platformId)); assertThat(child.getParentSequence(), is(invocation)); assertThat(child.getChildCount(), is(0L)); assertThat(child.getSpanIdent(), is(not(nullValue())));
if (InvocationSequenceDataHelper.hasSpanIdent(currentData) && !isSpanInTree(currentData.getSpanIdent())) { Optional<Span> optionalSpan = getSpan(currentData.getSpanIdent()); InvocationTreeElement newRoot = createTreeElement(currentData.getSpanIdent()); newRoot.addChild(parent); createTreeElement(currentData.getSpanIdent(), parent);
/** * {@inheritDoc} */ @Override public Object getElement(Object template, int occurance, ViewerFilter[] filters) { // return the span directly because it is unique if (template instanceof Span) { return template; } // returning matching invocations InvocationTreeContentProvider contentProvider = (InvocationTreeContentProvider) getContentProvider(); if (contentProvider.getRootElement() != null) { List<InvocationSequenceData> sequences; sequences = InvocationTreeUtil.getInvocationSequences(contentProvider.getRootElement()); InvocationSequenceData found = OccurrenceFinderFactory.getOccurrence(sequences, template, occurance, filters); if (InvocationSequenceDataHelper.hasSpanIdent(found) && (template instanceof Span)) { return spanService.get(found.getSpanIdent()); } else { return found; } } return null; }
/** * Calculates the duration starting from this invocation sequence data element. Includes span * duration as last resource if the span ident exists on the data. * * @param data * the <code>InvocationSequenceData</code> object. * @param spanService * Span service providing the additional span information if needed. * @return the duration starting from this invocation sequence data element. */ public static double calculateDuration(InvocationSequenceData data, ISpanService spanService) { if (InvocationSequenceDataHelper.hasTimerData(data)) { return data.getTimerData().getDuration(); } else if (InvocationSequenceDataHelper.hasSQLData(data)) { return data.getSqlStatementData().getDuration(); } else if ((null != spanService) && hasSpanIdent(data)) { Span span = spanService.get(data.getSpanIdent()); if ((span != null) && !References.FOLLOWS_FROM.equals(span.getReferenceType())) { return span.getDuration(); } } if (InvocationSequenceDataHelper.isRootElementInSequence(data)) { return data.getDuration(); } return -1.0d; }
/** * Resolves a span element. * * @param parent * a {@link InvocationTreeElement} from type {@link TreeElementType#SPAN}. */ private void resolveSpan(InvocationTreeElement parent) { Span currentSpan = (Span) parent.getDataElement(); if (!currentSpan.isCaller()) { // server span - expect invocation sequence for (InvocationSequenceData data : invocationSequences) { if (InvocationSequenceDataHelper.hasSpanIdent(data) && data.getSpanIdent().equals(currentSpan.getSpanIdent())) { InvocationTreeElement child = createTreeElement(data, parent); resolveInvocationSequence(child); } } } for (Span span : spans) { // if span is already in the tree, skip it if (isSpanInTree(span.getSpanIdent())) { continue; } if (span.getParentSpanId() == currentSpan.getSpanIdent().getId()) { InvocationTreeElement child = createTreeElement(span, parent); resolveSpan(child); } } }
/** * Clones invocation sequence. This method returns new object exactly same as the original * object, but with out nested sequences set. * * @return Cloned invocation sequence. */ public InvocationSequenceData getClonedInvocationSequence() { InvocationSequenceData clone = new InvocationSequenceData(this.getTimeStamp(), this.getPlatformIdent(), this.getSensorTypeIdent(), this.getMethodIdent()); clone.setId(this.getId()); clone.setSpanIdent(this.getSpanIdent()); clone.setChildCount(this.getChildCount()); clone.setDuration(this.getDuration()); clone.setEnd(this.getEnd()); clone.setNestedSequences(Collections.<InvocationSequenceData> emptyList()); clone.setParameterContentData(this.getParameterContentData()); clone.setParentSequence(this.getParentSequence()); clone.setPosition(this.getPosition()); clone.setSqlStatementData(this.getSqlStatementData()); clone.setTimerData(this.getTimerData()); clone.setExceptionSensorDataObjects(this.getExceptionSensorDataObjects()); clone.setStart(this.getStart()); clone.setNestedSqlStatements(this.isNestedSqlStatements()); clone.setNestedExceptions(this.isNestedExceptions()); clone.setLoggingData(this.getLoggingData()); clone.setApplicationId(this.getApplicationId()); clone.setBusinessTransactionId(this.getBusinessTransactionId()); return clone; }