/** * Returns whether the current tree contains already a span with an id equals to the one of the * given span ident. * * @param spanIdent * span ident to check * @return <code>true</code> if the tree contains a span with the id of the given span ident */ private boolean isSpanInTree(SpanIdent spanIdent) { return spansExistingInTree.containsKey(spanIdent.getId()); }
/** * 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; }
/** * 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)); }
/** * 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; }
@Test public void testBackEndSpanFirst() throws InterruptedException { when(spanDao.get(Matchers.eq(backEndIdent))).thenReturn(backEndSpan); processor.process(Collections.singleton(frontEndSpan), mock(EntityManager.class)); verify(backEndSpan, times(1)).setParentSpanId(eq(frontEndIdent.getId())); }
@Test public void transformerInterface() { SpanContextImpl context = new SpanContextImpl(1, 2, 3, null, Collections.<String, String> emptyMap()); SpanIdent spanIdent = SpanContextTransformer.INSTANCE.transform(context); assertThat(spanIdent.getId(), is(1L)); assertThat(spanIdent.getTraceId(), is(2L)); }
@Test public void happyPath() { SpanContextImpl context = new SpanContextImpl(1, 2, 3, null, Collections.<String, String> emptyMap()); SpanIdent spanIdent = SpanContextTransformer.transformSpanContext(context); assertThat(spanIdent.getId(), is(1L)); assertThat(spanIdent.getTraceId(), is(2L)); }
@Test public void context() { when(spanImpl.context()).thenReturn(new SpanContextImpl(1, 2, 3, null, Collections.<String, String> emptyMap())); AbstractSpan span = SpanTransformer.transformSpan(spanImpl); SpanIdent spanIdent = span.getSpanIdent(); assertThat(spanIdent.getId(), is(1L)); assertThat(spanIdent.getTraceId(), is(2L)); assertThat(span.getParentSpanId(), is(3L)); }
@Test public void transformerInterface() { when(spanImpl.context()).thenReturn(new SpanContextImpl(1, 2, 3, null, Collections.<String, String> emptyMap())); AbstractSpan span = SpanTransformer.INSTANCE.transform(spanImpl); SpanIdent spanIdent = span.getSpanIdent(); assertThat(spanIdent.getId(), is(1L)); assertThat(spanIdent.getTraceId(), is(2L)); assertThat(span.getParentSpanId(), is(3L)); }
@Test public void testEUMSpanFirst() throws InterruptedException { // span initially not available MutableInt counter = new MutableInt(0); doAnswer(new Answer<AbstractSpan>() { @Override public AbstractSpan answer(InvocationOnMock invocation) throws Throwable { counter.increment(); if (counter.longValue() >= 5) { // make it available on the fifth attempt return backEndSpan; } else { return null; } } }).when(spanDao).get(Matchers.eq(backEndIdent)); processor.process(Collections.singleton(frontEndSpan), mock(EntityManager.class)); verify(backEndSpan, times(1)).setParentSpanId(eq(frontEndIdent.getId())); }
/** * Returns query for getting span with given ident. * * @param spanIdent * {@link SpanIdent}. * @return Query */ public E get(SpanIdent spanIdent) { E query = getIndexQueryProvider().getIndexQuery(); // set classes searched query.setObjectClasses(CLASSES_LIST); // only span with specific id query.addIndexingRestriction(IndexQueryRestrictionFactory.equal("spanIdent.id", spanIdent.getId())); return query; }
@Test public void testAllDataAvailable() throws IOException { ObjectNode node = buildEventListenerRecord(); EUMSpan span = performDeserialization(node); assertThat(span.getDetails(), instanceOf(JSEventListenerExecution.class)); assertThat(span.getSpanIdent().getId(), equalTo(ELEMENT_ID)); assertThat(span.getSpanIdent().getTraceId(), equalTo(TRACE_ID)); assertThat(span.getParentSpanId(), equalTo(PARENT_ID)); assertThat(span.getTimeStamp().getTime(), equalTo(ENTER_TIMESTAMP)); assertThat(span.getDuration(), equalTo(DURATION)); JSEventListenerExecution exec = (JSEventListenerExecution) span.getDetails(); assertThat(exec.getFunctionName(), equalTo(FUNCTION_NAME)); assertThat(exec.getEventType(), equalTo(EVENT_TYPE)); }
@Test public void testDefaultTraceId() throws IOException { ObjectNode node = buildEventListenerRecord(); node.remove("traceId"); EUMSpan span = performDeserialization(node); assertThat(span.getDetails(), instanceOf(JSEventListenerExecution.class)); assertThat(span.getSpanIdent().getId(), equalTo(ELEMENT_ID)); assertThat(span.getSpanIdent().getTraceId(), equalTo(ELEMENT_ID)); assertThat(span.getParentSpanId(), equalTo(PARENT_ID)); assertThat(span.getTimeStamp().getTime(), equalTo(ENTER_TIMESTAMP)); assertThat(span.getDuration(), equalTo(DURATION)); JSEventListenerExecution exec = (JSEventListenerExecution) span.getDetails(); assertThat(exec.getFunctionName(), equalTo(FUNCTION_NAME)); assertThat(exec.getEventType(), equalTo(EVENT_TYPE)); }
@Test public void testDefaultParentId() throws IOException { ObjectNode node = buildEventListenerRecord(); node.remove("parentId"); EUMSpan span = performDeserialization(node); assertThat(span.getDetails(), instanceOf(JSEventListenerExecution.class)); assertThat(span.getSpanIdent().getId(), equalTo(ELEMENT_ID)); assertThat(span.getSpanIdent().getTraceId(), equalTo(TRACE_ID)); assertThat(span.getParentSpanId(), equalTo(0L)); assertThat(span.getTimeStamp().getTime(), equalTo(ENTER_TIMESTAMP)); assertThat(span.getDuration(), equalTo(DURATION)); JSEventListenerExecution exec = (JSEventListenerExecution) span.getDetails(); assertThat(exec.getFunctionName(), equalTo(FUNCTION_NAME)); assertThat(exec.getEventType(), equalTo(EVENT_TYPE)); }
/** * {@inheritDoc} */ @Override protected void processData(DefaultData data, EntityManager entityManager) { if (data instanceof EUMSpan) { EUMSpan frontEndSpan = (EUMSpan) data; AbstractEUMSpanDetails details = frontEndSpan.getDetails(); if (details instanceof PageLoadRequest) { long traceId = frontEndSpan.getSpanIdent().getTraceId(); long eumSpanId = frontEndSpan.getSpanIdent().getId(); // if the ids are equal no correlation takes place, e.g. because the html was // cached. if (traceId != eumSpanId) { EumSpanCorrelationTask correlationTask = new EumSpanCorrelationTask(traceId, eumSpanId); correlationTask.schedule(true); } } } }
/** * 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()); } }
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; }
/** * 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); } } }