Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ endif::[]

[float]
===== Features
* Added support for setting service name and version for a transaction via the public api - {pull}2451[#2451]

[[release-notes-1.x]]
=== Java Agent version 1.x
Expand Down
17 changes: 17 additions & 0 deletions apm-agent-api/src/main/java/co/elastic/apm/api/ElasticApm.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,21 @@ public static void captureException(@Nullable Throwable e) {
// co.elastic.apm.api.ElasticApmInstrumentation.CaptureExceptionInstrumentation.captureException
}

/**
* Associates a class loader with a service name and version.
* <p>
* The association is used to overwrite the autodetected service name and version when a transaction is started.
* </p>
* <p>
* NOTE: If the class loader already is associated with a service name and version,
* the existing information will not be overwritten.
* </p>
*
* @param classLoader the class loader which should be associated with the given service name and version
* @param serviceName the service name
* @param serviceVersion the service version
*/
public static void setServiceInfoForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName, @Nullable String serviceVersion) {
// co.elastic.apm.api.ElasticApmInstrumentation.SetServiceInfoForClassLoader.setServiceInfoForClassLoader
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ public Transaction setFrameworkName(String frameworkName) {
return this;
}

@Nonnull
@Override
public Transaction setServiceInfo(String serviceName, String serviceVersion) {
// noop
return this;
}

@Nonnull
@Override
public Transaction useServiceInfoForClassLoader(ClassLoader classLoader) {
// noop
return this;
}

@Nonnull
@Deprecated
@Override
Expand Down
27 changes: 27 additions & 0 deletions apm-agent-api/src/main/java/co/elastic/apm/api/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,33 @@ public interface Transaction extends Span {
@Nonnull
Transaction setFrameworkName(String frameworkName);

/**
* Sets the service name and version for this transaction and its child spans.
* <p>
* NOTE: If this method is called after child spans are already created,
* they may have the wrong service name and version.
* </p>
*
* @param serviceName the service name
* @param serviceVersion the service version
*/
@Nonnull
Transaction setServiceInfo(String serviceName, String serviceVersion);

/**
* Sets the service name and version, that are associated with the given class loader
* (see: {@link ElasticApm#setServiceInfoForClassLoader(ClassLoader, String, String)}),
* for this transaction and its child spans.
* <p>
* NOTE: If this method is called after child spans are already created,
* they may have the wrong service name and version.
* </p>
*
* @param classLoader the class loader that should be used to set the service name and version
*/
@Nonnull
Transaction useServiceInfoForClassLoader(ClassLoader classLoader);

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ public Transaction setType(String type) {
return this;
}

@Nonnull
@Override
public Transaction setServiceInfo(String serviceName, String serviceVersion) {
// co.elastic.apm.agent.pluginapi.TransactionInstrumentation$SetServiceInfoInstrumentation
return this;
}

@Nonnull
@Override
public Transaction useServiceInfoForClassLoader(ClassLoader classLoader) {
// co.elastic.apm.agent.pluginapi.TransactionInstrumentation$UseServiceInfoForClassLoaderInstrumentation
return this;
}

@Nonnull
@Deprecated
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,9 @@ private void afterTransactionStart(@Nullable ClassLoader initiatingClassLoader,
new RuntimeException("this exception is just used to record where the transaction has been started from"));
}
}
final ServiceInfo serviceInfo = getServiceInfo(initiatingClassLoader);
final ServiceInfo serviceInfo = getServiceInfoForClassLoader(initiatingClassLoader);
if (serviceInfo != null) {
transaction.getTraceContext().setServiceName(serviceInfo.getServiceName());
transaction.getTraceContext().setServiceVersion(serviceInfo.getServiceVersion());
transaction.getTraceContext().setServiceInfo(serviceInfo.getServiceName(), serviceInfo.getServiceVersion());
}
}

Expand Down Expand Up @@ -344,10 +343,9 @@ private ErrorCapture captureException(long epochMicros, @Nullable Throwable e, @
parent.setNonDiscardable();
} else {
error.getTraceContext().getId().setToRandomValue();
ServiceInfo serviceInfo = getServiceInfo(initiatingClassLoader);
ServiceInfo serviceInfo = getServiceInfoForClassLoader(initiatingClassLoader);
if (serviceInfo != null) {
error.getTraceContext().setServiceName(serviceInfo.getServiceName());
error.getTraceContext().setServiceVersion(serviceInfo.getServiceVersion());
error.getTraceContext().setServiceInfo(serviceInfo.getServiceName(), serviceInfo.getServiceVersion());
}
}
return error;
Expand Down Expand Up @@ -750,7 +748,7 @@ public List<ServiceInfo> getServiceInfoOverrides() {
}

@Override
public void overrideServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
public void setServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
// overriding the service name/version for the bootstrap class loader is not an actual use-case
// null may also mean we don't know about the initiating class loader
if (classLoader == null
Expand All @@ -767,7 +765,8 @@ public void overrideServiceInfoForClassLoader(@Nullable ClassLoader classLoader,
}

@Nullable
public ServiceInfo getServiceInfo(@Nullable ClassLoader initiatingClassLoader) {
@Override
public ServiceInfo getServiceInfoForClassLoader(@Nullable ClassLoader initiatingClassLoader) {
if (initiatingClassLoader == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,15 @@ public TracerState getState() {
return tracer.getState();
}

@Nullable
@Override
public ServiceInfo getServiceInfoForClassLoader(@Nullable ClassLoader classLoader) {
return tracer.getServiceInfoForClassLoader(classLoader);
}

@Override
public void overrideServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
tracer.overrideServiceInfoForClassLoader(classLoader, serviceInfo);
public void setServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
tracer.setServiceInfoForClassLoader(classLoader, serviceInfo);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,14 @@ public TracerState getState() {
return TracerState.UNINITIALIZED;
}

@Nullable
@Override
public ServiceInfo getServiceInfoForClassLoader(@Nullable ClassLoader classLoader) {
return null;
}

@Override
public void overrideServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
public void setServiceInfoForClassLoader(@Nullable ClassLoader classLoader, ServiceInfo serviceInfo) {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,11 @@ <C> 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}.
* <p>
* The main use case is being able to differentiate between multiple services deployed to the same application server.
Expand All @@ -163,7 +166,7 @@ <C> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,28 +682,24 @@ 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
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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();

Expand All @@ -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();

Expand Down Expand Up @@ -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();

Expand All @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Loading