private TransactionPayload createPayloadWithRequiredValues() { final TransactionPayload payload = createPayload(); final Transaction transaction = createTransactionWithRequiredValues(); payload.getTransactions().add(transaction); Span span = new Span(mock(ElasticApmTracer.class)); span.start(TraceContext.fromParent(), transaction) .withType("type") .withSubtype("subtype") .withAction("action") .withName("name"); payload.getSpans().add(span); return payload; }
String type = span.getType(); if (type != null) { replaceBuilder.setLength(0); replaceBuilder.append(type); replace(replaceBuilder, ".", "_", 0); String subtype = span.getSubtype(); String action = span.getAction(); if ((subtype != null && !subtype.isEmpty()) || (action != null && !action.isEmpty())) { replaceBuilder.append('.');
private void serializeSpan(final Span span) { jw.writeByte(OBJECT_START); writeField("name", span.getName()); writeTimestamp(span.getTimestamp()); serializeTraceContext(span.getTraceContext(), true); writeField("duration", span.getDuration()); if (span.getStacktrace() != null) { serializeStacktrace(span.getStacktrace().getStackTrace()); } if (span.getContext().hasContent()) { serializeSpanContext(span.getContext()); } serializeSpanType(span); jw.writeByte(OBJECT_END); }
@SuppressWarnings("ReferenceEquality") public void endSpan(Span span) { if (span.isSampled()) { long spanFramesMinDurationMs = stacktraceConfiguration.getSpanFramesMinDurationMs(); if (spanFramesMinDurationMs != 0 && span.isSampled()) { if (span.getDuration() >= spanFramesMinDurationMs) { span.withStacktrace(new Throwable()); } } reporter.report(span); } else { span.recycle(); } }
public <T> Span start(TraceContext.ChildContextCreator<T> childContextCreator, T parentContext, long epochMicros, boolean dropped) { onStart(); childContextCreator.asChildOf(traceContext, parentContext); if (dropped) { traceContext.setRecorded(false); } if (epochMicros >= 0) { timestamp = epochMicros; } else { timestamp = getTraceContext().getClock().getEpochMicros(); } if (logger.isDebugEnabled()) { logger.debug("startSpan {} {", this); if (logger.isTraceEnabled()) { logger.trace("starting span at", new RuntimeException("this exception is just used to record where the span has been started from")); } } return this; }
@Test void resetState() { Span span = new Span(mock(ElasticApmTracer.class)) .withName("SELECT FROM product_types") .withType("db") .withSubtype("postgresql") .withAction("query"); span.getContext().getDb() .withInstance("customers") .withStatement("SELECT * FROM product_types WHERE user_id=?") .withType("sql") .withUser("readonly_user"); span.resetState(); assertThat(span.getContext().hasContent()).isFalse(); assertThat((CharSequence) span.getName()).isNullOrEmpty(); assertThat(span.getType()).isNull(); assertThat(span.getSubtype()).isNull(); assertThat(span.getAction()).isNull(); } }
public static List<Span> getSpans(Transaction t) { List<Span> spans = new ArrayList<>(); Span span = new Span(mock(ElasticApmTracer.class)) .start(TraceContext.fromParent(), t) .withName("SELECT FROM product_types") .withType("db") .withSubtype("postgresql") .withAction("query"); span.getContext().getDb() .withInstance("customers") .withStatement("SELECT * FROM product_types WHERE user_id=?") .withType("sql") .withUser("readonly_user"); span.addTag("monitored_by", "ACME"); span.addTag("framework", "some-framework"); spans.add(span); spans.add(new Span(mock(ElasticApmTracer.class)) .start(TraceContext.fromParent(), t) .withName("GET /api/types") .withType("request")); spans.add(new Span(mock(ElasticApmTracer.class)) .start(TraceContext.fromParent(), t) .withName("GET /api/types") .withType("request")); spans.add(new Span(mock(ElasticApmTracer.class)) .start(TraceContext.fromParent(), t) .withName("GET /api/types") .withType("request"));
@Test void testEnableStacktraces() throws InterruptedException { when(tracerImpl.getConfig(StacktraceConfiguration.class).getSpanFramesMinDurationMs()).thenReturn(-1L); Transaction transaction = tracerImpl.startTransaction(); try (Scope scope = transaction.activateInScope()) { Span span = tracerImpl.getActive().createSpan(); try (Scope spanScope = span.activateInScope()) { Thread.sleep(10); span.end(); } transaction.end(); } assertThat(reporter.getFirstSpan().getStacktrace()).isNotNull(); }
@Test void testSpanTypeSerialization() throws IOException { Span span = new Span(mock(ElasticApmTracer.class)); span.getTraceContext().asRootSpan(ConstantSampler.of(true)); span.withType("template.jsf.render.view"); JsonNode spanJson = objectMapper.readTree(serializer.toJsonString(span)); assertThat(spanJson.get("type").textValue()).isEqualTo("template_jsf_render_view"); span.withType("template").withSubtype("jsf.lifecycle").withAction("render.view"); spanJson = objectMapper.readTree(serializer.toJsonString(span)); assertThat(spanJson.get("type").textValue()).isEqualTo("template.jsf_lifecycle.render_view"); span = new Span(mock(ElasticApmTracer.class)); span.getTraceContext().asRootSpan(ConstantSampler.of(true)); span.withType("template").withAction("jsf.render"); spanJson = objectMapper.readTree(serializer.toJsonString(span)); assertThat(spanJson.get("type").textValue()).isEqualTo("template..jsf_render"); span = new Span(mock(ElasticApmTracer.class)); span.getTraceContext().asRootSpan(ConstantSampler.of(true)); span.withType("template").withSubtype("jsf.render"); spanJson = objectMapper.readTree(serializer.toJsonString(span)); assertThat(spanJson.get("type").textValue()).isEqualTo("template.jsf_render"); span = new Span(mock(ElasticApmTracer.class)); span.getTraceContext().asRootSpan(ConstantSampler.of(true)); span.withSubtype("jsf").withAction("render"); spanJson = objectMapper.readTree(serializer.toJsonString(span)); assertThat(spanJson.get("type").isNull()).isTrue(); System.out.println(spanJson); }
@Test void testDisableMidTransaction() { Transaction transaction = tracerImpl.startTransaction(); try (Scope scope = transaction.activateInScope()) { assertThat(tracerImpl.currentTransaction()).isSameAs(transaction); Span span = tracerImpl.getActive().createSpan(); try (Scope spanScope = span.activateInScope()) { when(config.getConfig(CoreConfiguration.class).isActive()).thenReturn(false); span.withName("test"); assertThat(span.getName().toString()).isEqualTo("test"); assertThat(tracerImpl.getActive()).isSameAs(span); assertThat(span.isChildOf(transaction)).isTrue(); span.end(); } Span span2 = tracerImpl.getActive().createSpan(); try (Scope spanScope = span2.activateInScope()) { when(config.getConfig(CoreConfiguration.class).isActive()).thenReturn(false); span2.withName("test2"); assertThat(span2.getName().toString()).isEqualTo("test2"); assertThat(tracerImpl.getActive()).isSameAs(span2); assertThat(span2.isChildOf(transaction)).isTrue(); span2.end(); } assertThat(tracerImpl.getActive()).isEqualTo(transaction); transaction.end(); } assertThat(tracerImpl.currentTransaction()).isNull(); assertThat(reporter.getSpans()).hasSize(2); assertThat(reporter.getFirstTransaction()).isSameAs(transaction); }
@Test void testTimestamps() { final Transaction transaction = tracerImpl.startTransaction(TraceContext.fromTraceparentHeader(), null, ConstantSampler.of(true), 0); final Span span = transaction.createSpan(10); span.end(20); transaction.end(30); assertThat(transaction.getTimestamp()).isEqualTo(0); assertThat(transaction.getDuration()).isEqualTo(0.03); assertThat(span.getTimestamp()).isEqualTo(10); assertThat(span.getDuration()).isEqualTo(0.01); }
private void innerRecordExceptionWithTrace(boolean sampled) { reporter.reset(); Transaction transaction = tracerImpl.startTransaction(TraceContext.asRoot(), null, ConstantSampler.of(sampled), -1); transaction.withType("test-type"); try (Scope scope = transaction.activateInScope()) { transaction.getContext().getRequest() .addHeader("foo", "bar") .withMethod("GET") .getUrl() .withPathname("/foo"); tracerImpl.currentTransaction().captureException(new Exception("from transaction")); ErrorCapture error = validateError(transaction, sampled, transaction); assertThat(error.getContext().getRequest().getHeaders().get("foo")).isEqualTo("bar"); reporter.reset(); Span span = transaction.createSpan().activate(); span.captureException(new Exception("from span")); validateError(span, sampled, transaction); span.deactivate().end(); transaction.end(); } }
@Advice.OnMethodEnter(suppress = Throwable.class) public static void onMethodEnter(@SimpleMethodSignatureOffsetMappingFactory.SimpleMethodSignature String signature, @Advice.Local("span") AbstractSpan<?> span) { if (tracer != null) { final TraceContextHolder<?> parent = tracer.getActive(); if (parent == null) { span = tracer.startTransaction() .withName(signature) .activate(); } else { span = parent.createSpan() .withName(signature) .activate(); } } }
private void validateJsonStructure(TransactionPayload payload) throws IOException { JsonNode serializedSpans = getSerializedSpans(payload); validateDbSpanSchema(serializedSpans, true); validateHttpSpanSchema(serializedSpans); for (Span span : payload.getSpans()) { if (span.getType() != null && span.getType().equals("db")) { span.getContext().getTags().clear(); validateDbSpanSchema(getSerializedSpans(payload), false); break; } } }
@Override public Span createInstance() { return new Span(ElasticApmTracer.this); } });
@Test void testTraceMethod() { TestClass.traceMe(); assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getFirstTransaction().getName().toString()).isEqualTo("TestClass#traceMe"); assertThat(reporter.getSpans()).hasSize(1); assertThat(reporter.getFirstSpan().getName().toString()).isEqualTo("TestClass#traceMeToo"); }
public void captureException(long epochMicros, @Nullable Throwable e, @Nullable TraceContextHolder<?> active) { if (e != null) { ErrorCapture error = errorPool.createInstance(); error.withTimestamp(epochMicros); error.setException(e); Transaction currentTransaction = currentTransaction(); if (currentTransaction != null) { error.setTransactionType(currentTransaction.getType()); error.setTransactionSampled(currentTransaction.isSampled()); } if (active != null) { if (active instanceof Transaction) { Transaction transaction = (Transaction) active; // The error might have occurred in a different thread than the one the transaction was recorded // That's why we have to ensure the visibility of the transaction properties error.getContext().copyFrom(transaction.getContextEnsureVisibility()); } else if (active instanceof Span) { Span span = (Span) active; error.getContext().getTags().putAll(span.getContext().getTags()); } error.asChildOf(active.getTraceContext()); } else { error.getTraceContext().getId().setToRandomValue(); } reporter.report(error); } }
@Test void testEnableStacktracesForSlowSpans() throws InterruptedException { when(tracerImpl.getConfig(StacktraceConfiguration.class).getSpanFramesMinDurationMs()).thenReturn(1L); Transaction transaction = tracerImpl.startTransaction(); try (Scope scope = transaction.activateInScope()) { Span span = tracerImpl.getActive().createSpan(); try (Scope spanScope = span.activateInScope()) { Thread.sleep(10); span.end(); } transaction.end(); } assertThat(reporter.getFirstSpan().getStacktrace()).isNotNull(); }
private void reportSpan() { final ReportingEvent reportingEvent = new ReportingEvent(); reportingEvent.setSpan(new Span(mock(ElasticApmTracer.class))); reportingEventHandler.onEvent(reportingEvent, -1, true); }
@Test void testDisableStacktraces() { when(tracerImpl.getConfig(StacktraceConfiguration.class).getSpanFramesMinDurationMs()).thenReturn(0L); Transaction transaction = tracerImpl.startTransaction(); try (Scope scope = transaction.activateInScope()) { Span span = tracerImpl.getActive().createSpan(); try (Scope spanScope = span.activateInScope()) { span.end(); } transaction.end(); } assertThat(reporter.getFirstSpan().getStacktrace()).isNull(); }