diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index a361ea1efb..1d4ad79d66 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -43,6 +43,7 @@ by the agent may be different. This was done in order to improve the integration * Added support to capture `context.message.routing-key` in rabbitmq, spring amqp instrumentations - {pull}1767[#1767] * Breakdown metrics are now tracked per service (when using APM Server 8.0) - {pull}2208[#2208] * Add support for Spring AMQP batch API - {pull}1716[#1716] +* Add the (current) transaction name to the error (when using APM Server 8.0) - {pull}2235[#2235] [float] ===== Performance improvements diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index 17c9f65a35..f9a5d59bda 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -329,6 +329,9 @@ private ErrorCapture captureException(long epochMicros, @Nullable Throwable e, @ error.setException(e); Transaction currentTransaction = currentTransaction(); if (currentTransaction != null) { + if (currentTransaction.getNameForSerialization().length() > 0) { + error.setTransactionName(currentTransaction.getNameForSerialization()); + } error.setTransactionType(currentTransaction.getType()); error.setTransactionSampled(currentTransaction.isSampled()); } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/error/ErrorCapture.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/error/ErrorCapture.java index 50e0544346..cf5d017224 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/error/ErrorCapture.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/error/ErrorCapture.java @@ -238,6 +238,10 @@ public static class TransactionInfo implements Recyclable { * A hint for UI to be able to show whether a recorded trace for the corresponding transaction is expected */ private boolean isSampled; + /** + * The related TransactionInfo name + */ + private StringBuilder name = new StringBuilder(); /** * The related TransactionInfo type */ @@ -247,6 +251,7 @@ public static class TransactionInfo implements Recyclable { @Override public void resetState() { isSampled = false; + name.setLength(0); type = null; } @@ -254,6 +259,10 @@ public boolean isSampled() { return isSampled; } + public StringBuilder getName() { + return name; + } + @Nullable public String getType() { return type; @@ -268,6 +277,11 @@ public void setTransactionSampled(boolean transactionSampled) { transactionInfo.isSampled = transactionSampled; } + public void setTransactionName(@Nullable StringBuilder name) { + transactionInfo.name.setLength(0); + transactionInfo.name.append(name); + } + public void setTransactionType(@Nullable String type) { transactionInfo.type = type; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java index 44c88e7585..29b6c2e52b 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/DslJsonSerializer.java @@ -338,6 +338,9 @@ private void serializeError(ErrorCapture errorCapture) { private void serializeErrorTransactionInfo(ErrorCapture.TransactionInfo errorTransactionInfo) { writeFieldName("transaction"); jw.writeByte(JsonWriter.OBJECT_START); + if (errorTransactionInfo.getName() != null) { + writeField("name", errorTransactionInfo.getName()); + } if (errorTransactionInfo.getType() != null) { writeField("type", errorTransactionInfo.getType()); } diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerTest.java index 5c896046e3..78e98b084d 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerTest.java @@ -267,6 +267,9 @@ private ErrorCapture validateError(ErrorCapture error, AbstractSpan span, boo .describedAs("error trace context [%s] should be a child of span trace context [%s]", error.getTraceContext(), span.getTraceContext()) .isTrue(); assertThat(error.getTransactionInfo().isSampled()).isEqualTo(sampled); + if (!transaction.getNameAsString().isEmpty()) { + assertThat(error.getTransactionInfo().getName()).isEqualTo(transaction.getNameAsString()); + } assertThat(error.getTransactionInfo().getType()).isEqualTo(transaction.getType()); return error; } @@ -484,4 +487,17 @@ void testCaptureExceptionAndGetErrorId() { assertThat(error.getTraceContext().getId().toString()).isEqualTo(errorId); } + @Test + void testCaptureExceptionWithTransactionName() { + Transaction transaction = startTestRootTransaction().withName("My Transaction"); + try (Scope scope = transaction.activateInScope()) { + transaction.captureException(new Exception("test")); + transaction.end(); + } + + assertThat(reporter.getErrors()).hasSize(1); + ErrorCapture error = reporter.getFirstError(); + assertThat(error.getTransactionInfo().getName().toString()).isEqualTo("My Transaction"); + } + }