From d6e54d6b9beaf795b037adab8e9c223c5b2121bb Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Tue, 30 Mar 2021 16:07:16 +0200 Subject: [PATCH 1/5] Added support for overwriting the service version per classloader, similar to service name (#1725) --- .../configuration/CoreConfiguration.java | 4 +++ .../apm/agent/impl/ElasticApmTracer.java | 34 +++++++++++++++++++ .../elastic/apm/agent/impl/GlobalTracer.java | 5 +++ .../co/elastic/apm/agent/impl/NoopTracer.java | 8 +++-- .../co/elastic/apm/agent/impl/Tracer.java | 12 +++++++ .../agent/impl/transaction/TraceContext.java | 26 ++++++++++++-- .../report/serialize/DslJsonSerializer.java | 12 ++++--- .../agent/AbstractInstrumentationTest.java | 1 + .../apm/agent/impl/ElasticApmTracerTest.java | 26 ++++++++++++++ .../impl/transaction/TraceContextTest.java | 2 +- .../serialize/DslJsonSerializerTest.java | 3 ++ ...elasticapm.with-service-version.properties | 1 + .../api/ElasticApmApiInstrumentationTest.java | 14 ++++++++ .../elastic/apm/agent/profiler/CallTree.java | 10 +++--- .../apm/agent/profiler/SamplingProfiler.java | 23 +++++++++++-- .../agent/profiler/CallTreeSpanifyTest.java | 2 +- .../apm/agent/profiler/CallTreeTest.java | 2 +- ...tractViewRenderingInstrumentationTest.java | 1 + 18 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 apm-agent-core/src/test/resources/test.elasticapm.with-service-version.properties diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 31ccf525b8..c9fa41c5af 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -638,6 +638,10 @@ public String getServiceVersion() { return serviceVersion.get(); } + public ConfigurationOption getServiceVersionConfig() { + return serviceVersion; + } + public String getHostname() { return hostname.get(); } 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 cefed8edcb..403c8a814a 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 @@ -78,6 +78,8 @@ public class ElasticApmTracer implements Tracer { private static final WeakConcurrentMap serviceNameByClassLoader = WeakMapSupplier.createMap(); + private static final WeakConcurrentMap serviceVersionByClassLoader = WeakMapSupplier.createMap(); + private final ConfigurationRegistry configurationRegistry; private final StacktraceConfiguration stacktraceConfiguration; private final ApmServerClient apmServerClient; @@ -226,6 +228,10 @@ private void afterTransactionStart(@Nullable ClassLoader initiatingClassLoader, if (serviceName != null) { transaction.getTraceContext().setServiceName(serviceName); } + final String serviceVersion = getServiceVersion(initiatingClassLoader); + if (serviceVersion != null) { + transaction.getTraceContext().setServiceVersion(serviceVersion); + } } public Transaction noopTransaction() { @@ -332,6 +338,7 @@ private ErrorCapture captureException(long epochMicros, @Nullable Throwable e, @ } else { error.getTraceContext().getId().setToRandomValue(); error.getTraceContext().setServiceName(getServiceName(initiatingClassLoader)); + error.getTraceContext().setServiceVersion(getServiceVersion(initiatingClassLoader)); } return error; } @@ -735,6 +742,33 @@ public void resetServiceNameOverrides() { serviceNameByClassLoader.clear(); } + @Override + public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { + // overriding the service 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 + || serviceVersion == null || serviceVersion.isEmpty() + // if the service version is set explicitly, don't override it + || coreConfiguration.getServiceVersionConfig().getUsedKey() != null) { + return; + } + if (!serviceVersionByClassLoader.containsKey(classLoader)) { + serviceVersionByClassLoader.putIfAbsent(classLoader, serviceVersion); + } + } + + @Nullable + private String getServiceVersion(@Nullable ClassLoader initiatingClassLoader) { + if (initiatingClassLoader == null) { + return null; + } + return serviceVersionByClassLoader.get(initiatingClassLoader); + } + + public void resetServiceVersionOverrides() { + serviceVersionByClassLoader.clear(); + } + public ApmServerClient getApmServerClient() { return apmServerClient; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java index 2418c283c3..ba5a55d1fd 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java @@ -156,6 +156,11 @@ public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, tracer.overrideServiceNameForClassLoader(classLoader, serviceName); } + @Override + public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { + tracer.overrideServiceVersionForClassLoader(classLoader, serviceVersion); + } + @Override public void stop() { tracer.stop(); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java index fecb117d8b..6dfec5ae2a 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java @@ -11,9 +11,9 @@ * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -127,6 +127,10 @@ public TracerState getState() { public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName) { } + @Override + public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { + } + @Override public void stop() { } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java index 90fa702bc8..75b9f1a6b1 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java @@ -164,6 +164,18 @@ Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGet */ void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName); + /** + * Overrides the service 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. + *

+ * + * @param classLoader the class loader which corresponds to a particular service + * @param serviceVersion the service version for this class loader + */ + void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion); + /** * Called when the container shuts down. * Cleans up thread pools and other resources. 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 6d5921d4d1..cbe004f00b 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 @@ -246,6 +246,9 @@ public static void copyTraceContextTextHeaders(S source, TextHeaderGetter @Nullable private String serviceName; + @Nullable + private String serviceVersion; + private TraceContext(ElasticApmTracer tracer, Id id) { coreConfiguration = tracer.getConfig(CoreConfiguration.class); traceState = new TraceState(); @@ -441,6 +444,7 @@ public void asChildOf(TraceContext parent) { id.setToRandomValue(); clock.init(parent.clock); serviceName = parent.serviceName; + serviceVersion = parent.serviceVersion; applicationClassLoader = parent.applicationClassLoader; traceState.copyFrom(parent.traceState); onMutation(); @@ -457,6 +461,7 @@ public void resetState() { discardable = true; clock.resetState(); serviceName = null; + serviceVersion = null; applicationClassLoader = null; traceState.resetState(); traceState.setSizeLimit(coreConfiguration.getTracestateSizeLimit()); @@ -657,6 +662,7 @@ public void copyFrom(TraceContext other) { discardable = other.discardable; clock.init(other.clock); serviceName = other.serviceName; + serviceVersion = other.serviceVersion; applicationClassLoader = other.applicationClassLoader; traceState.copyFrom(other.traceState); onMutation(); @@ -689,6 +695,20 @@ public void setServiceName(@Nullable String serviceName) { this.serviceName = serviceName; } + @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); } @@ -757,7 +777,7 @@ public void serialize(byte[] buffer) { ByteUtils.putLong(buffer, offset, clock.getOffset()); } - private void asChildOf(byte[] buffer, @Nullable String serviceName) { + private void asChildOf(byte[] buffer, @Nullable String serviceName, @Nullable String serviceVersion) { int offset = 0; offset += traceId.fromBytes(buffer, offset); offset += parentId.fromBytes(buffer, offset); @@ -767,10 +787,11 @@ private void asChildOf(byte[] buffer, @Nullable String serviceName) { discardable = buffer[offset++] == (byte) 1; clock.init(ByteUtils.getLong(buffer, offset)); this.serviceName = serviceName; + this.serviceVersion = serviceVersion; onMutation(); } - public void deserialize(byte[] buffer, @Nullable String serviceName) { + public void deserialize(byte[] buffer, @Nullable String serviceName, @Nullable String serviceVersion) { int offset = 0; offset += traceId.fromBytes(buffer, offset); offset += id.fromBytes(buffer, offset); @@ -779,6 +800,7 @@ public void deserialize(byte[] buffer, @Nullable String serviceName) { discardable = buffer[offset++] == (byte) 1; clock.init(ByteUtils.getLong(buffer, offset)); this.serviceName = serviceName; + this.serviceVersion = serviceVersion; onMutation(); } 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 a1a29e0c9b..ad5c01893a 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 @@ -666,10 +666,12 @@ private void serializeSpan(final Span span) { private void serializeServiceName(TraceContext traceContext) { String serviceName = traceContext.getServiceName(); - if (serviceName != null) { + String serviceVersion = traceContext.getServiceVersion(); + if (serviceName != null || serviceVersion != null) { writeFieldName("service"); jw.writeByte(OBJECT_START); - writeLastField("name", serviceName); + writeField("name", serviceName); + writeLastField("version", serviceVersion); jw.writeByte(OBJECT_END); jw.writeByte(COMMA); } @@ -677,14 +679,16 @@ private void serializeServiceName(TraceContext traceContext) { private void serializeServiceNameWithFramework(@Nullable final Transaction transaction, final TraceContext traceContext) { String serviceName = traceContext.getServiceName(); + String serviceVersion = traceContext.getServiceVersion(); boolean isFrameworkNameNotNull = transaction != null && transaction.getFrameworkName() != null; - if (serviceName != null || isFrameworkNameNotNull) { + if (serviceName != null || serviceVersion != null || isFrameworkNameNotNull) { writeFieldName("service"); jw.writeByte(OBJECT_START); if (isFrameworkNameNotNull) { serializeFramework(transaction.getFrameworkName(), transaction.getFrameworkVersion()); } - writeLastField("name", serviceName); + writeField("name", serviceName); + writeLastField("version", serviceVersion); jw.writeByte(OBJECT_END); jw.writeByte(COMMA); } diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java index a38782fd24..cf002b72d6 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java @@ -105,6 +105,7 @@ public final void cleanUp() { } } tracer.resetServiceNameOverrides(); + tracer.resetServiceVersionOverrides(); assertThat(tracer.getActive()) .describedAs("nothing should be left active at end of test, failure will likely indicate a span/transaction still active") 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 46b0c2ea9d..164f8f75fb 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 @@ -477,6 +477,32 @@ void testNotOverrideServiceNameWhenDefaultServiceNameConfigured() { } } + @Test + void testOverrideServiceVersionWithoutExplicitServiceVersion() { + final ElasticApmTracer tracer = new ElasticApmTracerBuilder() + .reporter(reporter) + .buildAndStart(); + tracer.overrideServiceVersionForClassLoader(getClass().getClassLoader(), "overridden"); + + startTestRootTransaction().end(); + + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + } + + @Test + void testNotOverrideServiceVersionWhenServiceVersionConfigured() { + ConfigurationRegistry localConfig = SpyConfiguration.createSpyConfig(new PropertyFileConfigurationSource("test.elasticapm.with-service-version.properties")); + final ElasticApmTracer tracer = new ElasticApmTracerBuilder() + .reporter(reporter) + .configurationRegistry(localConfig) + .buildAndStart(); + tracer.overrideServiceVersionForClassLoader(getClass().getClassLoader(), "overridden"); + + startTestRootTransaction().end(); + + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isNull(); + } + @Test void testCaptureExceptionAndGetErrorId() { Transaction transaction = startTestRootTransaction(); 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 677bea3467..2b8c0b4ef1 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 @@ -741,7 +741,7 @@ void testDeserialization() { traceContext.serialize(serializedContext); TraceContext deserialized = TraceContext.with64BitId(tracer); - deserialized.deserialize(serializedContext, null); + deserialized.deserialize(serializedContext, null, null); assertThat(deserialized.traceIdAndIdEquals(serializedContext)).isTrue(); assertThat(deserialized.getTraceId()).isEqualTo(traceContext.getTraceId()); 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 50afa74b76..7509caf6ff 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 @@ -604,10 +604,12 @@ void testTransactionContextSerialization() { TraceContext ctx = transaction.getTraceContext(); String serviceName = RandomStringUtils.randomAlphabetic(5); + String serviceVersion = RandomStringUtils.randomAlphabetic(5); String frameworkName = RandomStringUtils.randomAlphanumeric(10); String frameworkVersion = RandomStringUtils.randomNumeric(3); ctx.setServiceName(serviceName); + ctx.setServiceVersion(serviceVersion); transaction.setFrameworkName(frameworkName); transaction.setFrameworkVersion(frameworkVersion); @@ -620,6 +622,7 @@ void testTransactionContextSerialization() { assertThat(jsonContext.get("user").get("email").asText()).isEqualTo("user@email.com"); assertThat(jsonContext.get("user").get("username").asText()).isEqualTo("bob"); assertThat(jsonContext.get("service").get("name").asText()).isEqualTo(serviceName); + assertThat(jsonContext.get("service").get("version").asText()).isEqualTo(serviceVersion); assertThat(jsonContext.get("service").get("framework").get("name").asText()).isEqualTo(frameworkName); assertThat(jsonContext.get("service").get("framework").get("version").asText()).isEqualTo(frameworkVersion); diff --git a/apm-agent-core/src/test/resources/test.elasticapm.with-service-version.properties b/apm-agent-core/src/test/resources/test.elasticapm.with-service-version.properties new file mode 100644 index 0000000000..908f6c963c --- /dev/null +++ b/apm-agent-core/src/test/resources/test.elasticapm.with-service-version.properties @@ -0,0 +1 @@ +service_version=TEST_SERVICE_VERSION 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 c50b786310..30fe3d6bc3 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 @@ -346,6 +346,20 @@ void testOverrideServiceNameForClassLoaderWithRemoteParent() { assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("overridden"); } + @Test + void testOverrideServiceVersionForClassLoader() { + tracer.overrideServiceVersionForClassLoader(Transaction.class.getClassLoader(), "overridden"); + ElasticApm.startTransaction().end(); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + } + + @Test + void testOverrideServiceVersionForClassLoaderWithRemoteParent() { + tracer.overrideServiceVersionForClassLoader(Transaction.class.getClassLoader(), "overridden"); + ElasticApm.startTransactionWithRemoteParent(key -> null).end(); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + } + @Test void testFrameworkNameWithStartTransactionWithRemoteParent() { ElasticApm.startTransactionWithRemoteParent(null).end(); diff --git a/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/CallTree.java b/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/CallTree.java index 35c3ebe86a..4655396f20 100644 --- a/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/CallTree.java +++ b/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/CallTree.java @@ -154,9 +154,9 @@ private boolean happenedAfter(long timestamp) { return lastSeen < timestamp; } - public static CallTree.Root createRoot(ObjectPool rootPool, byte[] traceContext, @Nullable String serviceName, long nanoTime) { + public static CallTree.Root createRoot(ObjectPool rootPool, byte[] traceContext, @Nullable String serviceName, @Nullable String serviceVersion, long nanoTime) { CallTree.Root root = rootPool.createInstance(); - root.set(traceContext, serviceName, nanoTime); + root.set(traceContext, serviceName, serviceVersion, nanoTime); return root; } @@ -602,9 +602,9 @@ public Root(ElasticApmTracer tracer) { this.rootContext = TraceContext.with64BitId(tracer); } - private void set(byte[] traceContext, @Nullable String serviceName, long nanoTime) { + private void set(byte[] traceContext, @Nullable String serviceName, @Nullable String serviceVersion, long nanoTime) { super.set(null, ROOT_FRAME, nanoTime); - this.rootContext.deserialize(traceContext, serviceName); + this.rootContext.deserialize(traceContext, serviceName, serviceVersion); setActiveSpan(traceContext, nanoTime); } @@ -666,7 +666,7 @@ public void addStackTrace(ElasticApmTracer tracer, List stackTrace, if (activeSpan == null) { firstFrameAfterActivation = true; activeSpan = TraceContext.with64BitId(tracer); - activeSpan.deserialize(activeSpanSerialized, rootContext.getServiceName()); + activeSpan.deserialize(activeSpanSerialized, rootContext.getServiceName(), rootContext.getServiceVersion()); } previousTopOfStack = topOfStack; topOfStack = addFrame(stackTrace, stackTrace.size(), activeSpan, activationTimestamp, nanoTime, callTreePool, minDurationNs, this); diff --git a/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/SamplingProfiler.java b/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/SamplingProfiler.java index 46e4d9bc6c..6149c950f6 100644 --- a/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/SamplingProfiler.java +++ b/apm-agent-plugins/apm-profiling-plugin/src/main/java/co/elastic/apm/agent/profiler/SamplingProfiler.java @@ -770,6 +770,7 @@ private static class ActivationEvent { public static final int SERIALIZED_SIZE = Long.SIZE / Byte.SIZE + // timestamp Short.SIZE / Byte.SIZE + // serviceName index + Short.SIZE / Byte.SIZE + // serviceVersion index TraceContext.SERIALIZED_LENGTH + // traceContextBuffer TraceContext.SERIALIZED_LENGTH + // previousContextBuffer 1 + // rootContext @@ -779,9 +780,14 @@ private static class ActivationEvent { private static final Map serviceNameMap = new HashMap<>(); private static final Map serviceNameBackMap = new HashMap<>(); + private static final Map serviceVersionMap = new HashMap<>(); + private static final Map serviceVersionBackMap = new HashMap<>(); + private long timestamp; @Nullable private String serviceName; + @Nullable + private String serviceVersion; private byte[] traceContextBuffer = new byte[TraceContext.SERIALIZED_LENGTH]; private byte[] previousContextBuffer = new byte[TraceContext.SERIALIZED_LENGTH]; private boolean rootContext; @@ -801,6 +807,7 @@ private void set(TraceContext traceContext, long threadId, boolean activation, @ this.threadId = threadId; this.activation = activation; this.serviceName = traceContext.getServiceName(); + this.serviceVersion = traceContext.getServiceVersion(); if (previousContext != null) { previousContext.serialize(previousContextBuffer); rootContext = false; @@ -838,7 +845,7 @@ private void handleActivationEvent(SamplingProfiler samplingProfiler) { } private void startProfiling(SamplingProfiler samplingProfiler) { - CallTree.Root root = CallTree.createRoot(samplingProfiler.rootPool, traceContextBuffer, serviceName, timestamp); + CallTree.Root root = CallTree.createRoot(samplingProfiler.rootPool, traceContextBuffer, serviceName, serviceVersion, timestamp); if (logger.isDebugEnabled()) { logger.debug("Create call tree ({}) for thread {}", deserialize(samplingProfiler, traceContextBuffer), threadId); } @@ -853,7 +860,7 @@ private void startProfiling(SamplingProfiler samplingProfiler) { } private TraceContext deserialize(SamplingProfiler samplingProfiler, byte[] traceContextBuffer) { - samplingProfiler.contextForLogging.deserialize(traceContextBuffer, null); + samplingProfiler.contextForLogging.deserialize(traceContextBuffer, null, null); return samplingProfiler.contextForLogging; } @@ -899,6 +906,7 @@ private void stopProfiling(SamplingProfiler samplingProfiler) { public void serialize(ByteBuffer buf) { buf.putLong(timestamp); buf.putShort(getServiceNameIndex()); + buf.putShort(getServiceVersionIndex()); buf.put(traceContextBuffer); buf.put(previousContextBuffer); buf.put(rootContext ? (byte) 1 : (byte) 0); @@ -909,6 +917,7 @@ public void serialize(ByteBuffer buf) { public void deserialize(ByteBuffer buf) { timestamp = buf.getLong(); serviceName = serviceNameBackMap.get(buf.getShort()); + serviceVersion = serviceVersionBackMap.get(buf.getShort()); buf.get(traceContextBuffer); buf.get(previousContextBuffer); rootContext = buf.get() == 1; @@ -925,6 +934,16 @@ private short getServiceNameIndex() { } return index; } + + private short getServiceVersionIndex() { + Short index = serviceVersionMap.get(serviceVersion); + if (index == null) { + index = (short) serviceVersionMap.size(); + serviceVersionMap.put(serviceVersion, index); + serviceVersionBackMap.put(index, serviceVersion); + } + return index; + } } /** diff --git a/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeSpanifyTest.java b/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeSpanifyTest.java index b94bb48509..8a65306085 100644 --- a/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeSpanifyTest.java +++ b/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeSpanifyTest.java @@ -105,7 +105,7 @@ void testSpanification() throws Exception { @Test void testCallTreeWithActiveSpan() { TraceContext rootContext = CallTreeTest.rootTraceContext(tracer); - CallTree.Root root = CallTree.createRoot(NoopObjectPool.ofRecyclable(() -> new CallTree.Root(tracer)), rootContext.serialize(), rootContext.getServiceName(), 0); + CallTree.Root root = CallTree.createRoot(NoopObjectPool.ofRecyclable(() -> new CallTree.Root(tracer)), rootContext.serialize(), rootContext.getServiceName(), rootContext.getServiceVersion(),0); NoopObjectPool callTreePool = NoopObjectPool.ofRecyclable(CallTree::new); root.addStackTrace(tracer, List.of(StackFrame.of("A", "a")), 0, callTreePool, 0); diff --git a/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeTest.java b/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeTest.java index a8e38c4b65..30de09e4ec 100644 --- a/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeTest.java +++ b/apm-agent-plugins/apm-profiling-plugin/src/test/java/co/elastic/apm/agent/profiler/CallTreeTest.java @@ -86,7 +86,7 @@ void tearDown() throws IOException { @Test void testCallTree() { TraceContext traceContext = TraceContext.with64BitId(MockTracer.create()); - CallTree.Root root = CallTree.createRoot(NoopObjectPool.ofRecyclable(() -> new CallTree.Root(tracer)), traceContext.serialize(), traceContext.getServiceName(), 0); + CallTree.Root root = CallTree.createRoot(NoopObjectPool.ofRecyclable(() -> new CallTree.Root(tracer)), traceContext.serialize(), traceContext.getServiceName(), traceContext.getServiceVersion(), 0); ObjectPool callTreePool = ListBasedObjectPool.ofRecyclable(new ArrayList<>(), Integer.MAX_VALUE, CallTree::new); root.addStackTrace(tracer, List.of(StackFrame.of("A", "a")), 0, callTreePool, 0); root.addStackTrace(tracer, List.of(StackFrame.of("A", "b"), StackFrame.of("A", "a")), TimeUnit.MILLISECONDS.toNanos(10), callTreePool, 0); diff --git a/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java b/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java index 962f7581ae..60c6520c99 100644 --- a/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java +++ b/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java @@ -89,6 +89,7 @@ void setup() { @AfterEach final void cleanUp() { tracer.resetServiceNameOverrides(); + tracer.resetServiceVersionOverrides(); assertThat(tracer.getActive()).isNull(); } From af6c8e72ea3d0e258abdd90b0a83f1cac268ce86 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Tue, 30 Mar 2021 16:11:32 +0200 Subject: [PATCH 2/5] Added #1726 to changelog --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index d6a542716e..f8b61e4917 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -59,6 +59,7 @@ By default, the VM arguments are not printed, but only when the `-a`/`--list-vma ** Remove dependency on `jps` + Even when matching on the main class name or on system properties, ** Checks the Java version before attaching to avoid attachment on unsupported JVMs. +* Added support for overwritting the service version per classloader {pull}#1726[#1726] [float] ===== Bug fixes From 0a6e128d1b62852c507fb989f36ac9deb7bd6fae Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Tue, 19 Oct 2021 07:40:40 +0200 Subject: [PATCH 3/5] Fixed build --- .../co/elastic/apm/agent/configuration/CoreConfiguration.java | 4 ++++ .../main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index b1bf88a5fe..af6020f964 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -661,6 +661,10 @@ public String getServiceVersion() { return serviceVersion.get(); } + public ConfigurationOption getServiceVersionConfig() { + return serviceVersion; + } + @Nullable public String getHostname() { return hostname.get(); 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 790db77f1f..74a6c14c85 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 @@ -72,7 +72,7 @@ public class ElasticApmTracer implements Tracer { private static final WeakMap serviceNameByClassLoader = WeakConcurrent.buildMap(); - private static final WeakConcurrentMap serviceVersionByClassLoader = WeakMapSupplier.createMap(); + private static final WeakMap serviceVersionByClassLoader = WeakConcurrent.buildMap(); private final ConfigurationRegistry configurationRegistry; private final StacktraceConfiguration stacktraceConfiguration; From 1a903416ac9c2c71ca08da22c9bbbc3b867666fb Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Wed, 27 Oct 2021 08:22:23 +0200 Subject: [PATCH 4/5] Track breakdown metrics per service name and version --- .../agent/impl/transaction/Transaction.java | 5 +++- .../co/elastic/apm/agent/metrics/Labels.java | 29 ++++++++++++++++++- .../apm/agent/impl/SpanTypeBreakdownTest.java | 29 +++++++++++++++---- .../elastic/apm/agent/metrics/LabelsTest.java | 3 ++ .../serialize/MetricSetSerializationTest.java | 13 +++++++++ 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/Transaction.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/Transaction.java index 88b21f689f..7a8eff045c 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/Transaction.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/Transaction.java @@ -403,7 +403,10 @@ private void trackMetrics() { } final Labels.Mutable labels = labelsThreadLocal.get(); labels.resetState(); - labels.serviceName(getTraceContext().getServiceName()).transactionName(name).transactionType(type); + labels.serviceName(getTraceContext().getServiceName()) + .serviceVersion(getTraceContext().getServiceVersion()) + .transactionName(name) + .transactionType(type); final MetricRegistry metricRegistry = tracer.getMetricRegistry(); long criticalValueAtEnter = metricRegistry.writerCriticalSectionEnter(); try { diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java index bc7ebb1e1c..aeba09da07 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/metrics/Labels.java @@ -48,6 +48,9 @@ public interface Labels { @Nullable String getServiceName(); + @Nullable + String getServiceVersion(); + @Nullable CharSequence getTransactionName(); @@ -92,7 +95,7 @@ public List getValues() { } public boolean isEmpty() { - return keys.isEmpty() && getServiceName() == null && getTransactionName() == null && getTransactionType() == null && getSpanType() == null; + return keys.isEmpty() && getServiceName() == null && getServiceVersion() == null && getTransactionName() == null && getTransactionType() == null && getSpanType() == null; } public int size() { @@ -117,6 +120,7 @@ public boolean equals(Object o) { Objects.equals(getTransactionType(), labels.getTransactionType()) && contentEquals(getTransactionName(), labels.getTransactionName()) && Objects.equals(getServiceName(), labels.getServiceName()) && + Objects.equals(getServiceVersion(), labels.getServiceVersion()) && keys.equals(labels.keys) && isEqual(values, labels.values); } @@ -128,6 +132,7 @@ public int hashCode() { h = 31 * h + hashEntryAt(i); } h = 31 * h + hash(getServiceName()); + h = 31 * h + hash(getServiceVersion()); h = 31 * h + hash(getTransactionName()); h = 31 * h + (getTransactionType() != null ? getTransactionType().hashCode() : 0); h = 31 * h + (getSpanType() != null ? getSpanType().hashCode() : 0); @@ -205,6 +210,8 @@ class Mutable extends AbstractBase implements Recyclable { @Nullable private String serviceName; @Nullable + private String serviceVersion; + @Nullable private CharSequence transactionName; @Nullable private String transactionType; @@ -246,6 +253,11 @@ public Labels.Mutable serviceName(@Nullable String serviceName) { return this; } + public Labels.Mutable serviceVersion(@Nullable String serviceVersion) { + this.serviceVersion = serviceVersion; + return this; + } + public Labels.Mutable transactionName(@Nullable CharSequence transactionName) { this.transactionName = transactionName; return this; @@ -271,6 +283,11 @@ public String getServiceName() { return serviceName; } + @Nullable + public String getServiceVersion() { + return serviceVersion; + } + @Nullable public CharSequence getTransactionName() { return transactionName; @@ -301,6 +318,7 @@ public void resetState() { keys.clear(); values.clear(); serviceName = null; + serviceVersion = null; transactionName = null; transactionType = null; spanType = null; @@ -323,6 +341,8 @@ class Immutable extends AbstractBase { @Nullable private final String serviceName; @Nullable + private final String serviceVersion; + @Nullable private final String transactionName; @Nullable private final String transactionType; @@ -334,6 +354,7 @@ class Immutable extends AbstractBase { public Immutable(Labels labels) { super(new ArrayList<>(labels.getKeys()), copy(labels.getValues())); this.serviceName = labels.getServiceName(); + this.serviceVersion = labels.getServiceVersion(); final CharSequence transactionName = labels.getTransactionName(); this.transactionName = transactionName != null ? transactionName.toString() : null; this.transactionType = labels.getTransactionType(); @@ -365,6 +386,12 @@ public String getServiceName() { return serviceName; } + @Nullable + @Override + public String getServiceVersion() { + return serviceVersion; + } + @Nullable @Override public String getTransactionName() { 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 3fdcda01f4..d6eabb05d8 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 @@ -353,10 +353,26 @@ void testBreakdown_serviceName() { transaction.end(27); tracer.getMetricRegistry().flipPhaseAndReport(metricSets -> { - assertThat(getTimer(metricSets, "span.self_time", "service_name", "app", null).getCount()).isEqualTo(1); - assertThat(getTimer(metricSets, "span.self_time", "service_name", "app", null).getTotalTimeUs()).isEqualTo(15); - assertThat(getTimer(metricSets, "span.self_time", "service_name", "db", "mysql").getCount()).isEqualTo(1); - assertThat(getTimer(metricSets, "span.self_time", "service_name", "db", "mysql").getTotalTimeUs()).isEqualTo(12); + assertThat(getTimer(metricSets, "span.self_time", "service_name", null, "app", null).getCount()).isEqualTo(1); + assertThat(getTimer(metricSets, "span.self_time", "service_name", null, "app", null).getTotalTimeUs()).isEqualTo(15); + assertThat(getTimer(metricSets, "span.self_time", "service_name", null, "db", "mysql").getCount()).isEqualTo(1); + assertThat(getTimer(metricSets, "span.self_time", "service_name", null, "db", "mysql").getTotalTimeUs()).isEqualTo(12); + }); + } + + @Test + void testBreakdown_serviceNameAndVersion() { + final Transaction transaction = createTransaction(); + transaction.getTraceContext().setServiceName("service_name"); + transaction.getTraceContext().setServiceVersion("service_version"); + transaction.createSpan(11).withType("db").withSubtype("mysql").end(23); + transaction.end(27); + + tracer.getMetricRegistry().flipPhaseAndReport(metricSets -> { + assertThat(getTimer(metricSets, "span.self_time", "service_name", "service_version", "app", null).getCount()).isEqualTo(1); + assertThat(getTimer(metricSets, "span.self_time", "service_name", "service_version", "app", null).getTotalTimeUs()).isEqualTo(15); + assertThat(getTimer(metricSets, "span.self_time", "service_name", "service_version", "db", "mysql").getCount()).isEqualTo(1); + assertThat(getTimer(metricSets, "span.self_time", "service_name", "service_version", "db", "mysql").getTotalTimeUs()).isEqualTo(12); }); } @@ -368,13 +384,14 @@ private Transaction createTransaction() { @Nullable private Timer getTimer(Map metricSets, String timerName, @Nullable String spanType, @Nullable String spanSubType) { - return getTimer(metricSets, timerName, null, spanType, spanSubType); + return getTimer(metricSets, timerName, null, null, spanType, spanSubType); } @Nullable - private Timer getTimer(Map metricSets, String timerName, @Nullable String serviceName, @Nullable String spanType, @Nullable String spanSubType) { + private Timer getTimer(Map metricSets, String timerName, @Nullable String serviceName, @Nullable String serviceVersion, @Nullable String spanType, @Nullable String spanSubType) { final MetricSet metricSet = metricSets.get(Labels.Mutable.of() .serviceName(serviceName) + .serviceVersion(serviceVersion) .transactionName("test") .transactionType("request") .spanType(spanType) diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java index 116219e093..e1f2d90b08 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/metrics/LabelsTest.java @@ -38,6 +38,9 @@ void testEqualsHashCode() { assertEqualsHashCode( Labels.Mutable.of().serviceName("foo"), Labels.Mutable.of().serviceName("foo")); + assertEqualsHashCode( + Labels.Mutable.of().serviceVersion("foo"), + Labels.Mutable.of().serviceVersion("foo")); assertEqualsHashCode( Labels.Mutable.of().transactionName("foo"), Labels.Mutable.of().transactionName(new StringBuilder("foo"))); diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java index 9b95c0e288..a43e1361a0 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java @@ -185,6 +185,19 @@ void testServiceName() throws Exception { assertThat(serviceName.asText()).isEqualTo("bar"); } + @Test + void testServiceNameAndVersion() throws Exception { + registry.updateTimer("foo", Labels.Mutable.of().serviceName("bar").serviceVersion("1.0"), 1); + + JsonNode jsonNode = reportAsJson(); + assertThat(jsonNode).isNotNull(); + JsonNode service = jsonNode.get("metricset").get("service"); + JsonNode serviceName = service.get("name"); + JsonNode serviceVersion = service.get("version"); + assertThat(serviceName.asText()).isEqualTo("bar"); + assertThat(serviceVersion.asText()).isEqualTo("1.0"); + } + @Nullable private JsonNode reportAsJson() throws Exception { final CompletableFuture jwFuture = new CompletableFuture<>(); From c8f8478e0b42d24ac30774057f80b4fc6c8f145c Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Mon, 8 Nov 2021 15:03:17 +0100 Subject: [PATCH 5/5] Added overwritten service version to metricset serialization and improved code --- .../configuration/CoreConfiguration.java | 4 - .../apm/agent/impl/ElasticApmTracer.java | 82 +++++++------------ .../elastic/apm/agent/impl/GlobalTracer.java | 4 +- .../co/elastic/apm/agent/impl/NoopTracer.java | 2 +- .../co/elastic/apm/agent/impl/Tracer.java | 5 +- .../report/serialize/DslJsonSerializer.java | 9 +- .../serialize/MetricRegistryReporter.java | 5 +- .../serialize/MetricRegistrySerializer.java | 23 +++--- .../apm/agent/util/ServiceNameAndVersion.java | 37 +++++++++ .../agent/AbstractInstrumentationTest.java | 3 +- .../apm/agent/impl/ElasticApmTracerTest.java | 12 +-- .../serialize/MetricSetSerializationTest.java | 22 +++-- .../api/ElasticApmApiInstrumentationTest.java | 10 ++- ...tractViewRenderingInstrumentationTest.java | 3 +- 14 files changed, 124 insertions(+), 97 deletions(-) create mode 100644 apm-agent-core/src/main/java/co/elastic/apm/agent/util/ServiceNameAndVersion.java diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java index 6063f092bc..60a596d802 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/configuration/CoreConfiguration.java @@ -664,10 +664,6 @@ public String getServiceVersion() { return serviceVersion.get(); } - public ConfigurationOption getServiceVersionConfig() { - return serviceVersion; - } - @Nullable public String getHostname() { return hostname.get(); 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 1cf8164794..f0c2018a95 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 @@ -45,6 +45,7 @@ import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; import co.elastic.apm.agent.util.DependencyInjectingServiceLoader; import co.elastic.apm.agent.util.ExecutorUtils; +import co.elastic.apm.agent.util.ServiceNameAndVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.stagemonitor.configuration.ConfigurationOption; @@ -56,7 +57,6 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -74,9 +74,7 @@ public class ElasticApmTracer implements Tracer { private static final Logger logger = LoggerFactory.getLogger(ElasticApmTracer.class); - private static final WeakMap serviceNameByClassLoader = WeakConcurrent.buildMap(); - - private static final WeakMap serviceVersionByClassLoader = WeakConcurrent.buildMap(); + private static final WeakMap serviceNameAndVersionByClassLoader = WeakConcurrent.buildMap(); private final ConfigurationRegistry configurationRegistry; private final StacktraceConfiguration stacktraceConfiguration; @@ -234,13 +232,10 @@ private void afterTransactionStart(@Nullable ClassLoader initiatingClassLoader, new RuntimeException("this exception is just used to record where the transaction has been started from")); } } - final String serviceName = getServiceName(initiatingClassLoader); - if (serviceName != null) { - transaction.getTraceContext().setServiceName(serviceName); - } - final String serviceVersion = getServiceVersion(initiatingClassLoader); - if (serviceVersion != null) { - transaction.getTraceContext().setServiceVersion(serviceVersion); + final ServiceNameAndVersion serviceNameAndVersion = getServiceNameAndVersion(initiatingClassLoader); + if (serviceNameAndVersion != null) { + transaction.getTraceContext().setServiceName(serviceNameAndVersion.getServiceName()); + transaction.getTraceContext().setServiceVersion(serviceNameAndVersion.getServiceVersion()); } } @@ -350,8 +345,11 @@ private ErrorCapture captureException(long epochMicros, @Nullable Throwable e, @ parent.setNonDiscardable(); } else { error.getTraceContext().getId().setToRandomValue(); - error.getTraceContext().setServiceName(getServiceName(initiatingClassLoader)); - error.getTraceContext().setServiceVersion(getServiceVersion(initiatingClassLoader)); + ServiceNameAndVersion serviceNameAndVersion = getServiceNameAndVersion(initiatingClassLoader); + if (serviceNameAndVersion != null) { + error.getTraceContext().setServiceName(serviceNameAndVersion.getServiceName()); + error.getTraceContext().setServiceVersion(serviceNameAndVersion.getServiceVersion()); + } } return error; } @@ -741,17 +739,22 @@ public MetricRegistry getMetricRegistry() { return metricRegistry; } - public List getServiceNameOverrides() { - List serviceNames = new ArrayList<>(serviceNameByClassLoader.approximateSize()); - for (Map.Entry entry : serviceNameByClassLoader) { - serviceNames.add(entry.getValue()); + public List getServiceNamesAndVersionsOverrides() { + List serviceNamesAndVersions = new ArrayList<>(serviceNameAndVersionByClassLoader.approximateSize()); + for (Map.Entry entry : serviceNameAndVersionByClassLoader) { + serviceNamesAndVersions.add(entry.getValue()); } - return serviceNames; + return serviceNamesAndVersions; } @Override public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName) { - // overriding the service name for the bootstrap class loader is not an actual use-case + overrideServiceNameAndVersionForClassLoader(classLoader, serviceName, null); + } + + @Override + public void overrideServiceNameAndVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName, @Nullable String serviceVersion) { + // 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 || serviceName == null || serviceName.isEmpty() @@ -761,49 +764,22 @@ public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, } String sanitizedServiceName = ServiceNameUtil.replaceDisallowedChars(serviceName); - logger.debug("Using `{}` as the service name for class loader [{}]", sanitizedServiceName, classLoader); - if (!serviceNameByClassLoader.containsKey(classLoader)) { - serviceNameByClassLoader.putIfAbsent(classLoader, sanitizedServiceName); - } - } - - @Nullable - private String getServiceName(@Nullable ClassLoader initiatingClassLoader) { - if (initiatingClassLoader == null) { - return null; - } - return serviceNameByClassLoader.get(initiatingClassLoader); - } - - public void resetServiceNameOverrides() { - serviceNameByClassLoader.clear(); - } - - @Override - public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { - // overriding the service 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 - || serviceVersion == null || serviceVersion.isEmpty() - // if the service version is set explicitly, don't override it - || coreConfiguration.getServiceVersionConfig().getUsedKey() != null) { - return; - } - if (!serviceVersionByClassLoader.containsKey(classLoader)) { - serviceVersionByClassLoader.putIfAbsent(classLoader, serviceVersion); + logger.debug("Using `{}` as the service name and {} as the service version for class loader [{}]", sanitizedServiceName, serviceVersion, classLoader); + if (!serviceNameAndVersionByClassLoader.containsKey(classLoader)) { + serviceNameAndVersionByClassLoader.putIfAbsent(classLoader, new ServiceNameAndVersion(serviceName, serviceVersion)); } } @Nullable - private String getServiceVersion(@Nullable ClassLoader initiatingClassLoader) { + private ServiceNameAndVersion getServiceNameAndVersion(@Nullable ClassLoader initiatingClassLoader) { if (initiatingClassLoader == null) { return null; } - return serviceVersionByClassLoader.get(initiatingClassLoader); + return serviceNameAndVersionByClassLoader.get(initiatingClassLoader); } - public void resetServiceVersionOverrides() { - serviceVersionByClassLoader.clear(); + public void resetServiceNamesAndVersionOverrides() { + serviceNameAndVersionByClassLoader.clear(); } public ApmServerClient getApmServerClient() { diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java index 6db15c6019..3fd6c5a8b7 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/GlobalTracer.java @@ -209,8 +209,8 @@ public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, } @Override - public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { - tracer.overrideServiceVersionForClassLoader(classLoader, serviceVersion); + public void overrideServiceNameAndVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName, @Nullable String serviceVersion) { + tracer.overrideServiceNameAndVersionForClassLoader(classLoader, serviceName, serviceVersion); } @Override diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java index 44e7ee5e42..43b7eedeff 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/NoopTracer.java @@ -134,7 +134,7 @@ public void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, } @Override - public void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion) { + public void overrideServiceNameAndVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName, @Nullable String serviceVersion) { } @Override diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java index 14f7049be5..6c7edf3076 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/Tracer.java @@ -165,16 +165,17 @@ Transaction startChildTransaction(@Nullable C headerCarrier, BinaryHeaderGet void overrideServiceNameForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName); /** - * Overrides the service version for all {@link Transaction}s, + * Overrides 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. *

* * @param classLoader the class loader which corresponds to a particular service + * @param serviceName the service name for this class loader * @param serviceVersion the service version for this class loader */ - void overrideServiceVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceVersion); + void overrideServiceNameAndVersionForClassLoader(@Nullable ClassLoader classLoader, @Nullable String serviceName, @Nullable String serviceVersion); /** * Called when the container shuts down. 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 814f528f7a..a18d15fd52 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 @@ -77,7 +77,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static co.elastic.apm.agent.util.ObjectUtils.defaultIfNull; import static com.dslplatform.json.JsonWriter.ARRAY_END; import static com.dslplatform.json.JsonWriter.ARRAY_START; import static com.dslplatform.json.JsonWriter.COMMA; @@ -1059,8 +1058,12 @@ private static void serializeStringKeyScalarValueMap(Iterator metricSets) { if (tracer.isRunning()) { - List serviceNames = tracer.getServiceNameOverrides(); + List serviceNamesAndVersions = tracer.getServiceNamesAndVersionsOverrides(); for (MetricSet metricSet : metricSets.values()) { - JsonWriter jw = serializer.serialize(metricSet, serviceNames); + JsonWriter jw = serializer.serialize(metricSet, serviceNamesAndVersions); if (jw != null) { reporter.report(jw); } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/MetricRegistrySerializer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/MetricRegistrySerializer.java index e33650b51f..11c889fdba 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/MetricRegistrySerializer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/report/serialize/MetricRegistrySerializer.java @@ -21,6 +21,7 @@ import co.elastic.apm.agent.metrics.DoubleSupplier; import co.elastic.apm.agent.metrics.MetricSet; import co.elastic.apm.agent.metrics.Timer; +import co.elastic.apm.agent.util.ServiceNameAndVersion; import com.dslplatform.json.DslJson; import com.dslplatform.json.JsonWriter; import com.dslplatform.json.NumberConverter; @@ -48,16 +49,18 @@ public class MetricRegistrySerializer { * @return the serialized metric-set or {@code null} if no samples were serialized */ @Nullable - public JsonWriter serialize(MetricSet metricSet, List serviceNames) { + public JsonWriter serialize(MetricSet metricSet, List serviceNamesAndVersions) { JsonWriter jw = dslJson.newWriter(maxSerializedSize); boolean hasSamples = false; - if (serviceNames.isEmpty() || metricSet.getLabels().getServiceName() != null) { - hasSamples = serialize(metricSet, null, jw); + if (serviceNamesAndVersions.isEmpty() || metricSet.getLabels().getServiceName() != null) { + hasSamples = serialize(metricSet, null, null, jw); } else { - hasSamples = serialize(metricSet, serviceNames.get(0), jw); + ServiceNameAndVersion serviceNameAndVersion = serviceNamesAndVersions.get(0); + hasSamples = serialize(metricSet, serviceNameAndVersion.getServiceName(), serviceNameAndVersion.getServiceVersion(), jw); if (hasSamples) { - for (int i = 1; i < serviceNames.size(); ++i) { - serialize(metricSet, serviceNames.get(i), jw); + for (int i = 1; i < serviceNamesAndVersions.size(); ++i) { + serviceNameAndVersion = serviceNamesAndVersions.get(i); + serialize(metricSet, serviceNameAndVersion.getServiceName(), serviceNameAndVersion.getServiceVersion(), jw); } } } @@ -68,12 +71,12 @@ public JsonWriter serialize(MetricSet metricSet, List serviceNames) { return null; } - private boolean serialize(MetricSet metricSet, String serviceName, JsonWriter jw) { + private boolean serialize(MetricSet metricSet, String serviceName, String serviceVersion, JsonWriter jw) { final long timestamp = System.currentTimeMillis() * 1000; - return serialize(metricSet, timestamp, serviceName, replaceBuilder, jw); + return serialize(metricSet, timestamp, serviceName, serviceVersion, replaceBuilder, jw); } - private static boolean serialize(MetricSet metricSet, long epochMicros, String serviceName, StringBuilder replaceBuilder, JsonWriter jw) { + private static boolean serialize(MetricSet metricSet, long epochMicros, String serviceName, String serviceVersion, StringBuilder replaceBuilder, JsonWriter jw) { boolean hasSamples; jw.writeByte(JsonWriter.OBJECT_START); { @@ -83,7 +86,7 @@ private static boolean serialize(MetricSet metricSet, long epochMicros, String s DslJsonSerializer.writeFieldName("timestamp", jw); NumberConverter.serialize(epochMicros, jw); jw.writeByte(JsonWriter.COMMA); - DslJsonSerializer.serializeLabels(metricSet.getLabels(), serviceName, replaceBuilder, jw); + DslJsonSerializer.serializeLabels(metricSet.getLabels(), serviceName, serviceVersion, replaceBuilder, jw); DslJsonSerializer.writeFieldName("samples", jw); jw.writeByte(JsonWriter.OBJECT_START); hasSamples = serializeGauges(metricSet.getGauges(), jw); diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/util/ServiceNameAndVersion.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/ServiceNameAndVersion.java new file mode 100644 index 0000000000..9d0ebf973c --- /dev/null +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/util/ServiceNameAndVersion.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package co.elastic.apm.agent.util; + +public final class ServiceNameAndVersion { + private final String serviceName; + private final String serviceVersion; + + public ServiceNameAndVersion(String serviceName, String serviceVersion) { + this.serviceName = serviceName; + this.serviceVersion = serviceVersion; + } + + public String getServiceName() { + return serviceName; + } + + public String getServiceVersion() { + return serviceVersion; + } +} diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java index 6a800c546c..286fd12926 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/AbstractInstrumentationTest.java @@ -118,8 +118,7 @@ public final void cleanUp() { TracerInternalApiUtils.resumeTracer(tracer); } } - tracer.resetServiceNameOverrides(); - tracer.resetServiceVersionOverrides(); + tracer.resetServiceNamesAndVersionOverrides(); // reset reporter to default behaviour on all checks reporter.resetChecks(); 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 4779ca4aba..7de314609e 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 @@ -72,7 +72,7 @@ void setUp() { void cleanupAndCheck() { reporter.assertRecycledAfterDecrementingReferences(); objectPoolFactory.checkAllPooledObjectsHaveBeenRecycled(); - tracerImpl.resetServiceNameOverrides(); + tracerImpl.resetServiceNamesAndVersionOverrides(); } @Test @@ -480,11 +480,12 @@ void testOverrideServiceVersionWithoutExplicitServiceVersion() { final ElasticApmTracer tracer = new ElasticApmTracerBuilder() .reporter(reporter) .buildAndStart(); - tracer.overrideServiceVersionForClassLoader(getClass().getClassLoader(), "overridden"); + tracer.overrideServiceNameAndVersionForClassLoader(getClass().getClassLoader(), "overridden_name", "overridden_version"); startTestRootTransaction().end(); - assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("overridden_name"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden_version"); } @Test @@ -494,11 +495,12 @@ void testNotOverrideServiceVersionWhenServiceVersionConfigured() { .reporter(reporter) .configurationRegistry(localConfig) .buildAndStart(); - tracer.overrideServiceVersionForClassLoader(getClass().getClassLoader(), "overridden"); + tracer.overrideServiceNameAndVersionForClassLoader(getClass().getClassLoader(), "overridden_name", "overridden_version"); startTestRootTransaction().end(); - assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isNull(); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("overridden_name"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden_version"); } @Test diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java index 68575f6db8..6b17a66fb0 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/report/serialize/MetricSetSerializationTest.java @@ -21,6 +21,7 @@ import co.elastic.apm.agent.metrics.Labels; import co.elastic.apm.agent.metrics.MetricRegistry; import co.elastic.apm.agent.report.ReporterConfiguration; +import co.elastic.apm.agent.util.ServiceNameAndVersion; import com.dslplatform.json.JsonWriter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -205,10 +206,12 @@ void testServiceNameAndVersion() throws Exception { void testServiceNameOverrideWithOneService() throws Exception { registry.updateTimer("foo", Labels.Mutable.of(), 1); - JsonNode jsonNode = reportAsJson(singletonList("bar")); + JsonNode jsonNode = reportAsJson(singletonList(new ServiceNameAndVersion("bar", "1.0"))); assertThat(jsonNode).isNotNull(); JsonNode serviceName = jsonNode.get("metricset").get("service").get("name"); assertThat(serviceName.asText()).isEqualTo("bar"); + JsonNode serviceVersion = jsonNode.get("metricset").get("service").get("version"); + assertThat(serviceVersion.asText()).isEqualTo("1.0"); } @Test @@ -217,22 +220,27 @@ void testServiceNameOverrideWithMultipleService() throws Exception { final CompletableFuture jwFuture = new CompletableFuture<>(); registry.flipPhaseAndReport( - metricSets -> jwFuture.complete(metricRegistrySerializer.serialize(metricSets.values().iterator().next(), List.of("bar1", "bar2"))) + metricSets -> jwFuture.complete(metricRegistrySerializer.serialize( + metricSets.values().iterator().next(), + List.of(new ServiceNameAndVersion("bar1", "2.0"), new ServiceNameAndVersion("bar2", null)) + )) ); String[] jsonStrings = jwFuture.getNow(null).toString().split("\n"); assertThat(jsonStrings.length).isEqualTo(2); JsonNode jsonNode1 = objectMapper.readTree(jsonStrings[0]); - String serviceName1 = jsonNode1.get("metricset").get("service").get("name").asText(); - assertThat(serviceName1).isEqualTo("bar1"); + JsonNode service1 = jsonNode1.get("metricset").get("service"); + assertThat(service1.get("name").asText()).isEqualTo("bar1"); + assertThat(service1.get("version").asText()).isEqualTo("2.0"); JsonNode samples1 = jsonNode1.get("metricset").get("samples"); assertThat(samples1.get("foo.sum.us").get("value").intValue()).isOne(); assertThat(samples1.get("foo.count").get("value").intValue()).isOne(); JsonNode jsonNode2 = objectMapper.readTree(jsonStrings[1]); - String serviceName2 = jsonNode2.get("metricset").get("service").get("name").asText(); - assertThat(serviceName2).isEqualTo("bar2"); + JsonNode service2 = jsonNode2.get("metricset").get("service"); + assertThat(service2.get("name").asText()).isEqualTo("bar2"); + assertThat(service2.get("version")).isNull(); JsonNode samples2 = jsonNode2.get("metricset").get("samples"); assertThat(samples2.get("foo.sum.us").get("value").intValue()).isOne(); assertThat(samples2.get("foo.count").get("value").intValue()).isOne(); @@ -244,7 +252,7 @@ private JsonNode reportAsJson() throws Exception { } @Nullable - private JsonNode reportAsJson(List serviceNames) throws Exception { + private JsonNode reportAsJson(List serviceNames) throws Exception { final CompletableFuture jwFuture = new CompletableFuture<>(); registry.flipPhaseAndReport( metricSets -> jwFuture.complete(metricRegistrySerializer.serialize(metricSets.values().iterator().next(), serviceNames)) 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 522fbfe7c0..a0429c755e 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 @@ -341,16 +341,18 @@ void testOverrideServiceNameForClassLoaderWithRemoteParent() { @Test void testOverrideServiceVersionForClassLoader() { - tracer.overrideServiceVersionForClassLoader(Transaction.class.getClassLoader(), "overridden"); + tracer.overrideServiceNameAndVersionForClassLoader(Transaction.class.getClassLoader(), "overridden_name", "overridden_version"); ElasticApm.startTransaction().end(); - assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("overridden_name"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden_version"); } @Test void testOverrideServiceVersionForClassLoaderWithRemoteParent() { - tracer.overrideServiceVersionForClassLoader(Transaction.class.getClassLoader(), "overridden"); + tracer.overrideServiceNameAndVersionForClassLoader(Transaction.class.getClassLoader(), "overridden_name", "overridden_version"); ElasticApm.startTransactionWithRemoteParent(key -> null).end(); - assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceName()).isEqualTo("overridden_name"); + assertThat(reporter.getFirstTransaction().getTraceContext().getServiceVersion()).isEqualTo("overridden_version"); } @Test diff --git a/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java b/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java index 786f8ef5a1..46aa705354 100644 --- a/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java +++ b/apm-agent-plugins/apm-spring-webmvc-plugin/src/test/java/co/elastic/apm/agent/springwebmvc/template/AbstractViewRenderingInstrumentationTest.java @@ -82,8 +82,7 @@ void setup() { @AfterEach final void cleanUp() { - tracer.resetServiceNameOverrides(); - tracer.resetServiceVersionOverrides(); + tracer.resetServiceNamesAndVersionOverrides(); assertThat(tracer.getActive()).isNull(); }