/** * Tryies to get the span with the given {@link SpanIdent}. * * @param ident * the span identifier to search for * @return an {@link Optional} which may contain the {@link Span} with belongs to the given * {@link SpanIdent} */ private Optional<Span> getSpan(SpanIdent ident) { return spans.stream().filter(s -> s.getSpanIdent().equals(ident)).findAny(); }
@Override public Span load(SpanIdent ident) throws Exception { // collect all from same trace as we expect them to be asked in same point of time // this way we don't do round-trips to only get one span // example: // - you ask for span id 1 and trace id 2 // - I load all spans with trace id 2, which might be few of them // - the spans not having id 1 I add to the cache manually // - i "load" the one with id 1, which will effectively add it also to the cache.. Collection<? extends Span> spans = service.getSpans(ident.getTraceId()); // add other spans from the trace to the cache and returned the one we tried to load if (CollectionUtils.isNotEmpty(spans)) { Span value = null; for (Span span : spans) { if (Objects.equals(ident, span.getSpanIdent())) { value = span; } else { cache.put(span.getSpanIdent(), span); } } // return asked one if (null != value) { return value; } } // if we can not locate, throw exception as per loading cache api throw new Exception("Span with ident " + ident + " can not be found."); } });
/** * {@inheritDoc} */ @Override public Collection<? extends Span> getRootSpans(int limit, Date fromDate, Date toDate, ResultComparator<AbstractSpan> resultComparator) { // call service Collection<? extends Span> spans = service.getRootSpans(limit, fromDate, toDate, resultComparator); // cache results for (Span span : spans) { cache.put(span.getSpanIdent(), span); } // then return return spans; }
/** * {@inheritDoc} */ @Override public Collection<? extends Span> getSpans(long traceId) { // call service // note we can not go via the cache here as we are not sure that cache holds all spans // belonging to the trace (due to eviction and/or spans coming to the server from several // agents in different time) Collection<? extends Span> spans = service.getSpans(traceId); // cache results for (Span span : spans) { cache.put(span.getSpanIdent(), span); } // then return return spans; }
} else if (type == TreeElementType.SPAN) { Span span = (Span) dataElement; builder.append(span.getSpanIdent().getId()); if (!isRoot()) { builder.append(";parent=");
/** * Creates a new {@link InvocationTreeElement} which is related to the given parent and contains * the given data objet. * * @param dataElement * the data element of the created {@link InvocationTreeElement} * @param parent * the parent element * @return the newly created {@link InvocationTreeElement} */ private InvocationTreeElement createTreeElement(Object dataElement, InvocationTreeElement parent) { InvocationTreeElement element = new InvocationTreeElement(dataElement); if (parent != null) { parent.addChild(element); } if (dataElement instanceof Span) { Span span = (Span) dataElement; // put the span into the `spansExistingInTree` map in order to mark that it is existing // in the tree, now spansExistingInTree.put(span.getSpanIdent().getId(), element); } return element; }
/** * Calculates a key which is used for the lookup map and identifying * {@link InvocationTreeElement} based on the contained data object. * * @param object * the object to generate a key for * @return the key of the given object */ public static String calculateLookupKey(Object object) { if (object == null) { return null; } if (object instanceof Span) { return "span_" + ((Span) object).getSpanIdent().getId(); } else if (object instanceof InvocationSequenceData) { return "isd_" + ((InvocationSequenceData) object).getId(); } else if (object instanceof SpanIdent) { return "span_" + ((SpanIdent) object).getId(); } return null; }
/** * 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); } } }
@Test public void buildOneInvocationSequenceWithSpan() { Span span01 = createServerSpan(null); InvocationSequenceData invoc01 = createSequence(span01); InvocationSequenceData _invoc02 = createSequence(null); invoc01.getNestedSequences().add(_invoc02); doReturn(span01).when(spanService).get(span01.getSpanIdent()); builder.setSpanService(spanService).setMode(Mode.SINGLE).setInvocationSequence(invoc01); InvocationTreeElement tree = builder.build(); Map<Object, InvocationTreeElement> lookupMap = InvocationTreeUtil.buildLookupMap(tree); assertThat(lookupMap.size(), is(3)); assertThat(tree.getDataElement(), is(span01)); assertThat(tree.getChildren(), contains(hasProperty("dataElement", is(invoc01)))); verify(spanService).get(span01.getSpanIdent()); verifyNoMoreInteractions(spanService); verifyZeroInteractions(invocationService); }
InvocationSequenceData createSequence(Span span) { InvocationSequenceData data = new InvocationSequenceData(); data.setId(idSequence++); if (span != null) { data.setSpanIdent(span.getSpanIdent()); } data.setTimeStamp(new Timestamp(timeSequence++)); return data; }
/** * Resolves additional span details (e.g. has nested exception or SQL data) for the given * {@link InvocationTreeElement}. * * @param element * the {@link InvocationTreeElement} which details should be resolved * @param spanToInvocationSequenceMap * lookup map for mapping the spans to {@link InvocationSequenceData} */ private void resolveSpanDetails(InvocationTreeElement element, Map<Long, InvocationSequenceData> spanToInvocationSequenceMap) { if (!element.isSpan()) { return; } InvocationSequenceData sequenceData = spanToInvocationSequenceMap.get(((Span) element.getDataElement()).getSpanIdent().getId()); if (sequenceData != null) { element.setHasNestedSqls((sequenceData.isNestedSqlStatements() != null) && sequenceData.isNestedSqlStatements()); element.setHasNestedExceptions((sequenceData.isNestedExceptions() != null) && sequenceData.isNestedExceptions()); } }
invoc01.getNestedSequences().add(_invoc02); invoc03.getNestedSequences().add(_invoc04); doReturn(span01).when(spanService).get(span01.getSpanIdent()); doReturn(span02).when(spanService).get(span02.getSpanIdent()); doReturn(span03).when(spanService).get(span03.getSpanIdent()); doReturn(span04).when(spanService).get(span04.getSpanIdent()); assertThat(InvocationTreeUtil.lookupTreeElement(lookupMap, _invoc02), is(nullValue())); assertThat(InvocationTreeUtil.lookupTreeElement(lookupMap, span04), is(nullValue())); verify(spanService).get(span02.getSpanIdent()); verify(spanService).get(span03.getSpanIdent()); verifyNoMoreInteractions(spanService); verifyZeroInteractions(invocationService);
ServerSpan createServerSpan(Span parent) { ServerSpan span = new ServerSpan(); span.setSpanIdent(new SpanIdent(idSequence++, 0)); span.setTimeStamp(new Timestamp(timeSequence++)); span.setPropagationType(PropagationType.PROCESS); if (parent != null) { span.setParentSpanId(parent.getSpanIdent().getId()); } return span; }
ClientSpan createClientSpan(Span parent) { ClientSpan span = new ClientSpan(); span.setSpanIdent(new SpanIdent(idSequence++, 0)); span.setTimeStamp(new Timestamp(timeSequence++)); span.setPropagationType(PropagationType.PROCESS); if (parent != null) { span.setParentSpanId(parent.getSpanIdent().getId()); } return span; }
/** * Returns the styled text for a specific column. * * @param data * The data object to extract the information from. * @param enumId * The enumeration ID. * @return The styled string containing the information from the data object. */ private StyledString getStyledTextForColumn(Span data, Column enumId) { switch (enumId) { case TIME: return new StyledString(NumberFormatter.formatTimeWithMillis(data.getTimeStamp())); case DURATION: return new StyledString(NumberFormatter.formatDouble(data.getDuration(), timeDecimalPlaces)); case PROPAGATION: return TextFormatter.getPropagationStyled(data.getPropagationType()); case DETAILS: return TextFormatter.getSpanDetailsShort(data, cachedDataService); case ORIGIN: return TextFormatter.getSpanOriginStyled(data, cachedDataService.getPlatformIdentForId(data.getPlatformIdent())); case TRACE_ID: return new StyledString(Long.toHexString(data.getSpanIdent().getTraceId())); default: return new StyledString("error"); } } }
} else { if ((parent.getParent() == null) || !parent.getParent().isSpan() || (((Span) parent.getParent().getDataElement()).getSpanIdent().getId() != span.getSpanIdent().getId())) { child = createTreeElement(span, parent);