@Test void testCopyFromDoNotCopyTags() { TransactionContext context = new TransactionContext(); context.getTags().put("foo", "bar"); TransactionContext copyOfContext = new TransactionContext(); copyOfContext.copyFrom(context); assertThat(copyOfContext.getTags()).isEmpty(); }
private void serializeContext(final TransactionContext context) { writeFieldName("context"); jw.writeByte(OBJECT_START); if (context.getUser().hasContent()) { serializeUser(context.getUser()); jw.writeByte(COMMA); } serializeRequest(context.getRequest()); serializeResponse(context.getResponse()); // TODO custom context writeFieldName("tags"); final Map<String, String> value = context.getTags(); serializeTags(value); jw.writeByte(OBJECT_END); jw.writeByte(COMMA); }
@Test void testCopyFromDoNotCopyCustom() { TransactionContext context = new TransactionContext(); context.getCustom().put("foo", "bar"); TransactionContext copyOfContext = new TransactionContext(); copyOfContext.copyFrom(context); assertThat(copyOfContext.getCustom()).isEmpty(); }
private TransactionContext createContext() { TransactionContext context = new TransactionContext(); Request request = context.getRequest(); request.withHttpVersion("1.1"); request.withMethod("POST"); request.getCookies().add("c2", "v2"); context.getResponse() .withStatusCode(200) .withFinished(true) .addHeader("content-type", "application/json"); context.getUser() .withId("99") .withUsername("foo")
@Test void testBodyBufferCopy() throws IOException { final Transaction transaction = createTransactionWithRequiredValues(); final CharBuffer bodyBuffer = transaction.getContext().getRequest().withBodyBuffer(); IOUtils.decodeUtf8Bytes("{foo}".getBytes(StandardCharsets.UTF_8), bodyBuffer); bodyBuffer.flip(); Transaction copy = createTransactionWithRequiredValues(); copy.getContext().copyFrom(transaction.getContext()); assertThat(objectMapper.readTree(serializer.toJsonString(copy)).get("context")) .isEqualTo(objectMapper.readTree(serializer.toJsonString(transaction)).get("context")); }
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 testNullHeaders() throws IOException { Transaction transaction = new Transaction(mock(ElasticApmTracer.class)); transaction.getContext().getRequest().addHeader("foo", (String) null); transaction.getContext().getRequest().addHeader("baz", (Enumeration<String>) null); transaction.getContext().getRequest().getHeaders().add("bar", null); JsonNode jsonNode = objectMapper.readTree(serializer.toJsonString(transaction)); System.out.println(jsonNode); // calling addHeader with a null value ignores the header assertThat(jsonNode.get("context").get("request").get("headers").get("foo")).isNull(); assertThat(jsonNode.get("context").get("request").get("headers").get("baz")).isNull(); // should a null value sneak in, it should not break assertThat(jsonNode.get("context").get("request").get("headers").get("bar").isNull()).isTrue(); }
@Test void testCopyFrom() { TransactionContext context = createContext(); TransactionContext copyOfContext = new TransactionContext(); copyOfContext.copyFrom(context); assertThat(toJson(context)).isEqualTo(toJson(copyOfContext)); }
public void setUser(String id, String email, String username) { if (!isSampled()) { return; } getContext().getUser().withId(id).withEmail(email).withUsername(username); }
@Override public void addTag(String key, String value) { if (!isSampled()) { return; } getContext().getTags().put(key, value); }
@Override public void resetState() { exception = null; context.resetState(); timestamp = 0; transactionInfo.resetState(); traceContext.resetState(); culprit.setLength(0); }
@Test void testBodyBuffer() throws IOException { final Transaction transaction = createTransactionWithRequiredValues(); final CharBuffer bodyBuffer = transaction.getContext().getRequest().withBodyBuffer(); IOUtils.decodeUtf8Bytes("{f".getBytes(StandardCharsets.UTF_8), bodyBuffer); IOUtils.decodeUtf8Bytes(new byte[]{0, 0, 'o', 'o', 0}, 2, 2, bodyBuffer); IOUtils.decodeUtf8Byte((byte) '}', bodyBuffer); bodyBuffer.flip(); final String content = serializer.toJsonString(transaction); System.out.println(content); final JsonNode transactionJson = objectMapper.readTree(content); assertThat(transactionJson.get("context").get("request").get("body").textValue()).isEqualTo("{foo}"); transaction.resetState(); assertThat((Object) transaction.getContext().getRequest().getBodyBuffer()).isNull(); }
@Test void testSamplingNone() throws IOException { config.getConfig(CoreConfiguration.class).getSampleRate().update(0.0, SpyConfiguration.CONFIG_SOURCE_NAME); Transaction transaction = tracerImpl.startTransaction().withType("request"); try (Scope scope = transaction.activateInScope()) { transaction.setUser("1", "jon.doe@example.com", "jondoe"); Span span = tracerImpl.getActive().createSpan(); try (Scope spanScope = span.activateInScope()) { span.end(); } transaction.end(); } // we do report non-sampled transactions (without the context) assertThat(reporter.getTransactions()).hasSize(1); assertThat(reporter.getSpans()).hasSize(0); assertThat(reporter.getFirstTransaction().getContext().getUser().getEmail()).isNull(); assertThat(reporter.getFirstTransaction().getType()).isEqualTo("request"); }
@Test void testErrorSerialization() throws IOException { ElasticApmTracer tracer = MockTracer.create(); Transaction transaction = new Transaction(tracer); ErrorCapture error = new ErrorCapture(tracer).asChildOf(transaction.getTraceContext()).withTimestamp(5000); error.setTransactionSampled(true); error.setTransactionType("test-type"); error.setException(new Exception("test")); error.getContext().getTags().put("foo", "bar"); String errorJson = serializer.toJsonString(error); System.out.println("errorJson = " + errorJson); JsonNode errorTree = objectMapper.readTree(errorJson); assertThat(errorTree.get("timestamp").longValue()).isEqualTo(5000); assertThat(errorTree.get("culprit").textValue()).startsWith(this.getClass().getName()); JsonNode context = errorTree.get("context"); assertThat(context.get("tags").get("foo").textValue()).isEqualTo("bar"); JsonNode exception = errorTree.get("exception"); assertThat(exception.get("message").textValue()).isEqualTo("test"); assertThat(exception.get("stacktrace")).isNotNull(); assertThat(exception.get("type").textValue()).isEqualTo(Exception.class.getName()); assertThat(errorTree.get("transaction").get("sampled").booleanValue()).isTrue(); assertThat(errorTree.get("transaction").get("type").textValue()).isEqualTo("test-type"); }
@Override public void doEnd(long epochMicros) { if (!isSampled()) { context.resetState(); } if (type == null) { type = "custom"; } this.tracer.endTransaction(this); }
Request request = context.getRequest(); request.withHttpVersion("1.1"); request.withMethod("POST"); request.getCookies().add("c2", "v2"); context.getResponse() .withStatusCode(200) .withFinished(true) .addHeader("content-type", "application/json"); context.getUser() .withId("99") .withUsername("foo") .withEmail("foo@example.com"); context.getTags().put("organization_uuid", "9f0e9d64-c185-4d21-a6f4-4673ed561ec8"); context.getCustom().put("my_key", 1); context.getCustom().put("some_other_value", "foo bar"); context.getCustom().put("and_objects", STRINGS);
private Transaction createTransactionWithRequiredValues() { Transaction t = new Transaction(mock(ElasticApmTracer.class)); t.start(TraceContext.asRoot(), null, (long) 0, ConstantSampler.of(true)); t.withType("type"); t.getContext().getRequest().withMethod("GET"); t.getContext().getRequest().getUrl().appendToFull("http://localhost:8080/foo/bar"); return t; }
@Override public void resetState() { super.resetState(); context.resetState(); result = null; spanCount.resetState(); noop = false; type = null; }
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(); } }