Skip to content

Commit 8e47532

Browse files
updated dynamic context attributes
1 parent 14b43c3 commit 8e47532

14 files changed

Lines changed: 129 additions & 55 deletions

File tree

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.nio.file.Paths;
4141
import java.util.ArrayList;
4242
import java.util.EnumSet;
43+
import java.util.List;
4344
import java.util.Set;
4445
import java.util.concurrent.atomic.AtomicBoolean;
4546
import java.util.concurrent.locks.LockSupport;
@@ -86,6 +87,8 @@ static DatadogProfiler newInstance(ConfigProvider configProvider) {
8687

8788
private final ContextSetter contextSetter;
8889

90+
private final List<String> orderedContextAttributes;
91+
8992
private DatadogProfiler() throws UnsupportedEnvironmentException {
9093
this(ConfigProvider.getInstance());
9194
}
@@ -94,6 +97,7 @@ private DatadogProfiler(Void dummy) {
9497
this.configProvider = null;
9598
this.profiler = null;
9699
this.contextSetter = null;
100+
this.orderedContextAttributes = null;
97101
}
98102

99103
private DatadogProfiler(ConfigProvider configProvider) throws UnsupportedEnvironmentException {
@@ -125,7 +129,8 @@ private DatadogProfiler(ConfigProvider configProvider) throws UnsupportedEnviron
125129
if (isWallClockProfilerEnabled(configProvider)) {
126130
profilingModes.add(WALL);
127131
}
128-
this.contextSetter = new ContextSetter(profiler, new ArrayList<>(contextAttributes));
132+
this.orderedContextAttributes = new ArrayList<>(contextAttributes);
133+
this.contextSetter = new ContextSetter(profiler, orderedContextAttributes);
129134
try {
130135
// sanity test - force load Datadog profiler to catch it not being available early
131136
profiler.execute("status");
@@ -307,6 +312,7 @@ String cmdStartProfiling(Path file) throws IllegalStateException {
307312
cmd.append(",jstackdepth=").append(getStackDepth(configProvider));
308313
cmd.append(",cstack=").append(getCStack(configProvider));
309314
cmd.append(",safemode=").append(getSafeMode(configProvider));
315+
cmd.append(",attributes=").append(String.join(";", orderedContextAttributes));
310316
if (profilingModes.contains(CPU)) {
311317
// cpu profiling is enabled.
312318
String schedulingEvent = getSchedulingEvent(configProvider);
@@ -368,4 +374,11 @@ public boolean setContextValue(String attribute, String value) {
368374
}
369375
return false;
370376
}
377+
378+
public boolean clearContextValue(String attribute) {
379+
if (contextSetter != null) {
380+
return contextSetter.clearContextValue(attribute);
381+
}
382+
return false;
383+
}
371384
}

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,39 @@
11
package com.datadog.profiling.ddprof;
22

33
import static datadog.trace.api.Platform.isJ9;
4-
import static datadog.trace.api.config.ProfilingConfig.*;
4+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_CONTEXT_ATTRIBUTES;
5+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_ENABLED;
6+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_ENABLED_DEFAULT;
7+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_INTERVAL;
8+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_ALLOC_INTERVAL_DEFAULT;
9+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_ENABLED;
10+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_ENABLED_DEFAULT;
11+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_INTERVAL;
12+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_INTERVAL_DEFAULT;
13+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK;
14+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK_DEFAULT;
15+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LIBPATH;
16+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LOG_LEVEL;
17+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LOG_LEVEL_DEFAULT;
18+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_CAPACITY;
19+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_CAPACITY_DEFAULT;
20+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_ENABLED;
21+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_ENABLED_DEFAULT;
22+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_INTERVAL;
23+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE;
24+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE_DEFAULT;
25+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SCHEDULING_EVENT;
26+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SCHEDULING_EVENT_INTERVAL;
27+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_STACKDEPTH;
28+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_STACKDEPTH_DEFAULT;
29+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_COLLAPSING;
30+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_COLLAPSING_DEFAULT;
31+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER;
32+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER_DEFAULT;
33+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_ENABLED;
34+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_ENABLED_DEFAULT;
35+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_INTERVAL;
36+
import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_INTERVAL_DEFAULT;
537

638
import datadog.trace.bootstrap.config.provider.ConfigProvider;
739
import java.lang.management.ManagementFactory;

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilingIntegration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ public void setContext(long rootSpanId, long spanId) {
3535
public void setContextValue(String attribute, String value) {
3636
DDPROF.setContextValue(attribute, value);
3737
}
38+
39+
@Override
40+
public void clearContextValue(String attribute) {
41+
DDPROF.clearContextValue(attribute);
42+
}
3843
}

dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.datadog.profiling.ddprof;
22

3-
import static org.junit.jupiter.api.Assertions.*;
3+
import static org.junit.jupiter.api.Assertions.assertFalse;
4+
import static org.junit.jupiter.api.Assertions.assertNotNull;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
46

57
import com.datadog.profiling.controller.OngoingRecording;
68
import com.datadog.profiling.controller.RecordingData;
@@ -99,6 +101,10 @@ private static Stream<Arguments> profilingModes() {
99101

100102
@Test
101103
public void testContextRegistration() throws UnsupportedEnvironmentException {
104+
// warning - the profiler is a process wide singleton and can't be reinitialised
105+
// so there is only one shot to test it here, 'foo,bar' need to be kept in the same
106+
// order whether in the list or the enum, and any other test which tries to register
107+
// context attributes will fail
102108
DatadogProfiler profiler =
103109
new DatadogProfiler(
104110
configProvider(true, true, true, true), new HashSet<>(Arrays.asList("foo", "bar")));

dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/TestProfilingContextIntegration.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ class TestProfilingContextIntegration implements ProfilingContextIntegration {
2424
@Override
2525
void setContextValue(String attribute, String value) {
2626
}
27+
28+
@Override
29+
void clearContextValue(String attribute) {
30+
}
2731
}

dd-smoke-tests/profiling-integration-tests/src/test/java/datadog/smoketest/JFRBasedProfilingIntegrationTest.java

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
55
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
import static org.junit.jupiter.api.Assertions.assertNull;
67
import static org.junit.jupiter.api.Assertions.assertTrue;
78
import static org.openjdk.jmc.common.item.Attribute.attr;
89
import static org.openjdk.jmc.common.unit.UnitLookup.NUMBER;
@@ -93,8 +94,8 @@ private interface TestBody {
9394
attr("localRootSpanId", "localRootSpanId", "localRootSpanId", NUMBER);
9495
public static final IAttribute<IQuantity> SPAN_ID = attr("spanId", "spanId", "spanId", NUMBER);
9596

96-
public static final IAttribute<String> ATTR_1 = attr("attribute1", "", "", PLAIN_TEXT);
97-
public static final IAttribute<String> VALUE_1 = attr("value1", "", "", PLAIN_TEXT);
97+
public static final IAttribute<String> FOO = attr("foo", "", "", PLAIN_TEXT);
98+
public static final IAttribute<String> BAR = attr("bar", "", "", PLAIN_TEXT);
9899

99100
private MockWebServer profilingServer;
100101
private MockWebServer tracingServer;
@@ -516,25 +517,21 @@ private void assertRecordingEvents(
516517
IItemCollection executionSamples =
517518
events.apply(ItemFilters.type("datadog.ExecutionSample"));
518519
Set<Long> rootSpanIds = new HashSet<>();
519-
Set<String> tags = new HashSet<>();
520520
Set<String> values = new HashSet<>();
521521
for (IItemIterable executionSampleEvents : executionSamples) {
522522
IMemberAccessor<IQuantity, IItem> rootSpanIdAccessor =
523523
LOCAL_ROOT_SPAN_ID.getAccessor(executionSampleEvents.getType());
524-
IMemberAccessor<String, IItem> tagAttributeAccessor =
525-
ATTR_1.getAccessor(executionSampleEvents.getType());
526-
IMemberAccessor<String, IItem> tagValueAccessor =
527-
VALUE_1.getAccessor(executionSampleEvents.getType());
524+
IMemberAccessor<String, IItem> fooAccessor =
525+
FOO.getAccessor(executionSampleEvents.getType());
526+
IMemberAccessor<String, IItem> barAccessor =
527+
BAR.getAccessor(executionSampleEvents.getType());
528528
for (IItem executionSample : executionSampleEvents) {
529529
rootSpanIds.add(rootSpanIdAccessor.getMember(executionSample).longValue());
530-
String attribute = tagAttributeAccessor.getMember(executionSample);
531-
if (attribute != null) {
532-
tags.add(attribute);
533-
}
534-
String value = tagValueAccessor.getMember(executionSample);
535-
if (value != null) {
536-
values.add(value);
530+
String foo = fooAccessor.getMember(executionSample);
531+
if (foo != null) {
532+
values.add(foo);
537533
}
534+
assertNull(barAccessor.getMember(executionSample));
538535
}
539536
}
540537
int matches = 0;
@@ -548,8 +545,6 @@ private void assertRecordingEvents(
548545
}
549546
// we expect a rough correspondence between these events
550547
assertTrue(matches > 0);
551-
assertEquals(1, tags.size());
552-
assertEquals("foo", tags.iterator().next());
553548
assertFalse(values.isEmpty());
554549
for (String value : values) {
555550
assertTrue(value.startsWith("context"));
@@ -584,11 +579,6 @@ private void assertRecordingEvents(
584579
assertTrue(events.apply(ItemFilters.type("datadog.ProfilerSetting")).hasItems());
585580
}
586581

587-
private static String getStringParameter(
588-
final String name, final Multimap<String, Object> parameters) {
589-
return getParameter(name, String.class, parameters);
590-
}
591-
592582
private static <T> T getParameter(
593583
final String name, final Class<T> type, final Multimap<String, Object> parameters) {
594584
final List<?> vals = (List<?>) parameters.get(name);
@@ -672,7 +662,7 @@ private static ProcessBuilder createProcessBuilder(
672662
"-Ddd.profiling.upload.timeout=" + PROFILING_UPLOAD_TIMEOUT_SECONDS,
673663
"-Ddd.profiling.debug.dump_path=/tmp/dd-profiler",
674664
"-Ddatadog.slf4j.simpleLogger.defaultLogLevel=debug",
675-
"-Ddd.profiling.experimental.context.attributes=foo",
665+
"-Ddd.profiling.experimental.context.attributes=foo,bar",
676666
"-Dorg.slf4j.simpleLogger.defaultLogLevel=debug",
677667
"-XX:+IgnoreUnrecognizedVMOptions",
678668
"-XX:+UnlockCommercialFeatures",

dd-trace-api/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ excludedClassesCoverage += [
1515
'datadog.trace.api.TracePropagationStyle',
1616
'datadog.trace.api.SpanCorrelation*',
1717
'datadog.trace.api.interceptor.MutableSpan',
18-
'datadog.trace.api.experimental.ProfilingContext'
18+
'datadog.trace.api.experimental.ProfilingContext',
19+
'datadog.trace.api.experimental.ProfilingContext.NoOp'
1920
]
2021

2122
description = 'dd-trace-api'

dd-trace-api/src/main/java/datadog/trace/api/experimental/ProfilingContext.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,42 @@
22

33
import datadog.trace.api.GlobalTracer;
44
import datadog.trace.api.Tracer;
5+
import datadog.trace.api.internal.InternalTracer;
56

67
/** This class is experimental and is subject to change and may be removed. */
78
public interface ProfilingContext {
89

910
static ProfilingContext get() {
1011
Tracer tracer = GlobalTracer.get();
11-
if (tracer instanceof ProfilingContext) {
12-
return (ProfilingContext) tracer;
12+
if (tracer instanceof InternalTracer) {
13+
return ((InternalTracer) tracer).getProfilingContext();
1314
}
14-
return (attribute, value) -> {};
15+
return NoOp.INSTANCE;
1516
}
17+
1618
/**
1719
* Sets a context value to be appended to profiling data
1820
*
1921
* @param attribute the attribute (must have been registered at startup)
2022
* @param value the value
2123
*/
2224
void setContextValue(String attribute, String value);
25+
26+
/**
27+
* Clears a context value
28+
*
29+
* @param attribute the attribute (must have been registered at startup)
30+
*/
31+
void clearContextValue(String attribute);
32+
33+
final class NoOp implements ProfilingContext {
34+
35+
public static final NoOp INSTANCE = new NoOp();
36+
37+
@Override
38+
public void setContextValue(String attribute, String value) {}
39+
40+
@Override
41+
public void clearContextValue(String attribute) {}
42+
}
2343
}

dd-trace-api/src/main/java/datadog/trace/api/internal/InternalTracer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package datadog.trace.api.internal;
22

3+
import datadog.trace.api.experimental.ProfilingContext;
4+
35
/**
46
* Tracer internal features. Those features are not part of public API and can change or be removed
57
* at any time.
@@ -16,4 +18,6 @@ public interface InternalTracer {
1618
void flush();
1719

1820
void flushMetrics();
21+
22+
ProfilingContext getProfilingContext();
1923
}

dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import datadog.trace.api.StatsDClient;
2626
import datadog.trace.api.TracePropagationStyle;
2727
import datadog.trace.api.config.GeneralConfig;
28+
import datadog.trace.api.experimental.ProfilingContext;
2829
import datadog.trace.api.gateway.CallbackProvider;
2930
import datadog.trace.api.gateway.InstrumentationGateway;
3031
import datadog.trace.api.gateway.RequestContext;
@@ -210,11 +211,6 @@ public EndpointTracker onRootSpanStarted(AgentSpan root) {
210211
return endpointCheckpointer.onRootSpanStarted(root);
211212
}
212213

213-
@Override
214-
public void setContextValue(String attribute, String value) {
215-
profilingContextIntegration.setContextValue(attribute, value);
216-
}
217-
218214
public static class CoreTracerBuilder {
219215

220216
private Config config;
@@ -1041,6 +1037,11 @@ public void flushMetrics() {
10411037
}
10421038
}
10431039

1040+
@Override
1041+
public ProfilingContext getProfilingContext() {
1042+
return profilingContextIntegration;
1043+
}
1044+
10441045
private static StatsDClient createStatsDClient(final Config config) {
10451046
if (!config.isHealthMetricsEnabled()) {
10461047
return StatsDClient.NO_OP;

0 commit comments

Comments
 (0)