Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGet
TracerState getState();
+ @Nullable
+ ServiceInfo getServiceInfoForClassLoader(@Nullable ClassLoader classLoader);
+
/**
- * Overrides the service name and version for all {@link Transaction}s,
+ * Sets the service name and version for all {@link Transaction}s,
* {@link Span}s and {@link ErrorCapture}s which are created by the service which corresponds to the provided {@link ClassLoader}.
*
* The main use case is being able to differentiate between multiple services deployed to the same application server.
@@ -163,7 +166,7 @@ Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGet
* @param classLoader the class loader which corresponds to a particular service
* @param serviceInfo the service name and version for this class loader
*/
- void overrideServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo);
+ void setServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo);
/**
* Called when the container shuts down.
diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java
index 455e6272b6..6f2393936f 100644
--- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java
+++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TraceContext.java
@@ -682,12 +682,17 @@ public String getServiceName() {
}
/**
- * Overrides the {@code co.elastic.apm.agent.impl.payload.Service#name} property sent via the meta data Intake V2 event.
+ * Overrides the {@code co.elastic.apm.agent.impl.payload.Service#name} and {@code co.elastic.apm.agent.impl.payload.Service#version} properties sent via the meta data Intake V2 event.
*
- * @param serviceName the service name for this event
+ * @param serviceName the service name for this event
+ * @param serviceVersion the service version for this event
*/
- public void setServiceName(@Nullable String serviceName) {
+ public void setServiceInfo(@Nullable String serviceName, @Nullable String serviceVersion) {
+ if (serviceName == null || serviceName.isEmpty()) {
+ return;
+ }
this.serviceName = serviceName;
+ this.serviceVersion = serviceVersion;
}
@Nullable
@@ -695,15 +700,6 @@ public String getServiceVersion() {
return serviceVersion;
}
- /**
- * Overrides the {@code co.elastic.apm.agent.impl.payload.Service#version} property sent via the meta data Intake V2 event.
- *
- * @param serviceVersion the service version for this event
- */
- public void setServiceVersion(@Nullable String serviceVersion) {
- this.serviceVersion = serviceVersion;
- }
-
public Span createSpan() {
return tracer.startSpan(fromParentContext(), this);
}
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 113f9328c4..e38466c8de 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
@@ -434,8 +434,8 @@ void testOverrideServiceNameWithoutExplicitServiceName() {
ClassLoader cl = getClass().getClassLoader();
ServiceInfo overridden = ServiceInfo.of("overridden");
- tracer.overrideServiceInfoForClassLoader(cl, overridden);
- assertThat(tracer.getServiceInfo(cl)).isEqualTo(overridden);
+ tracer.setServiceInfoForClassLoader(cl, overridden);
+ assertThat(tracer.getServiceInfoForClassLoader(cl)).isEqualTo(overridden);
startTestRootTransaction().end();
@@ -452,8 +452,8 @@ void testNotOverrideServiceNameWhenServiceNameConfigured() {
.configurationRegistry(localConfig)
.buildAndStart();
ClassLoader cl = getClass().getClassLoader();
- tracer.overrideServiceInfoForClassLoader(cl, ServiceInfo.of("overridden"));
- assertThat(tracer.getServiceInfo(cl)).isNull();
+ tracer.setServiceInfoForClassLoader(cl, ServiceInfo.of("overridden"));
+ assertThat(tracer.getServiceInfoForClassLoader(cl)).isNull();
startTestRootTransaction().end();
@@ -474,8 +474,8 @@ void testNotOverrideServiceNameWhenDefaultServiceNameConfigured() {
.buildAndStart();
ClassLoader cl = getClass().getClassLoader();
- tracer.overrideServiceInfoForClassLoader(cl, ServiceInfo.of("overridden"));
- assertThat(tracer.getServiceInfo(cl)).isNull();
+ tracer.setServiceInfoForClassLoader(cl, ServiceInfo.of("overridden"));
+ assertThat(tracer.getServiceInfoForClassLoader(cl)).isNull();
startTestRootTransaction().end();
@@ -505,7 +505,7 @@ void testOverrideServiceVersionWithoutExplicitServiceVersion() {
.buildAndStart();
ServiceInfo overridden = ServiceInfo.of("overridden_name", "overridden_version");
- tracer.overrideServiceInfoForClassLoader(getClass().getClassLoader(), overridden);
+ tracer.setServiceInfoForClassLoader(getClass().getClassLoader(), overridden);
startTestRootTransaction().end();
@@ -522,8 +522,8 @@ void testNotOverrideServiceVersionWhenServiceVersionConfigured() {
ServiceInfo overridden = ServiceInfo.of("overridden_name", "overridden_version");
ClassLoader cl = getClass().getClassLoader();
- tracer.overrideServiceInfoForClassLoader(cl, overridden);
- assertThat(tracer.getServiceInfo(cl)).isEqualTo(overridden);
+ tracer.setServiceInfoForClassLoader(cl, overridden);
+ assertThat(tracer.getServiceInfoForClassLoader(cl)).isEqualTo(overridden);
startTestRootTransaction().end();
diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/SpanTypeBreakdownTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/SpanTypeBreakdownTest.java
index d6eabb05d8..31c724d116 100644
--- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/SpanTypeBreakdownTest.java
+++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/SpanTypeBreakdownTest.java
@@ -348,7 +348,7 @@ void testBreakdown_spanStartedAfterParentEnded() {
@Test
void testBreakdown_serviceName() {
final Transaction transaction = createTransaction();
- transaction.getTraceContext().setServiceName("service_name");
+ transaction.getTraceContext().setServiceInfo("service_name", null);
transaction.createSpan(11).withType("db").withSubtype("mysql").end(23);
transaction.end(27);
@@ -363,8 +363,7 @@ void testBreakdown_serviceName() {
@Test
void testBreakdown_serviceNameAndVersion() {
final Transaction transaction = createTransaction();
- transaction.getTraceContext().setServiceName("service_name");
- transaction.getTraceContext().setServiceVersion("service_version");
+ transaction.getTraceContext().setServiceInfo("service_name", "service_version");
transaction.createSpan(11).withType("db").withSubtype("mysql").end(23);
transaction.end(27);
diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java
index b53de50530..e9512b7d98 100644
--- a/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java
+++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/impl/transaction/TraceContextTest.java
@@ -744,4 +744,27 @@ void testDeserialization() {
assertThat(deserialized.getClock().getOffset()).isEqualTo(traceContext.getClock().getOffset());
}
+ @Test
+ void testSetServiceInfoWithEmptyServiceName() {
+ TraceContext traceContext = TraceContext.with64BitId(tracer);
+
+ traceContext.setServiceInfo(null, "My Version");
+ assertThat(traceContext.getServiceName()).isNull();
+ assertThat(traceContext.getServiceVersion()).isNull();
+ traceContext.setServiceInfo("", "My Version");
+ assertThat(traceContext.getServiceName()).isNull();
+ assertThat(traceContext.getServiceVersion()).isNull();
+ }
+
+ @Test
+ void testSetServiceInfoWithNonEmptyServiceName() {
+ TraceContext traceContext = TraceContext.with64BitId(tracer);
+
+ traceContext.setServiceInfo("My Service", null);
+ assertThat(traceContext.getServiceName()).isEqualTo("My Service");
+ assertThat(traceContext.getServiceVersion()).isNull();
+ traceContext.setServiceInfo("My Service", "My Version");
+ assertThat(traceContext.getServiceName()).isEqualTo("My Service");
+ assertThat(traceContext.getServiceVersion()).isEqualTo("My Version");
+ }
}
diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java
index d140d0471b..b6dd633e3b 100644
--- a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java
+++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/DslJsonSerializerTest.java
@@ -441,7 +441,7 @@ void testSpanDestinationContextSerialization() {
@Test
void testTransactionNullFrameworkNameSerialization() {
Transaction transaction = new Transaction(MockTracer.create());
- transaction.getTraceContext().setServiceName("service-name");
+ transaction.getTraceContext().setServiceInfo("service-name", null);
transaction.setUserFrameworkName(null);
JsonNode transactionJson = readJsonString(serializer.toJsonString(transaction));
assertThat(transactionJson.get("context").get("service").get("framework")).isNull();
@@ -450,7 +450,7 @@ void testTransactionNullFrameworkNameSerialization() {
@Test
void testTransactionEmptyFrameworkNameSerialization() {
Transaction transaction = new Transaction(MockTracer.create());
- transaction.getTraceContext().setServiceName("service-name");
+ transaction.getTraceContext().setServiceInfo("service-name", null);
transaction.setUserFrameworkName("");
JsonNode transactionJson = readJsonString(serializer.toJsonString(transaction));
assertThat(transactionJson.get("context").get("service").get("framework")).isNull();
@@ -827,8 +827,7 @@ void testTransactionContextSerialization() {
String frameworkName = RandomStringUtils.randomAlphanumeric(10);
String frameworkVersion = RandomStringUtils.randomNumeric(3);
- ctx.setServiceName(serviceName);
- ctx.setServiceVersion(serviceVersion);
+ ctx.setServiceInfo(serviceName, serviceVersion);
transaction.setFrameworkName(frameworkName);
transaction.setFrameworkVersion(frameworkVersion);
diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricRegistryReporterTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricRegistryReporterTest.java
index d965364c59..6f646b0bc5 100644
--- a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricRegistryReporterTest.java
+++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricRegistryReporterTest.java
@@ -41,7 +41,7 @@ void testReportedMetricsUseDefaultServiceNameIfServiceNameIsExplicitlySet() thro
.configurationRegistry(SpyConfiguration.createSpyConfig(SimpleSource.forTest("service_name", "foo")))
.reporter(reporter)
.buildAndStart();
- tracer.overrideServiceInfoForClassLoader(MetricRegistryReporterTest.class.getClassLoader(), ServiceInfo.of("MetricRegistryReporterTest"));
+ tracer.setServiceInfoForClassLoader(MetricRegistryReporterTest.class.getClassLoader(), ServiceInfo.of("MetricRegistryReporterTest"));
new MetricRegistryReporter(tracer).run();
diff --git a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/ElasticApmApiInstrumentation.java b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/ElasticApmApiInstrumentation.java
index 471ae0ff02..1ee320425b 100644
--- a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/ElasticApmApiInstrumentation.java
+++ b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/ElasticApmApiInstrumentation.java
@@ -18,6 +18,7 @@
*/
package co.elastic.apm.agent.pluginapi;
+import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.impl.transaction.Transaction;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
@@ -147,4 +148,16 @@ public static void captureException(@Advice.Origin Class> clazz, @Advice.Argum
}
}
+ public static class SetServiceInfoForClassLoaderInstrumentation extends ElasticApmApiInstrumentation {
+ public SetServiceInfoForClassLoaderInstrumentation() {
+ super(named("setServiceInfoForClassLoader"));
+ }
+
+ public static class AdviceClass {
+ @Advice.OnMethodExit(suppress = Throwable.class, inline = false)
+ public static void setServiceInfoForClassLoader(@Advice.Argument(0) @Nullable ClassLoader classLoader, @Advice.Argument(1) String serviceName, @Advice.Argument(2) @Nullable String serviceVersion) {
+ tracer.setServiceInfoForClassLoader(classLoader, ServiceInfo.of(serviceName, serviceVersion));
+ }
+ }
+ }
}
diff --git a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentation.java b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentation.java
index d96638fabd..766cf743eb 100644
--- a/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentation.java
+++ b/apm-agent-plugins/apm-api-plugin/src/main/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentation.java
@@ -18,6 +18,7 @@
*/
package co.elastic.apm.agent.pluginapi;
+import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.impl.transaction.Id;
import co.elastic.apm.agent.impl.transaction.TraceContext;
import co.elastic.apm.agent.impl.transaction.Transaction;
@@ -147,4 +148,39 @@ public static void addCustomContext(@Advice.FieldValue(value = "span", typing =
}
}
}
+
+ public static class SetServiceInfoInstrumentation extends TransactionInstrumentation {
+ public SetServiceInfoInstrumentation() {
+ super(named("setServiceInfo"));
+ }
+
+ public static class AdviceClass {
+ @Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
+ public static void setServiceInfo(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) Object transaction,
+ @Advice.Argument(0) String serviceName, @Advice.Argument(1) String serviceVersion) {
+ if (transaction instanceof Transaction) {
+ ((Transaction) transaction).getTraceContext().setServiceInfo(serviceName, serviceVersion);
+ }
+ }
+ }
+ }
+
+ public static class UseServiceInfoForClassLoaderInstrumentation extends TransactionInstrumentation {
+ public UseServiceInfoForClassLoaderInstrumentation() {
+ super(named("useServiceInfoForClassLoader"));
+ }
+
+ public static class AdviceClass {
+ @Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
+ public static void useServiceInfoForClassLoader(@Advice.FieldValue(value = "span", typing = Assigner.Typing.DYNAMIC) Object transaction,
+ @Advice.Argument(0) ClassLoader classLoader) {
+ if (transaction instanceof Transaction) {
+ ServiceInfo serviceInfo = tracer.getServiceInfoForClassLoader(classLoader);
+ if (serviceInfo != null) {
+ ((Transaction) transaction).getTraceContext().setServiceInfo(serviceInfo.getServiceName(), serviceInfo.getServiceVersion());
+ }
+ }
+ }
+ }
+ }
}
diff --git a/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation b/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
index 161e9bceca..dd2716fdfd 100644
--- a/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
+++ b/apm-agent-plugins/apm-api-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.sdk.ElasticApmInstrumentation
@@ -3,11 +3,14 @@ co.elastic.apm.agent.pluginapi.ElasticApmApiInstrumentation$StartTransactionWith
co.elastic.apm.agent.pluginapi.ElasticApmApiInstrumentation$CurrentTransactionInstrumentation
co.elastic.apm.agent.pluginapi.ElasticApmApiInstrumentation$CurrentSpanInstrumentation
co.elastic.apm.agent.pluginapi.ElasticApmApiInstrumentation$CaptureExceptionInstrumentation
+co.elastic.apm.agent.pluginapi.ElasticApmApiInstrumentation$SetServiceInfoForClassLoaderInstrumentation
co.elastic.apm.agent.pluginapi.TransactionInstrumentation$SetFrameworkNameInstrumentation
co.elastic.apm.agent.pluginapi.TransactionInstrumentation$SetUserInstrumentation
co.elastic.apm.agent.pluginapi.TransactionInstrumentation$EnsureParentIdInstrumentation
co.elastic.apm.agent.pluginapi.TransactionInstrumentation$SetResultInstrumentation
co.elastic.apm.agent.pluginapi.TransactionInstrumentation$AddCustomContextInstrumentation
+co.elastic.apm.agent.pluginapi.TransactionInstrumentation$SetServiceInfoInstrumentation
+co.elastic.apm.agent.pluginapi.TransactionInstrumentation$UseServiceInfoForClassLoaderInstrumentation
co.elastic.apm.agent.pluginapi.AbstractSpanInstrumentation$SetNameInstrumentation
co.elastic.apm.agent.pluginapi.AbstractSpanInstrumentation$SetTypeInstrumentation
co.elastic.apm.agent.pluginapi.AbstractSpanInstrumentation$SetTypesInstrumentation
diff --git a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentationTest.java b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentationTest.java
index cd84e97cba..ab3cdd5202 100644
--- a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentationTest.java
+++ b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/agent/pluginapi/TransactionInstrumentationTest.java
@@ -19,6 +19,7 @@
package co.elastic.apm.agent.pluginapi;
import co.elastic.apm.AbstractApiTest;
+import co.elastic.apm.agent.configuration.ServiceInfo;
import co.elastic.apm.agent.impl.TracerInternalApiUtils;
import co.elastic.apm.api.AbstractSpanImplAccessor;
import co.elastic.apm.api.ElasticApm;
@@ -296,6 +297,27 @@ void setOutcome_success() {
testSetOutcome(Outcome.SUCCESS);
}
+ @Test
+ void setSetServiceInfo() {
+ transaction.setServiceInfo("My Service", "My Version");
+ endTransaction();
+ assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("My Service");
+ assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("My Version");
+ }
+
+ @Test
+ void useServiceInfoForClassLoader() {
+ try {
+ tracer.setServiceInfoForClassLoader(TransactionInstrumentationTest.class.getClassLoader(), ServiceInfo.of("My Service", "My Version"));
+ transaction.useServiceInfoForClassLoader(TransactionInstrumentationTest.class.getClassLoader());
+ endTransaction();
+ assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("My Service");
+ assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("My Version");
+ } finally {
+ tracer.resetServiceInfoOverrides();
+ }
+ }
+
private void testSetOutcome(Outcome outcome) {
// set it first to a different value than the expected one
Outcome[] values = Outcome.values();
diff --git a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/api/ElasticApmApiInstrumentationTest.java b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/api/ElasticApmApiInstrumentationTest.java
index 78183567bc..bb4ed04e09 100644
--- a/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/api/ElasticApmApiInstrumentationTest.java
+++ b/apm-agent-plugins/apm-api-plugin/src/test/java/co/elastic/apm/api/ElasticApmApiInstrumentationTest.java
@@ -330,7 +330,7 @@ void testManualTimestampsDeactivated() {
@Test
void testOverrideServiceNameForClassLoader() {
ServiceInfo overridden = ServiceInfo.of("overridden");
- tracer.overrideServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
+ tracer.setServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
ElasticApm.startTransaction().end();
checkTransactionServiceInfo(overridden);
}
@@ -338,7 +338,7 @@ void testOverrideServiceNameForClassLoader() {
@Test
void testOverrideServiceNameForClassLoaderWithRemoteParent() {
ServiceInfo overridden = ServiceInfo.of("overridden");
- tracer.overrideServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
+ tracer.setServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
ElasticApm.startTransactionWithRemoteParent(key -> null).end();
checkTransactionServiceInfo(overridden);
}
@@ -346,7 +346,7 @@ void testOverrideServiceNameForClassLoaderWithRemoteParent() {
@Test
void testOverrideServiceVersionForClassLoader() {
ServiceInfo overridden = ServiceInfo.of("overridden_name", "overridden_version");
- tracer.overrideServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
+ tracer.setServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
ElasticApm.startTransaction().end();
checkTransactionServiceInfo(overridden);
}
@@ -354,7 +354,7 @@ void testOverrideServiceVersionForClassLoader() {
@Test
void testOverrideServiceVersionForClassLoaderWithRemoteParent() {
ServiceInfo overridden = ServiceInfo.of("overridden_name", "overridden_version");
- tracer.overrideServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
+ tracer.setServiceInfoForClassLoader(Transaction.class.getClassLoader(), overridden);
ElasticApm.startTransactionWithRemoteParent(key -> null).end();
checkTransactionServiceInfo(overridden);
}
@@ -370,4 +370,16 @@ void testFrameworkNameWithStartTransactionWithRemoteParent() {
ElasticApm.startTransactionWithRemoteParent(null).end();
assertThat(reporter.getFirstTransaction().getFrameworkName()).isEqualTo("API");
}
+
+ @Test
+ void testSetServiceInfo() {
+ try {
+ ElasticApm.setServiceInfoForClassLoader(ElasticApmApiInstrumentationTest.class.getClassLoader(), "My Service", "My Version");
+ ServiceInfo getServiceInfo = tracer.getServiceInfoForClassLoader(ElasticApmApiInstrumentationTest.class.getClassLoader());
+ assertThat(getServiceInfo.getServiceName()).isEqualTo("My Service");
+ assertThat(getServiceInfo.getServiceVersion()).isEqualTo("My Version");
+ } finally {
+ tracer.resetServiceInfoOverrides();
+ }
+ }
}
diff --git a/apm-agent-plugins/apm-ecs-logging-plugin/src/main/java/co/elastic/apm/agent/ecs_logging/Log4j2ServiceNameInstrumentation.java b/apm-agent-plugins/apm-ecs-logging-plugin/src/main/java/co/elastic/apm/agent/ecs_logging/Log4j2ServiceNameInstrumentation.java
index ac11702d62..435f8b51b8 100644
--- a/apm-agent-plugins/apm-ecs-logging-plugin/src/main/java/co/elastic/apm/agent/ecs_logging/Log4j2ServiceNameInstrumentation.java
+++ b/apm-agent-plugins/apm-ecs-logging-plugin/src/main/java/co/elastic/apm/agent/ecs_logging/Log4j2ServiceNameInstrumentation.java
@@ -65,7 +65,7 @@ public static class AdviceClass {
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
public static void onEnter(@Advice.This EcsLayout.Builder builder) {
if (builder.getServiceName() == null || builder.getServiceName().isEmpty()) {
- ServiceInfo serviceInfo = tracer.getServiceInfo(Thread.currentThread().getContextClassLoader());
+ ServiceInfo serviceInfo = tracer.getServiceInfoForClassLoader(Thread.currentThread().getContextClassLoader());
String configuredServiceName = tracer.getConfig(CoreConfiguration.class).getServiceName();
builder.setServiceName(serviceInfo != null ? serviceInfo.getServiceName() : configuredServiceName);
}
diff --git a/apm-agent-plugins/apm-servlet-plugin/src/main/java/co/elastic/apm/agent/servlet/ServletServiceNameHelper.java b/apm-agent-plugins/apm-servlet-plugin/src/main/java/co/elastic/apm/agent/servlet/ServletServiceNameHelper.java
index 8ed2c4850d..2b00e0fb01 100644
--- a/apm-agent-plugins/apm-servlet-plugin/src/main/java/co/elastic/apm/agent/servlet/ServletServiceNameHelper.java
+++ b/apm-agent-plugins/apm-servlet-plugin/src/main/java/co/elastic/apm/agent/servlet/ServletServiceNameHelper.java
@@ -51,7 +51,7 @@ public static void determineServiceName(ServletContextAdapter ServiceInfo detectServiceInfo(ServletContextAdapter adapter, ServletContext servletContext, ClassLoader servletContextClassLoader) {
diff --git a/apm-agent-plugins/apm-spring-webmvc-plugin/src/main/java/co/elastic/apm/agent/springwebmvc/SpringServiceNameInstrumentation.java b/apm-agent-plugins/apm-spring-webmvc-plugin/src/main/java/co/elastic/apm/agent/springwebmvc/SpringServiceNameInstrumentation.java
index 60c2ff3a97..f7cd9204d8 100644
--- a/apm-agent-plugins/apm-spring-webmvc-plugin/src/main/java/co/elastic/apm/agent/springwebmvc/SpringServiceNameInstrumentation.java
+++ b/apm-agent-plugins/apm-spring-webmvc-plugin/src/main/java/co/elastic/apm/agent/springwebmvc/SpringServiceNameInstrumentation.java
@@ -97,7 +97,7 @@ public static void afterInitPropertySources(@Advice.This WebApplicationContext a
ServiceInfo fromSpringApplicationNameProperty = ServiceInfo.of(applicationContext.getEnvironment().getProperty("spring.application.name", ""));
ServiceInfo fromApplicationContextApplicationName = ServiceInfo.of(removeLeadingSlash(applicationContext.getApplicationName()));
- tracer.overrideServiceInfoForClassLoader(classLoader, fromSpringApplicationNameProperty
+ tracer.setServiceInfoForClassLoader(classLoader, fromSpringApplicationNameProperty
.withFallback(fromServletContext)
.withFallback(fromApplicationContextApplicationName));
}
diff --git a/docs/public-api.asciidoc b/docs/public-api.asciidoc
index 2861f1c11e..54a70cf15d 100644
--- a/docs/public-api.asciidoc
+++ b/docs/public-api.asciidoc
@@ -192,6 +192,19 @@ public Response onIncomingRequest(Request request) throws Exception {
NOTE: If the protocol does not support multi-value headers, use <>
+[float]
+[[api-set-service-info-for-class-loader]]
+==== `void setServiceInfoForClassLoader(ClassLoader, String, String)` added[1.30.0]
+Associates a class loader with a service name and version.
+
+The association is used to overwrite the autodetected service name and version when a transaction is started.
+
+NOTE: If the class loader already is associated with a service name and version, the existing information will not be overwritten.
+
+* `classLoader`: the class loader which should be associated with the given service name and version
+* `serviceName`: the service name
+* `serviceVersion`: the service version
+
//----------------------------
[float]
[[api-annotation]]
@@ -329,6 +342,27 @@ transaction.setFrameworkName("My Framework");
* `frameworkName`: The name of the framework
+[float]
+[[api-transaction-set-service-info]]
+==== `Transaction setServiceInfo(String serviceName, String serviceVersion)` added[1.30.0]
+Sets the service name and version for this transaction and its child spans.
+
+NOTE: If this method is called after child spans are already created, they may have the wrong service name and version.
+
+* `serviceName`: the service name
+* `serviceVersion`: the service version
+
+[float]
+[[api-transaction-use-service-info-for-class-loader]]
+==== `Transaction useServiceInfoForClassLoader(ClassLoader classLoader)` added[1.30.0]
+Sets the service name and version, that are associated with the given class loader
+(see: <>),
+for this transaction and its child spans.
+
+NOTE: If this method is called after child spans are already created, they may have the wrong service name and version.
+
+* `classLoader`: the class loader that should be used to set the service name and version
+
[float]
[[api-transaction-add-tag]]
==== `Transaction setLabel(String key, value)` added[1.5.0 as `addLabel`,Number and boolean labels require APM Server 6.7]
diff --git a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ExternalPluginTestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ExternalPluginTestApp.java
index 5c07b4cc4f..27621fe601 100644
--- a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ExternalPluginTestApp.java
+++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ExternalPluginTestApp.java
@@ -92,7 +92,7 @@ private void executeTest(final AbstractServletContainerIntegrationTest container
/**
* Since we test custom transaction creation through the external plugin, the service name for this transaction cannot be
- * captured through the {@link Tracer#overrideServiceInfoForClassLoader(ClassLoader, ServiceInfo)} mechanism.
+ * captured through the {@link Tracer#setServiceInfoForClassLoader(ClassLoader, ServiceInfo)} mechanism.
*/
@Nullable
@Override