Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import datadog.environment.JavaVirtualMachine;
import datadog.libs.ddprof.DdprofLibraryLoader;
import datadog.trace.api.config.ProfilingConfig;
import datadog.trace.api.internal.VisibleForTesting;
import datadog.trace.api.profiling.RecordingData;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
import datadog.trace.bootstrap.instrumentation.api.TaskWrapper;
Expand Down Expand Up @@ -113,11 +112,6 @@ public static DatadogProfiler newInstance(ConfigProvider configProvider) {
private final Path recordingsPath;

private DatadogProfiler(ConfigProvider configProvider) {
this(configProvider, getContextAttributes(configProvider));
}

@VisibleForTesting
DatadogProfiler(ConfigProvider configProvider, Set<String> contextAttributes) {
this.configProvider = configProvider;
this.profiler = DdprofLibraryLoader.javaProfiler().getComponent();
this.detailedDebugLogging =
Expand All @@ -143,13 +137,7 @@ private DatadogProfiler(ConfigProvider configProvider) {
if (isWallClockProfilerEnabled(configProvider)) {
profilingModes.add(WALL);
}
this.orderedContextAttributes = new ArrayList<>(contextAttributes);
if (isSpanNameContextAttributeEnabled(configProvider)) {
orderedContextAttributes.add(OPERATION);
}
if (isResourceNameContextAttributeEnabled(configProvider)) {
orderedContextAttributes.add(RESOURCE);
}
this.orderedContextAttributes = getOrderedContextAttributes(configProvider);
this.contextSetter = new ContextSetter(profiler, orderedContextAttributes);
this.queueTimeThresholdMillis =
configProvider.getLong(
Expand All @@ -170,6 +158,23 @@ private DatadogProfiler(ConfigProvider configProvider) {
}
}

/**
* Computes the ordered context-attribute list (base attributes from config, then the optional
* span-name and resource-name attributes) in the exact order used for the per-thread {@link
* ContextSetter} and the native profiler's {@code attributes=} argument. Exposed so the OTel
* process context can publish the same {@code attribute_key_map} before the profiler starts.
*/
public static List<String> getOrderedContextAttributes(ConfigProvider configProvider) {
List<String> ordered = new ArrayList<>(getContextAttributes(configProvider));
if (isSpanNameContextAttributeEnabled(configProvider)) {
ordered.add(OPERATION);
}
if (isResourceNameContextAttributeEnabled(configProvider)) {
ordered.add(RESOURCE);
}
return ordered;
}

void addThread() {
profiler.addThread();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.UUID;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -169,9 +168,14 @@ public void testContextRegistration() {
// so there is only one shot to test it here, 'foo,bar' need to be kept in the same
// order whether in the list or the enum, and any other test which tries to register
// context attributes will fail
Properties props = new Properties();
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_ENABLED, "true");
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_ENABLED, "true");
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_ENABLED, "true");
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_LIVEHEAP_ENABLED, "true");
props.put(ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES, "foo,bar");
DatadogProfiler profiler =
new DatadogProfiler(
configProvider(true, true, true, true), new HashSet<>(Arrays.asList("foo", "bar")));
DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props));
assertTrue(profiler.setContextValue("foo", "abc"));
assertTrue(profiler.setContextValue("bar", "abc"));
assertTrue(profiler.setContextValue("foo", "xyz"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.datadog.profiling.agent;

import com.datadog.profiling.ddprof.DatadogProfiler;
import datadog.libs.ddprof.DdprofLibraryLoader;
import datadog.trace.api.Config;
import datadog.trace.api.config.ProfilingConfig;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -19,6 +21,11 @@ public static void register(ConfigProvider configProvider) {
Throwable err = holder.getReasonNotLoaded();
if (err == null) {
Config cfg = Config.get();
// Publish the thread-context attribute keys together with the process context so the
// very first published context already carries the attribute_key_map. The order must
// match what DatadogProfiler passes to the native attributes= argument and the
// per-thread ContextSetter, so external readers can decode the thread-local record.
List<String> attributeKeys = DatadogProfiler.getOrderedContextAttributes(configProvider);
holder
.getComponent()
.setProcessContext(
Expand All @@ -27,7 +34,8 @@ public static void register(ConfigProvider configProvider) {
cfg.getRuntimeId(),
cfg.getServiceName(),
cfg.getRuntimeVersion(),
cfg.getVersion());
cfg.getVersion(),
attributeKeys.toArray(new String[0]));
} else {
log.warn("Failed to register process context for OTel profiler", err);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.datadog.profiling.agent;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
Expand All @@ -12,6 +14,8 @@
import datadog.trace.api.Config;
import datadog.trace.api.config.ProfilingConfig;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
import java.util.Arrays;
import java.util.LinkedHashSet;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;

Expand All @@ -24,6 +28,8 @@ void testRegisterSetsProcessContextValues() {
eq(ProfilingConfig.PROFILING_PROCESS_CONTEXT_ENABLED),
eq(ProfilingConfig.PROFILING_PROCESS_CONTEXT_ENABLED_DEFAULT)))
.thenReturn(true);
when(configProvider.getSet(eq(ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES), any()))
.thenReturn(new LinkedHashSet<>(Arrays.asList("http.route", "db.system")));

Config config = mock(Config.class);
when(config.getEnv()).thenReturn("test-env");
Expand Down Expand Up @@ -54,7 +60,8 @@ void testRegisterSetsProcessContextValues() {
eq("test-runtime-id"),
eq("test-service"),
eq("test-runtime-version"),
eq("test-version"));
eq("test-version"),
aryEq(new String[] {"http.route", "db.system"}));
}
}

Expand Down
Loading