From 61bbb70e2345fa29b2025f36fbe4f87eb83667b0 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Tue, 15 Apr 2025 15:55:00 +0200 Subject: [PATCH 1/7] Collect process tags for tracing --- ...veImageGeneratorRunnerInstrumentation.java | 1 + .../SpringApplicationInstrumentation.java | 13 ++ .../groovy/SpringBootApplicationTest.groovy | 15 ++- .../trace/agent/test/AgentTestRunner.groovy | 2 + .../datadog/trace/api/ConfigDefaults.java | 3 +- .../main/java/datadog/trace/api/DDTags.java | 1 + .../trace/api/config/GeneralConfig.java | 3 + .../core/tagprocessor/ProcessTagsAdder.java | 21 +++ .../TagsPostProcessorFactory.java | 6 +- .../tagprocessor/ProcessTagsAdderTest.groovy | 27 ++++ .../main/java/datadog/trace/api/Config.java | 7 + .../java/datadog/trace/api/ProcessTags.java | 120 ++++++++++++++++++ .../trace/api/env/CapturedEnvironment.java | 83 ++++++++---- .../trace/api/ProcessTagsForkedTest.groovy | 61 +++++++++ .../trace/test/util/DDSpecification.groovy | 8 +- 15 files changed, 339 insertions(+), 32 deletions(-) create mode 100644 dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java create mode 100644 dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy create mode 100644 internal-api/src/main/java/datadog/trace/api/ProcessTags.java create mode 100644 internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 1dc8679b989..3ebe7f59da4 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -76,6 +76,7 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.Platform:rerun," + "datadog.trace.api.Platform$Captured:build_time," + "datadog.trace.api.env.CapturedEnvironment:build_time," + + "datadog.trace.api.env.CapturedEnvironment$ProcessInfo:build_time," + "datadog.trace.api.ConfigCollector:rerun," + "datadog.trace.api.ConfigDefaults:build_time," + "datadog.trace.api.ConfigOrigin:build_time," diff --git a/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java b/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java index dfddac80de1..7c6eefc6881 100644 --- a/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java @@ -7,7 +7,9 @@ import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.api.Config; +import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import java.util.Arrays; import net.bytebuddy.asm.Advice; import org.springframework.core.env.ConfigurableEnvironment; @@ -60,6 +62,17 @@ public static void afterEnvironmentPostProcessed( final String applicationName = environment.getProperty("spring.application.name"); if (applicationName != null && !applicationName.isEmpty()) { AgentTracer.get().updatePreferredServiceName(applicationName); + ProcessTags.addTag("springboot.application", applicationName); + } + final String[] profiles = environment.getActiveProfiles(); + System.err.println(Arrays.toString(profiles)); + if (profiles != null && profiles.length > 0) { + ProcessTags.addTag("springboot.profile", profiles[0]); + } else { + final String[] defaultProfiles = environment.getDefaultProfiles(); + if (defaultProfiles != null && defaultProfiles.length > 0) { + ProcessTags.addTag("springboot.profile", defaultProfiles[0]); + } } } } diff --git a/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy b/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy index 31a17c0b048..a98bd1d32fa 100644 --- a/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy +++ b/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy @@ -1,3 +1,5 @@ +import datadog.trace.api.ProcessTags + import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace import datadog.trace.agent.test.AgentTestRunner @@ -10,6 +12,7 @@ class SpringBootApplicationTest extends AgentTestRunner { protected void configurePreAgent() { super.configurePreAgent() } + static class BeanWhoTraces implements InitializingBean { @Override @@ -32,15 +35,19 @@ class SpringBootApplicationTest extends AgentTestRunner { } } }) + and: + def processTags = ProcessTags.getTagsForSerialization() + assert processTags.toString() =~ ".+,springboot.application:$expectedService,springboot.profile:$expectedProfile" context != null cleanup: context?.stop() where: - expectedService | args - "application-name-from-args" | new String[]{ - "--spring.application.name=application-name-from-args" + expectedService | expectedProfile | args + "application-name-from-args" | "prod" | new String[]{ + "--spring.application.name=application-name-from-args", + "--spring.profiles.active=prod,common", } - "application-name-from-properties" | new String[0] // will load from properties + "application-name-from-properties" | "default" | new String[0] // will load from properties } } diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy index 029024f2a35..547431d7ace 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/AgentTestRunner.groovy @@ -27,6 +27,7 @@ import datadog.trace.agent.tooling.bytebuddy.matcher.GlobalIgnores import datadog.trace.api.Config import datadog.trace.api.DDSpanId import datadog.trace.api.IdGenerationStrategy +import datadog.trace.api.ProcessTags import datadog.trace.api.StatsDClient import datadog.trace.api.TraceConfig import datadog.trace.api.WellKnownTags @@ -509,6 +510,7 @@ abstract class AgentTestRunner extends DDSpecification implements AgentBuilder.L ActiveSubsystems.APPSEC_ACTIVE = true } InstrumentationErrors.resetErrorCount() + ProcessTags.reset() } @Override diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 37931a666f5..4e42869ec8f 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -241,7 +241,8 @@ public final class ConfigDefaults { static final int DEFAULT_TELEMETRY_DEPENDENCY_RESOLUTION_QUEUE_SIZE = 100000; static final Set DEFAULT_TRACE_EXPERIMENTAL_FEATURES_ENABLED = - new HashSet<>(asList("DD_TAGS", "DD_LOGS_INJECTION")); + new HashSet<>( + asList("DD_TAGS", "DD_LOGS_INJECTION", "EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED")); static final boolean DEFAULT_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = true; static final boolean DEFAULT_TRACE_128_BIT_TRACEID_LOGGING_ENABLED = true; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java index 7d165a33b59..d8ed8ddd776 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java @@ -98,4 +98,5 @@ public class DDTags { public static final String DECISION_MAKER_INHERITED = "_dd.dm.inherited"; public static final String DECISION_MAKER_SERVICE = "_dd.dm.service"; public static final String DECISION_MAKER_RESOURCE = "_dd.dm.resource"; + public static final String PROCESS_TAGS = "_dd.process"; } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java index e49baba90e0..adf23013d9b 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java @@ -29,6 +29,9 @@ public final class GeneralConfig { @Deprecated // Use dd.tags instead public static final String GLOBAL_TAGS = "trace.global.tags"; + public static final String EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED = + "experimental.collect.tags.enabled"; + public static final String LOG_LEVEL = "log.level"; public static final String TRACE_DEBUG = "trace.debug"; public static final String TRACE_TRIAGE = "trace.triage"; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java new file mode 100644 index 00000000000..aa10555a64a --- /dev/null +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java @@ -0,0 +1,21 @@ +package datadog.trace.core.tagprocessor; + +import static datadog.trace.api.DDTags.PROCESS_TAGS; + +import datadog.trace.api.ProcessTags; +import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.core.DDSpanContext; +import java.util.List; +import java.util.Map; + +public class ProcessTagsAdder implements TagsPostProcessor { + @Override + public Map processTags( + Map unsafeTags, DDSpanContext spanContext, List spanLinks) { + final CharSequence processTags = ProcessTags.getTagsForSerialization(); + if (processTags != null) { + unsafeTags.put(PROCESS_TAGS, processTags); + } + return unsafeTags; + } +} diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java index 154d7f54153..dc80379e5b8 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java @@ -10,7 +10,7 @@ public final class TagsPostProcessorFactory { private static class Lazy { private static TagsPostProcessor create() { - final List processors = new ArrayList<>(4); + final List processors = new ArrayList<>(7); processors.add(new PeerServiceCalculator()); if (addBaseService) { processors.add(new BaseServiceAdder(Config.get().getServiceName())); @@ -32,6 +32,9 @@ private static TagsPostProcessor create() { if (Config.get().isAddSpanPointers("aws")) { processors.add(new SpanPointersProcessor()); } + if (Config.get().isExperimentalCollectProcessTagsEnabled()) { + processors.add(new ProcessTagsAdder()); + } return new PostProcessorChain( processors.toArray(processors.toArray(new TagsPostProcessor[0]))); } @@ -52,6 +55,7 @@ public static void withAddBaseService(boolean enabled) { addBaseService = enabled; Lazy.instance = Lazy.create(); } + /** * Mostly used for test purposes. * diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy new file mode 100644 index 00000000000..cee4e14affc --- /dev/null +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy @@ -0,0 +1,27 @@ +package datadog.trace.core.tagprocessor + +import datadog.trace.api.ProcessTags +import datadog.trace.core.DDSpanContext +import datadog.trace.test.util.DDSpecification + +class ProcessTagsAdderTest extends DDSpecification { + def "should add _dd.process"() { + setup: + def adder = new ProcessTagsAdder() + def spanContext = Mock(DDSpanContext) + + when: + def enrichedTags = adder.processTags([:], spanContext, []) + + then: + def firstValue = enrichedTags.get("_dd.process") + assert !firstValue.toString().isEmpty() + + when: + ProcessTags.addTag("test", "value") + enrichedTags = adder.processTags([:], spanContext, []) + + then: + assert enrichedTags.get("_dd.process").toString() == "$firstValue,test:value" + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 0a6f84057b4..bf049d0543a 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -150,6 +150,7 @@ public static String getHostName() { private final boolean peerServiceDefaultsEnabled; private final Map peerServiceComponentOverrides; private final boolean removeIntegrationServiceNamesEnabled; + private final boolean experimentalCollectProcessTagsEnabled; private final Map peerServiceMapping; private final Map serviceMapping; private final Map tags; @@ -846,6 +847,8 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins // feature flag to remove fake services in v0 removeIntegrationServiceNamesEnabled = configProvider.getBoolean(TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED, false); + experimentalCollectProcessTagsEnabled = + configProvider.getBoolean(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, false); peerServiceMapping = configProvider.getMergedMap(TRACE_PEER_SERVICE_MAPPING); @@ -2091,6 +2094,10 @@ public Set getExperimentalFeaturesEnabled() { return experimentalFeaturesEnabled; } + public boolean isExperimentalCollectProcessTagsEnabled() { + return experimentalCollectProcessTagsEnabled; + } + public boolean isTraceEnabled() { return instrumenterConfig.isTraceEnabled(); } diff --git a/internal-api/src/main/java/datadog/trace/api/ProcessTags.java b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java new file mode 100644 index 00000000000..01ee7155d7f --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java @@ -0,0 +1,120 @@ +package datadog.trace.api; + +import datadog.trace.api.env.CapturedEnvironment; +import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; +import datadog.trace.util.TraceUtils; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProcessTags { + private static final Logger LOGGER = LoggerFactory.getLogger(ProcessTags.class); + + private static class Lazy { + static final Map TAGS = loadTags(); + static volatile UTF8BytesString serializedForm; + + private static Map loadTags() { + Map tags = new LinkedHashMap<>(); + try { + fillBaseTags(tags); + fillJbossTags(tags); + } catch (Throwable t) { + LOGGER.debug("Unable to calculate default process tags", t); + } + return tags; + } + + private static void insertSysPropIfPresent( + Map tags, String propKey, String tagKey) { + String value = System.getProperty(propKey); + if (value != null) { + tags.put(tagKey, value); + } + } + + private static boolean insertLastPathSegmentIfPresent( + Map tags, String path, String tagKey) { + if (path == null || path.isEmpty()) { + return false; + } + try { + final Path p = Paths.get(path).getFileName(); + if (p != null) { + tags.put(tagKey, p.toString()); + return true; + } + } catch (Throwable ignored) { + } + return false; + } + + private static void fillBaseTags(Map tags) { + final CapturedEnvironment.ProcessInfo processInfo = + CapturedEnvironment.get().getProcessInfo(); + if (processInfo.mainClass != null) { + tags.put("entrypoint.name", processInfo.mainClass); + } + if (processInfo.jarFile != null) { + final String jarName = processInfo.jarFile.getName(); + tags.put("entrypoint.name", jarName.substring(0, jarName.length() - 4)); // strip .jar + insertLastPathSegmentIfPresent(tags, processInfo.jarFile.getParent(), "entrypoint.basedir"); + } + + insertLastPathSegmentIfPresent(tags, System.getProperty("user.dir"), "entrypoint.workdir"); + } + + private static void fillJbossTags(Map tags) { + if (insertLastPathSegmentIfPresent( + tags, System.getProperty("jboss.home.dir"), "jboss.home")) { + insertSysPropIfPresent(tags, "jboss.server.name", "server.name"); + tags.put( + "jboss.mode", + System.getProperties().containsKey("[Standalone]") ? "standalone" : "domain"); + } + } + + static synchronized UTF8BytesString calculateSerializedForm() { + if (serializedForm == null && !TAGS.isEmpty()) { + serializedForm = + UTF8BytesString.create( + TAGS.entrySet().stream() + .map(entry -> entry.getKey() + ":" + TraceUtils.normalizeTag(entry.getValue())) + .collect(Collectors.joining(","))); + } + return serializedForm; + } + } + + private ProcessTags() {} + + // need to be synchronized on writing. As optimization, it does not need to be sync on read. + public static synchronized void addTag(String key, String value) { + Lazy.TAGS.put(key, value); + Lazy.serializedForm = null; + } + + public static UTF8BytesString getTagsForSerialization() { + final UTF8BytesString serializedForm = Lazy.serializedForm; + if (serializedForm != null) { + return serializedForm; + } + return Lazy.calculateSerializedForm(); + } + + /** Visible for testing. */ + static void empty() { + Lazy.TAGS.clear(); + Lazy.serializedForm = null; + } + + /** Visible for testing. */ + static void reset() { + empty(); + Lazy.TAGS.putAll(Lazy.loadTags()); + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/env/CapturedEnvironment.java b/internal-api/src/main/java/datadog/trace/api/env/CapturedEnvironment.java index 5bbb2744531..50e4d67fc5d 100644 --- a/internal-api/src/main/java/datadog/trace/api/env/CapturedEnvironment.java +++ b/internal-api/src/main/java/datadog/trace/api/env/CapturedEnvironment.java @@ -4,6 +4,7 @@ import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.File; import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -13,12 +14,54 @@ */ public class CapturedEnvironment { + public static class ProcessInfo { + public String mainClass; + public File jarFile; + + @SuppressForbidden + public ProcessInfo() { + // Besides "sun.java.command" property is not an standard, all main JDKs has set this + // property. + // Tested on: + // - OracleJDK, OpenJDK, AdoptOpenJDK, IBM JDK, Azul Zulu JDK, Amazon Coretto JDK + final String command = System.getProperty("sun.java.command"); + if (command == null || command.isEmpty()) { + return; + } + + final String[] split = command.trim().split(" "); + if (split.length == 0 || split[0].isEmpty()) { + return; + } + + final String candidate = split[0]; + if (candidate.toLowerCase(Locale.ROOT).endsWith(".jar")) { + jarFile = new File(candidate); + } else { + mainClass = candidate; + } + } + + /** + * Visible for testing + * + * @param mainClass + * @param jarFile + */ + ProcessInfo(String mainClass, File jarFile) { + this.mainClass = mainClass; + this.jarFile = jarFile; + } + } + private static final CapturedEnvironment INSTANCE = new CapturedEnvironment(); private final Map properties; + private ProcessInfo processInfo; CapturedEnvironment() { properties = new HashMap<>(); + processInfo = new ProcessInfo(); properties.put(GeneralConfig.SERVICE_NAME, autodetectServiceName()); } @@ -26,6 +69,10 @@ public Map getProperties() { return properties; } + public ProcessInfo getProcessInfo() { + return processInfo; + } + // Testing purposes static void useFixedEnv(final Map props) { INSTANCE.properties.clear(); @@ -35,6 +82,15 @@ static void useFixedEnv(final Map props) { } } + /** + * For testing purposes. + * + * @param processInfo + */ + static void useFixedProcessInfo(final ProcessInfo processInfo) { + INSTANCE.processInfo = processInfo; + } + /** * Returns autodetected service name based on the java process command line. Typically, the * autodetection will return either the JAR filename or the java main class. @@ -47,29 +103,12 @@ private String autodetectServiceName() { return siteName; } - // Besides "sun.java.command" property is not an standard, all main JDKs has set this property. - // Tested on: - // - OracleJDK, OpenJDK, AdoptOpenJDK, IBM JDK, Azul Zulu JDK, Amazon Coretto JDK - return extractJarOrClass(System.getProperty("sun.java.command")); - } - - @SuppressForbidden - private String extractJarOrClass(final String command) { - if (command == null || command.equals("")) { - return null; + if (processInfo.jarFile != null) { + final String jarName = processInfo.jarFile.getName(); + return jarName.substring(0, jarName.length() - 4); // strip .jar + } else { + return processInfo.mainClass; } - - final String[] split = command.trim().split(" "); - if (split.length == 0 || split[0].equals("")) { - return null; - } - - final String candidate = split[0]; - if (candidate.endsWith(".jar")) { - return new File(candidate).getName().replace(".jar", ""); - } - - return candidate; } public static CapturedEnvironment get() { diff --git a/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy new file mode 100644 index 00000000000..202553adb5d --- /dev/null +++ b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy @@ -0,0 +1,61 @@ +package datadog.trace.api + +import datadog.trace.api.env.CapturedEnvironment +import datadog.trace.test.util.DDSpecification + +import java.nio.file.Paths + +class ProcessTagsForkedTest extends DDSpecification { + + def originalProcessInfo + + def setup() { + originalProcessInfo = CapturedEnvironment.get().getProcessInfo() + } + + def cleanup() { + CapturedEnvironment.useFixedProcessInfo(originalProcessInfo) + ProcessTags.reset() + } + + def 'should load default tags for jar #jar and main class #cls'() { + given: + CapturedEnvironment.useFixedProcessInfo(new CapturedEnvironment.ProcessInfo(cls, jar)) + ProcessTags.reset() + def tags = ProcessTags.getTagsForSerialization() + expect: + tags =~ expected + where: + jar | cls | expected + Paths.get("my test", "my.jar").toFile() | null | "entrypoint.name:my,entrypoint.basedir:my_test,entrypoint.workdir:[^,]+" + Paths.get("my.jar").toFile() | null | "entrypoint.name:my,entrypoint.workdir:[^,]+" + null | "com.test.Main" | "entrypoint.name:com.test.main,entrypoint.workdir:[^,]+" + null | null | "entrypoint.workdir:[^,]+" + } + + def 'should load default tags jboss (mode #mode)'() { + setup: + if (jbossHome != null) { + System.setProperty("jboss.home.dir", jbossHome) + } + System.setProperty(mode, "") // i.e. -D[Standalone] + System.setProperty("jboss.server.name", serverName) + when: + CapturedEnvironment.useFixedProcessInfo(new CapturedEnvironment.ProcessInfo(null, new File("/somewhere/jboss-modules.jar"))) + ProcessTags.reset() + def tags = ProcessTags.getTagsForSerialization() + then: + assert tags =~ expected + cleanup: + System.clearProperty(mode) + System.clearProperty("jboss.home.dir") + System.clearProperty("jboss.server.name") + where: + jbossHome | mode | serverName | expected + "/opt/jboss/myserver" | "[Standalone]" | "standalone" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:.+,jboss.home:myserver,server.name:standalone,jboss.mode:standalone" + "/opt/jboss/myserver" | "[server1:12345]" | "server1" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:.+,jboss.home:myserver,server.name:server1,jboss.mode:domain" + null | "[Standalone]" | "standalone" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:[^,]+" // don't expect jboss tags since home is missing + + + } +} diff --git a/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy b/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy index 734f347e36d..c5346024a81 100644 --- a/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy +++ b/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy @@ -90,7 +90,7 @@ abstract class DDSpecification extends Specification { void setupSpec() { assert !configModificationFailed: "Config class modification failed. Ensure all test classes extend DDSpecification" - assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (getDDThreads().isEmpty()) { @@ -106,7 +106,7 @@ abstract class DDSpecification extends Specification { void cleanupSpec() { restoreProperties() - assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { @@ -129,7 +129,7 @@ abstract class DDSpecification extends Specification { void setup() { restoreProperties() - assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { @@ -140,7 +140,7 @@ abstract class DDSpecification extends Specification { void cleanup() { restoreProperties() - assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { From fcbe97771764564908ebfeab6f0bcebcf4fb033b Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Tue, 15 Apr 2025 16:56:45 +0200 Subject: [PATCH 2/7] fix tests and experimental features --- .../src/main/java/datadog/trace/api/ConfigDefaults.java | 2 +- .../src/test/groovy/datadog/trace/api/ConfigTest.groovy | 2 +- .../groovy/datadog/trace/test/util/DDSpecification.groovy | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index 4e42869ec8f..0caa4a58cd0 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -242,7 +242,7 @@ public final class ConfigDefaults { static final Set DEFAULT_TRACE_EXPERIMENTAL_FEATURES_ENABLED = new HashSet<>( - asList("DD_TAGS", "DD_LOGS_INJECTION", "EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED")); + asList("DD_TAGS", "DD_LOGS_INJECTION", "DD_EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED")); static final boolean DEFAULT_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = true; static final boolean DEFAULT_TRACE_128_BIT_TRACEID_LOGGING_ENABLED = true; diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 8dafd91f4a2..9149b0f4a01 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -1938,7 +1938,7 @@ class ConfigTest extends DDSpecification { def config = new Config() then: - config.experimentalFeaturesEnabled == ["DD_TAGS", "DD_LOGS_INJECTION"].toSet() + config.experimentalFeaturesEnabled == ["DD_TAGS", "DD_LOGS_INJECTION", "DD_EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED"].toSet() } def "detect if agent is configured using default values"() { diff --git a/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy b/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy index c5346024a81..734f347e36d 100644 --- a/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy +++ b/utils/test-utils/src/main/groovy/datadog/trace/test/util/DDSpecification.groovy @@ -90,7 +90,7 @@ abstract class DDSpecification extends Specification { void setupSpec() { assert !configModificationFailed: "Config class modification failed. Ensure all test classes extend DDSpecification" - // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (getDDThreads().isEmpty()) { @@ -106,7 +106,7 @@ abstract class DDSpecification extends Specification { void cleanupSpec() { restoreProperties() - // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { @@ -129,7 +129,7 @@ abstract class DDSpecification extends Specification { void setup() { restoreProperties() - // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { @@ -140,7 +140,7 @@ abstract class DDSpecification extends Specification { void cleanup() { restoreProperties() - // // assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() + assert System.getenv().findAll { it.key.startsWith("DD_") }.isEmpty() assert systemPropertiesExceptAllowed().findAll { it.key.toString().startsWith("dd.") }.isEmpty() if (isConfigInstanceModifiable) { From 69e81f665a32cc97b8c9e8b3d70e89cea94a9a0f Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Wed, 16 Apr 2025 23:20:45 +0200 Subject: [PATCH 3/7] Only add to first span in chunk --- .../common/writer/ddagent/TraceMapper.java | 1 + .../writer/ddagent/TraceMapperV0_4.java | 24 +++++-- .../writer/ddagent/TraceMapperV0_5.java | 24 +++++-- .../datadog/trace/core/DDSpanContext.java | 4 +- .../java/datadog/trace/core/Metadata.java | 9 ++- .../core/tagprocessor/ProcessTagsAdder.java | 21 ------ .../TagsPostProcessorFactory.java | 3 - .../trace/common/writer/TraceGenerator.groovy | 4 +- .../ddagent/TraceMapperV04PayloadTest.groovy | 49 ++++++++++++++ .../ddagent/TraceMapperV05PayloadTest.groovy | 67 +++++++++++++++++-- .../tagprocessor/ProcessTagsAdderTest.groovy | 27 -------- .../groovy/TraceGenerator.groovy | 4 +- .../java/datadog/trace/api/ProcessTags.java | 23 +++++-- .../trace/api/ProcessTagsForkedTest.groovy | 27 +++++++- 14 files changed, 212 insertions(+), 75 deletions(-) delete mode 100644 dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java delete mode 100644 dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapper.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapper.java index 3866a056b5e..b48e8adbc0c 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapper.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapper.java @@ -12,4 +12,5 @@ public interface TraceMapper extends RemoteMapper { UTF8BytesString SAMPLING_PRIORITY_KEY = UTF8BytesString.create(DDSpanContext.PRIORITY_SAMPLING_KEY); UTF8BytesString ORIGIN_KEY = UTF8BytesString.create(DDTags.ORIGIN_KEY); + UTF8BytesString PROCESS_TAGS_KEY = UTF8BytesString.create(DDTags.PROCESS_TAGS); } diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_4.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_4.java index 4033a23897b..a1d60164b82 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_4.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_4.java @@ -6,6 +6,7 @@ import datadog.communication.serialization.GrowableBuffer; import datadog.communication.serialization.Writable; import datadog.communication.serialization.msgpack.MsgPackWriter; +import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.InstrumentationTags; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.common.writer.Payload; @@ -36,25 +37,35 @@ public TraceMapperV0_4() { private static final class MetaWriter implements MetadataConsumer { private Writable writable; - private boolean writeSamplingPriority; + private boolean firstSpanInChunk; + private boolean lastSpanInChunk; MetaWriter withWritable(Writable writable) { this.writable = writable; return this; } - MetaWriter withWriteSamplingPriority(final boolean writeSamplingPriority) { - this.writeSamplingPriority = writeSamplingPriority; + MetaWriter forFirstSpanInChunk(final boolean firstSpanInChunk) { + this.firstSpanInChunk = firstSpanInChunk; + return this; + } + + MetaWriter forLastSpanInChunk(final boolean lastSpanInChunk) { + this.lastSpanInChunk = lastSpanInChunk; return this; } @Override public void accept(Metadata metadata) { + final boolean writeSamplingPriority = firstSpanInChunk || lastSpanInChunk; + final UTF8BytesString processTags = + firstSpanInChunk ? ProcessTags.getTagsForSerialization() : null; int metaSize = metadata.getBaggage().size() + metadata.getTags().size() + (null == metadata.getHttpStatusCode() ? 0 : 1) + (null == metadata.getOrigin() ? 0 : 1) + + (null == processTags ? 0 : 1) + 1; int metricsSize = (writeSamplingPriority && metadata.hasSamplingPriority() ? 1 : 0) @@ -124,6 +135,10 @@ public void accept(Metadata metadata) { writable.writeUTF8(ORIGIN_KEY); writable.writeString(metadata.getOrigin(), null); } + if (processTags != null) { + writable.writeUTF8(PROCESS_TAGS_KEY); + writable.writeUTF8(processTags); + } for (Map.Entry entry : metadata.getTags().entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); @@ -273,7 +288,8 @@ public void map(List> trace, final Writable writable) { span.processTagsAndBaggage( metaWriter .withWritable(writable) - .withWriteSamplingPriority(i == 0 || i == trace.size() - 1)); + .forFirstSpanInChunk(i == 0) + .forLastSpanInChunk(i == trace.size() - 1)); if (!metaStruct.isEmpty()) { /* 13 */ metaStructWriter.withWritable(writable).write(metaStruct); diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_5.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_5.java index 681a9a57693..786df12ecfc 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_5.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV0_5.java @@ -7,6 +7,7 @@ import datadog.communication.serialization.Writable; import datadog.communication.serialization.WritableFormatter; import datadog.communication.serialization.msgpack.MsgPackWriter; +import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.InstrumentationTags; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.common.writer.Payload; @@ -78,7 +79,8 @@ public void map(final List> trace, final Writable writable span.processTagsAndBaggage( metaWriter .withWritable(writable) - .withWriteSamplingPriority(i == 0 || i == trace.size() - 1)); + .forLastSpanInChunk(i == 0) + .forLastSpanInChunk(i == trace.size() - 1)); /* 12 */ writeDictionaryEncoded(writable, span.getType()); } @@ -179,25 +181,35 @@ private List toList() { private final class MetaWriter implements MetadataConsumer { private Writable writable; - private boolean writeSamplingPriority; + private boolean firstSpanInChunk; + private boolean lastSpanInChunk; MetaWriter withWritable(final Writable writable) { this.writable = writable; return this; } - MetaWriter withWriteSamplingPriority(final boolean writeSamplingPriority) { - this.writeSamplingPriority = writeSamplingPriority; + MetaWriter forFirstSpanInChunk(final boolean firstSpanInChunk) { + this.firstSpanInChunk = firstSpanInChunk; + return this; + } + + MetaWriter forLastSpanInChunk(final boolean lastSpanInChunk) { + this.lastSpanInChunk = lastSpanInChunk; return this; } @Override public void accept(Metadata metadata) { + final boolean writeSamplingPriority = firstSpanInChunk || lastSpanInChunk; + final UTF8BytesString processTags = + firstSpanInChunk ? ProcessTags.getTagsForSerialization() : null; int metaSize = metadata.getBaggage().size() + metadata.getTags().size() + (null == metadata.getHttpStatusCode() ? 0 : 1) + (null == metadata.getOrigin() ? 0 : 1) + + (null == processTags ? 0 : 1) + 1; int metricsSize = (writeSamplingPriority && metadata.hasSamplingPriority() ? 1 : 0) @@ -234,6 +246,10 @@ public void accept(Metadata metadata) { writeDictionaryEncoded(writable, ORIGIN_KEY); writeDictionaryEncoded(writable, metadata.getOrigin()); } + if (null != processTags) { + writeDictionaryEncoded(writable, PROCESS_TAGS_KEY); + writeDictionaryEncoded(writable, processTags); + } for (Map.Entry entry : metadata.getTags().entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index 70b96f2ff55..783bc02bfd2 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -7,6 +7,7 @@ import datadog.trace.api.DDTags; import datadog.trace.api.DDTraceId; import datadog.trace.api.Functions; +import datadog.trace.api.ProcessTags; import datadog.trace.api.cache.DDCache; import datadog.trace.api.cache.DDCaches; import datadog.trace.api.config.TracerConfig; @@ -874,7 +875,8 @@ public void processTagsAndBaggage( httpStatusCode == 0 ? null : HTTP_STATUSES.get(httpStatusCode), // Get origin from rootSpan.context getOrigin(), - longRunningVersion)); + longRunningVersion, + ProcessTags.getTagsForSerialization())); } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/Metadata.java b/dd-trace-core/src/main/java/datadog/trace/core/Metadata.java index f1f79454164..01054a91638 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/Metadata.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/Metadata.java @@ -17,6 +17,7 @@ public final class Metadata { private final boolean topLevel; private final CharSequence origin; private final int longRunningVersion; + private final UTF8BytesString processTags; public Metadata( long threadId, @@ -28,7 +29,8 @@ public Metadata( boolean topLevel, UTF8BytesString httpStatusCode, CharSequence origin, - int longRunningVersion) { + int longRunningVersion, + UTF8BytesString processTags) { this.threadId = threadId; this.threadName = threadName; this.httpStatusCode = httpStatusCode; @@ -39,6 +41,7 @@ public Metadata( this.topLevel = topLevel; this.origin = origin; this.longRunningVersion = longRunningVersion; + this.processTags = processTags; } public UTF8BytesString getHttpStatusCode() { @@ -84,4 +87,8 @@ public boolean hasSamplingPriority() { public int samplingPriority() { return samplingPriority; } + + public UTF8BytesString processTags() { + return processTags; + } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java deleted file mode 100644 index aa10555a64a..00000000000 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ProcessTagsAdder.java +++ /dev/null @@ -1,21 +0,0 @@ -package datadog.trace.core.tagprocessor; - -import static datadog.trace.api.DDTags.PROCESS_TAGS; - -import datadog.trace.api.ProcessTags; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; -import datadog.trace.core.DDSpanContext; -import java.util.List; -import java.util.Map; - -public class ProcessTagsAdder implements TagsPostProcessor { - @Override - public Map processTags( - Map unsafeTags, DDSpanContext spanContext, List spanLinks) { - final CharSequence processTags = ProcessTags.getTagsForSerialization(); - if (processTags != null) { - unsafeTags.put(PROCESS_TAGS, processTags); - } - return unsafeTags; - } -} diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java index dc80379e5b8..2812bdb8479 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessorFactory.java @@ -32,9 +32,6 @@ private static TagsPostProcessor create() { if (Config.get().isAddSpanPointers("aws")) { processors.add(new SpanPointersProcessor()); } - if (Config.get().isExperimentalCollectProcessTagsEnabled()) { - processors.add(new ProcessTagsAdder()); - } return new PostProcessorChain( processors.toArray(processors.toArray(new TagsPostProcessor[0]))); } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/TraceGenerator.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/TraceGenerator.groovy index db3bd899805..4ce25337ce7 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/TraceGenerator.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/TraceGenerator.groovy @@ -4,6 +4,7 @@ import datadog.trace.api.DDSpanId import datadog.trace.api.DDTags import datadog.trace.api.DDTraceId import datadog.trace.api.IdGenerationStrategy +import datadog.trace.api.ProcessTags import datadog.trace.api.sampling.PrioritySampling import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString import datadog.trace.core.CoreSpan @@ -177,7 +178,8 @@ class TraceGenerator { this.samplingPriority = samplingPriority this.metadata = new Metadata(Thread.currentThread().getId(), UTF8BytesString.create(Thread.currentThread().getName()), tags, baggage, samplingPriority, measured, topLevel, - statusCode == 0 ? null : UTF8BytesString.create(Integer.toString(statusCode)), origin, 0) + statusCode == 0 ? null : UTF8BytesString.create(Integer.toString(statusCode)), origin, 0, + ProcessTags.tagsForSerialization) this.httpStatusCode = (short) statusCode } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy index 8cde97d61b2..bc8d6cb1a86 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy @@ -3,9 +3,11 @@ package datadog.trace.common.writer.ddagent import datadog.communication.serialization.ByteBufferConsumer import datadog.communication.serialization.FlushingBuffer import datadog.communication.serialization.msgpack.MsgPackWriter +import datadog.trace.api.Config import datadog.trace.api.DD64bTraceId import datadog.trace.api.DDTags import datadog.trace.api.DDTraceId +import datadog.trace.api.ProcessTags import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.common.writer.Payload import datadog.trace.common.writer.TraceGenerator @@ -19,10 +21,13 @@ import org.msgpack.core.MessageUnpacker import java.nio.ByteBuffer import java.nio.channels.WritableByteChannel +import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DD_MEASURED import static datadog.trace.common.writer.TraceGenerator.generateRandomTraces import static org.junit.jupiter.api.Assertions.assertEquals import static org.junit.jupiter.api.Assertions.assertFalse +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.junit.jupiter.api.Assertions.assertTrue import static org.msgpack.core.MessageFormat.FLOAT32 import static org.msgpack.core.MessageFormat.FLOAT64 import static org.msgpack.core.MessageFormat.INT16 @@ -170,6 +175,46 @@ class TraceMapperV04PayloadTest extends DDSpecification { verifier.verifyTracesConsumed() } + void 'test process tags serialization'() { + setup: + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") + ProcessTags.reset() + assertNotNull(ProcessTags.tagsForSerialization) + def spans = (1..2).collect { + new TraceGenerator.PojoSpan( + 'service', + 'operation', + 'resource', + DDTraceId.ONE, + it, + -1L, + 123L, + 456L, + 0, + [:], + [:], + 'type', + false, + 0, + 0, + 'origin') + } + + def traces = [spans] + TraceMapperV0_4 traceMapper = new TraceMapperV0_4() + PayloadVerifier verifier = new PayloadVerifier(traces, traceMapper) + MsgPackWriter packer = new MsgPackWriter(new FlushingBuffer(20 << 10, verifier)) + + when: + packer.format(spans, traceMapper) + packer.flush() + + then: + verifier.verifyTracesConsumed() + cleanup: + ProcessTags.empty() + } + private static final class PayloadVerifier implements ByteBufferConsumer, WritableByteChannel { private final List> expectedTraces @@ -301,6 +346,10 @@ class TraceMapperV04PayloadTest extends DDSpecification { assertEquals(String.valueOf(expectedSpan.getHttpStatusCode()), entry.getValue()) } else if (DDTags.ORIGIN_KEY.equals(entry.getKey())) { assertEquals(expectedSpan.getOrigin(), entry.getValue()) + } else if (DDTags.PROCESS_TAGS.equals(entry.getKey())) { + assertTrue(Config.get().isExperimentalCollectProcessTagsEnabled()) + assertEquals(0, i) + assertEquals(ProcessTags.tagsForSerialization.toString(), entry.getValue()) } else { Object tag = expectedSpan.getTag(entry.getKey()) if (null != tag) { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy index f416b7fff5a..3a4d5f67137 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy @@ -3,13 +3,15 @@ package datadog.trace.common.writer.ddagent import datadog.communication.serialization.ByteBufferConsumer import datadog.communication.serialization.FlushingBuffer import datadog.communication.serialization.msgpack.MsgPackWriter +import datadog.trace.api.Config import datadog.trace.api.DDSpanId import datadog.trace.api.DDTags import datadog.trace.api.DDTraceId +import datadog.trace.api.ProcessTags import datadog.trace.api.sampling.PrioritySampling +import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.common.writer.Payload import datadog.trace.common.writer.TraceGenerator -import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.core.DDSpanContext import datadog.trace.test.util.DDSpecification import org.junit.Assert @@ -21,11 +23,25 @@ import java.nio.ByteBuffer import java.nio.channels.WritableByteChannel import java.util.concurrent.atomic.AtomicInteger +import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DD_MEASURED import static datadog.trace.common.writer.TraceGenerator.generateRandomTraces -import static org.junit.Assert.assertEquals import static org.junit.Assert.assertFalse -import static org.msgpack.core.MessageFormat.* +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.junit.jupiter.api.Assertions.assertTrue +import static org.msgpack.core.MessageFormat.FLOAT32 +import static org.msgpack.core.MessageFormat.FLOAT64 +import static org.msgpack.core.MessageFormat.INT16 +import static org.msgpack.core.MessageFormat.INT32 +import static org.msgpack.core.MessageFormat.INT64 +import static org.msgpack.core.MessageFormat.INT8 +import static org.msgpack.core.MessageFormat.NEGFIXINT +import static org.msgpack.core.MessageFormat.POSFIXINT +import static org.msgpack.core.MessageFormat.UINT16 +import static org.msgpack.core.MessageFormat.UINT32 +import static org.msgpack.core.MessageFormat.UINT64 +import static org.msgpack.core.MessageFormat.UINT8 class TraceMapperV05PayloadTest extends DDSpecification { @@ -129,6 +145,46 @@ class TraceMapperV05PayloadTest extends DDSpecification { 100 << 10 | 100 << 10 | 1000 | false } + void 'test process tags serialization'() { + setup: + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") + ProcessTags.reset() + assertNotNull(ProcessTags.tagsForSerialization) + def spans = (1..2).collect { + new TraceGenerator.PojoSpan( + 'service', + 'operation', + 'resource', + DDTraceId.ONE, + it, + -1L, + 123L, + 456L, + 0, + [:], + [:], + 'type', + false, + 0, + 0, + 'origin') + } + + def traces = [spans] + TraceMapperV0_5 traceMapper = new TraceMapperV0_5() + PayloadVerifier verifier = new PayloadVerifier(traces, traceMapper) + MsgPackWriter packer = new MsgPackWriter(new FlushingBuffer(20 << 10, verifier)) + + when: + packer.format(spans, traceMapper) + packer.flush() + + then: + verifier.verifyTracesConsumed() + cleanup: + ProcessTags.empty() + } + private static final class PayloadVerifier implements ByteBufferConsumer, WritableByteChannel { private final List> expectedTraces @@ -203,7 +259,10 @@ class TraceMapperV05PayloadTest extends DDSpecification { } else if(DDTags.ORIGIN_KEY.equals(entry.getKey())) { assertEquals(expectedSpan.getOrigin(), entry.getValue()) - + } else if (DDTags.PROCESS_TAGS.equals(entry.getKey())) { + assertTrue(Config.get().isExperimentalCollectProcessTagsEnabled()) + assertEquals(0, i) + assertEquals(ProcessTags.tagsForSerialization.toString(), entry.getValue()) } else { Object tag = expectedSpan.getTag(entry.getKey()) if (null != tag) { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy deleted file mode 100644 index cee4e14affc..00000000000 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/ProcessTagsAdderTest.groovy +++ /dev/null @@ -1,27 +0,0 @@ -package datadog.trace.core.tagprocessor - -import datadog.trace.api.ProcessTags -import datadog.trace.core.DDSpanContext -import datadog.trace.test.util.DDSpecification - -class ProcessTagsAdderTest extends DDSpecification { - def "should add _dd.process"() { - setup: - def adder = new ProcessTagsAdder() - def spanContext = Mock(DDSpanContext) - - when: - def enrichedTags = adder.processTags([:], spanContext, []) - - then: - def firstValue = enrichedTags.get("_dd.process") - assert !firstValue.toString().isEmpty() - - when: - ProcessTags.addTag("test", "value") - enrichedTags = adder.processTags([:], spanContext, []) - - then: - assert enrichedTags.get("_dd.process").toString() == "$firstValue,test:value" - } -} diff --git a/dd-trace-core/src/traceAgentTest/groovy/TraceGenerator.groovy b/dd-trace-core/src/traceAgentTest/groovy/TraceGenerator.groovy index 9089f8b5a43..d3420c2116b 100644 --- a/dd-trace-core/src/traceAgentTest/groovy/TraceGenerator.groovy +++ b/dd-trace-core/src/traceAgentTest/groovy/TraceGenerator.groovy @@ -2,6 +2,7 @@ import datadog.trace.api.DDSpanId import datadog.trace.api.DDTags import datadog.trace.api.DDTraceId import datadog.trace.api.IdGenerationStrategy +import datadog.trace.api.ProcessTags import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString import datadog.trace.core.CoreSpan import datadog.trace.core.Metadata @@ -155,7 +156,8 @@ class TraceGenerator { this.type = type this.measured = measured this.metadata = new Metadata(Thread.currentThread().getId(), - UTF8BytesString.create(Thread.currentThread().getName()), tags, baggage, UNSET, measured, topLevel, null, null, 0) + UTF8BytesString.create(Thread.currentThread().getName()), tags, baggage, UNSET, measured, topLevel, null, null, 0, + ProcessTags.tagsForSerialization) } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/ProcessTags.java b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java index 01ee7155d7f..92d6defc30e 100644 --- a/internal-api/src/main/java/datadog/trace/api/ProcessTags.java +++ b/internal-api/src/main/java/datadog/trace/api/ProcessTags.java @@ -13,6 +13,7 @@ public class ProcessTags { private static final Logger LOGGER = LoggerFactory.getLogger(ProcessTags.class); + private static boolean enabled = Config.get().isExperimentalCollectProcessTagsEnabled(); private static class Lazy { static final Map TAGS = loadTags(); @@ -20,11 +21,13 @@ private static class Lazy { private static Map loadTags() { Map tags = new LinkedHashMap<>(); - try { - fillBaseTags(tags); - fillJbossTags(tags); - } catch (Throwable t) { - LOGGER.debug("Unable to calculate default process tags", t); + if (enabled) { + try { + fillBaseTags(tags); + fillJbossTags(tags); + } catch (Throwable t) { + LOGGER.debug("Unable to calculate default process tags", t); + } } return tags; } @@ -94,11 +97,16 @@ private ProcessTags() {} // need to be synchronized on writing. As optimization, it does not need to be sync on read. public static synchronized void addTag(String key, String value) { - Lazy.TAGS.put(key, value); - Lazy.serializedForm = null; + if (enabled) { + Lazy.TAGS.put(key, value); + Lazy.serializedForm = null; + } } public static UTF8BytesString getTagsForSerialization() { + if (!enabled) { + return null; + } final UTF8BytesString serializedForm = Lazy.serializedForm; if (serializedForm != null) { return serializedForm; @@ -115,6 +123,7 @@ static void empty() { /** Visible for testing. */ static void reset() { empty(); + enabled = Config.get().isExperimentalCollectProcessTagsEnabled(); Lazy.TAGS.putAll(Lazy.loadTags()); } } diff --git a/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy index 202553adb5d..b88c446d792 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy @@ -5,21 +5,24 @@ import datadog.trace.test.util.DDSpecification import java.nio.file.Paths +import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED + class ProcessTagsForkedTest extends DDSpecification { def originalProcessInfo def setup() { originalProcessInfo = CapturedEnvironment.get().getProcessInfo() + ProcessTags.reset() } def cleanup() { CapturedEnvironment.useFixedProcessInfo(originalProcessInfo) - ProcessTags.reset() } def 'should load default tags for jar #jar and main class #cls'() { given: + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") CapturedEnvironment.useFixedProcessInfo(new CapturedEnvironment.ProcessInfo(cls, jar)) ProcessTags.reset() def tags = ProcessTags.getTagsForSerialization() @@ -35,6 +38,7 @@ class ProcessTagsForkedTest extends DDSpecification { def 'should load default tags jboss (mode #mode)'() { setup: + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") if (jbossHome != null) { System.setProperty("jboss.home.dir", jbossHome) } @@ -55,7 +59,28 @@ class ProcessTagsForkedTest extends DDSpecification { "/opt/jboss/myserver" | "[Standalone]" | "standalone" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:.+,jboss.home:myserver,server.name:standalone,jboss.mode:standalone" "/opt/jboss/myserver" | "[server1:12345]" | "server1" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:.+,jboss.home:myserver,server.name:server1,jboss.mode:domain" null | "[Standalone]" | "standalone" | "entrypoint.name:jboss-modules,entrypoint.basedir:somewhere,entrypoint.workdir:[^,]+" // don't expect jboss tags since home is missing + } + def 'should not calculate process tags by default'() { + given: + def processTags = ProcessTags.tagsForSerialization + expect: + !ProcessTags.enabled + processTags == null + } + def 'should lazily recalculate when a tag is added'() { + setup: + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") + ProcessTags.reset() + when: + def processTags = ProcessTags.tagsForSerialization + then: + assert ProcessTags.enabled + assert processTags != null + when: + ProcessTags.addTag("test", "value") + then: + assert ProcessTags.tagsForSerialization.toString() == "$processTags,test:value" } } From c494386526a0bb413a0977d2fa823bae68df40d0 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 17 Apr 2025 09:32:40 +0200 Subject: [PATCH 4/7] fix tests --- .../groovy/SpringBootApplicationTest.groovy | 3 +++ .../ddagent/TraceMapperV04PayloadTest.groovy | 2 +- .../ddagent/TraceMapperV05PayloadTest.groovy | 20 ++++--------------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy b/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy index a98bd1d32fa..00694c25505 100644 --- a/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy +++ b/dd-java-agent/instrumentation/spring-boot/src/test/groovy/SpringBootApplicationTest.groovy @@ -7,10 +7,13 @@ import datadog.trace.api.Config import org.springframework.beans.factory.InitializingBean import org.springframework.boot.SpringApplication +import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED + class SpringBootApplicationTest extends AgentTestRunner { @Override protected void configurePreAgent() { super.configurePreAgent() + injectSysConfig(EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED, "true") } static class BeanWhoTraces implements InitializingBean { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy index bc8d6cb1a86..f7d027f62d4 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV04PayloadTest.groovy @@ -348,7 +348,7 @@ class TraceMapperV04PayloadTest extends DDSpecification { assertEquals(expectedSpan.getOrigin(), entry.getValue()) } else if (DDTags.PROCESS_TAGS.equals(entry.getKey())) { assertTrue(Config.get().isExperimentalCollectProcessTagsEnabled()) - assertEquals(0, i) + assertEquals(0, k) assertEquals(ProcessTags.tagsForSerialization.toString(), entry.getValue()) } else { Object tag = expectedSpan.getTag(entry.getKey()) diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy index 3a4d5f67137..1c46f0a62f6 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV05PayloadTest.groovy @@ -26,22 +26,10 @@ import java.util.concurrent.atomic.AtomicInteger import static datadog.trace.api.config.GeneralConfig.EXPERIMENTAL_COLLECT_PROCESS_TAGS_ENABLED import static datadog.trace.bootstrap.instrumentation.api.InstrumentationTags.DD_MEASURED import static datadog.trace.common.writer.TraceGenerator.generateRandomTraces +import static org.junit.Assert.assertEquals import static org.junit.Assert.assertFalse -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertNotNull -import static org.junit.jupiter.api.Assertions.assertTrue -import static org.msgpack.core.MessageFormat.FLOAT32 -import static org.msgpack.core.MessageFormat.FLOAT64 -import static org.msgpack.core.MessageFormat.INT16 -import static org.msgpack.core.MessageFormat.INT32 -import static org.msgpack.core.MessageFormat.INT64 -import static org.msgpack.core.MessageFormat.INT8 -import static org.msgpack.core.MessageFormat.NEGFIXINT -import static org.msgpack.core.MessageFormat.POSFIXINT -import static org.msgpack.core.MessageFormat.UINT16 -import static org.msgpack.core.MessageFormat.UINT32 -import static org.msgpack.core.MessageFormat.UINT64 -import static org.msgpack.core.MessageFormat.UINT8 +import static org.junit.Assert.assertNotNull +import static org.msgpack.core.MessageFormat.* class TraceMapperV05PayloadTest extends DDSpecification { @@ -261,7 +249,7 @@ class TraceMapperV05PayloadTest extends DDSpecification { assertEquals(expectedSpan.getOrigin(), entry.getValue()) } else if (DDTags.PROCESS_TAGS.equals(entry.getKey())) { assertTrue(Config.get().isExperimentalCollectProcessTagsEnabled()) - assertEquals(0, i) + assertEquals(0, k) assertEquals(ProcessTags.tagsForSerialization.toString(), entry.getValue()) } else { Object tag = expectedSpan.getTag(entry.getKey()) From 364952152317daf128bc5f88ca5168503d93f29c Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 17 Apr 2025 11:49:35 +0200 Subject: [PATCH 5/7] use the good tag name --- dd-trace-api/src/main/java/datadog/trace/api/DDTags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java index d8ed8ddd776..1556fef030c 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java @@ -98,5 +98,5 @@ public class DDTags { public static final String DECISION_MAKER_INHERITED = "_dd.dm.inherited"; public static final String DECISION_MAKER_SERVICE = "_dd.dm.service"; public static final String DECISION_MAKER_RESOURCE = "_dd.dm.resource"; - public static final String PROCESS_TAGS = "_dd.process"; + public static final String PROCESS_TAGS = "_dd.tags.process"; } From 88bb6b04ceb5cb7456ffa4f30e3aee319a600984 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 17 Apr 2025 12:17:13 +0200 Subject: [PATCH 6/7] target all spring boot advices --- .../SpringApplicationInstrumentation.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java b/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java index 7c6eefc6881..215c10892e5 100644 --- a/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-boot/src/main/java/datadog/trace/instrumentation/springboot/SpringApplicationInstrumentation.java @@ -9,7 +9,6 @@ import datadog.trace.api.Config; import datadog.trace.api.ProcessTags; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; -import java.util.Arrays; import net.bytebuddy.asm.Advice; import org.springframework.core.env.ConfigurableEnvironment; @@ -64,14 +63,15 @@ public static void afterEnvironmentPostProcessed( AgentTracer.get().updatePreferredServiceName(applicationName); ProcessTags.addTag("springboot.application", applicationName); } - final String[] profiles = environment.getActiveProfiles(); - System.err.println(Arrays.toString(profiles)); - if (profiles != null && profiles.length > 0) { - ProcessTags.addTag("springboot.profile", profiles[0]); - } else { - final String[] defaultProfiles = environment.getDefaultProfiles(); - if (defaultProfiles != null && defaultProfiles.length > 0) { - ProcessTags.addTag("springboot.profile", defaultProfiles[0]); + if (Config.get().isExperimentalCollectProcessTagsEnabled()) { + final String[] profiles = environment.getActiveProfiles(); + if (profiles != null && profiles.length > 0) { + ProcessTags.addTag("springboot.profile", profiles[0]); + } else { + final String[] defaultProfiles = environment.getDefaultProfiles(); + if (defaultProfiles != null && defaultProfiles.length > 0) { + ProcessTags.addTag("springboot.profile", defaultProfiles[0]); + } } } } @@ -90,6 +90,18 @@ public static void afterEnvironmentPostProcessed( final String applicationName = environment.getProperty("spring.application.name"); if (applicationName != null && !applicationName.isEmpty()) { AgentTracer.get().updatePreferredServiceName(applicationName); + ProcessTags.addTag("springboot.application", applicationName); + } + if (Config.get().isExperimentalCollectProcessTagsEnabled()) { + final String[] profiles = environment.getActiveProfiles(); + if (profiles != null && profiles.length > 0) { + ProcessTags.addTag("springboot.profile", profiles[0]); + } else { + final String[] defaultProfiles = environment.getDefaultProfiles(); + if (defaultProfiles != null && defaultProfiles.length > 0) { + ProcessTags.addTag("springboot.profile", defaultProfiles[0]); + } + } } } } From f9f99f55b29ee2d8e9f26ef3503d54dbfbfba047 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 17 Apr 2025 14:26:03 +0200 Subject: [PATCH 7/7] fix coverage --- .../datadog/trace/api/ProcessTagsForkedTest.groovy | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy index b88c446d792..cc962b048f0 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ProcessTagsForkedTest.groovy @@ -62,11 +62,16 @@ class ProcessTagsForkedTest extends DDSpecification { } def 'should not calculate process tags by default'() { - given: + when: + ProcessTags.reset() def processTags = ProcessTags.tagsForSerialization - expect: - !ProcessTags.enabled - processTags == null + then: + assert !ProcessTags.enabled + assert processTags == null + when: + ProcessTags.addTag("test", "value") + then: + assert ProcessTags.tagsForSerialization == null } def 'should lazily recalculate when a tag is added'() {