Skip to content

Commit 8fbdc86

Browse files
dougqhdevflow.devflow-routing-intake
andauthored
Reuse TagMap.Entry objects in BaseDecorator (#10501)
Updating tests to account for API changes Adding tagIterator and valueIterator Adding checks for EntryIterator Removing EntryIterator and EntryChangeIterator EntryIterator and EntryChangeIterator are arguably redundant spotless Merge branch 'master' into dougqh/tagmap-entryreader Refining handling of primitive types Fixed bug TagValueConversions.toBoolean Could cause LegacyTagMap.EntryReader to produce incorrect answers to some queries For simplicity, now treating Byte and Short as Integer. That will make calling code doing primitive handling simpler. Fleshing out tests -- more tests to come Refining comment in toBoolean Adding more TagValueConversionTest-s Coverage for byte, short, float, and double Adding Entry tests for byte and short boxes spotless Merge branch 'master' into dougqh/tagmap-entryreader Merge branch 'master' into dougqh/tagmap-entryreader Direct TagMap.Entry support in AgentSpan / DDSpan Adding methods to AgentSpan / DDSpan that take TagMap.Entry/Reader objects directly This will enable TagMap.Entry reuse which can reduce memory allocation/GC pressure Adding public create methods to TagMap.Entry Methods are intended to be used to create TagMap.Entry objects for repeatedly used values Overloads are provided for all the supported types to be easier for developers not familiar with TagMap internals. Internally, TagMap still uses the more explicit new<X>Entry methods. spotless Merge branch 'master' into dougqh/fdirect-apis-for-tagmap-entry Fixed merge Removing statics that were previously moved to TagValueConversions Clarifying comments Adding tests for TagMap.Entry.create - tests exposed missing TagMap.Entry.create for boolean - added explanatory strings to some asserts spotless Comments Merge branch 'master' into dougqh/fdirect-apis-for-tagmap-entry Adding test for TagMap.Entry setters Merge branch 'dougqh/fdirect-apis-for-tagmap-entry' of github.com:DataDog/dd-trace-java into dougqh/fdirect-apis-for-tagmap-entry Adding missing import spotless Groovy codeNarc Merge branch 'master' into dougqh/fdirect-apis-for-tagmap-entry Reusing entries for analytics sample rate & component spotless For clarity, adding an explicit initial set to null Reduced visibility of cachedComponentEntry Doesn't need to be visible to children If any child needs the componentEntry, they can call the method instead Merge branch 'master' into dougqh/basedecorator-entry-reuse Taking advantage of null handling in setMetric to simplify code Merge branch 'dougqh/basedecorator-entry-reuse' of github.com:DataDog/dd-trace-java into dougqh/basedecorator-entry-reuse Clarifying comment & spotless Simplifying approach - just use final field in constructor Merge branch 'master' into dougqh/basedecorator-entry-reuse Merge branch 'master' into dougqh/basedecorator-entry-reuse spotless Merge branch 'dougqh/basedecorator-entry-reuse' of github.com:DataDog/dd-trace-java into dougqh/basedecorator-entry-reuse Merge branch 'master' into dougqh/basedecorator-entry-reuse Fixing tests Code is now calling setTag(TagMap.Entry) or setMetric(TagMap.Entry) Since these tests use mocks rather than checking span contents, I had to update them to account for the change Merge branch 'dougqh/basedecorator-entry-reuse' of github.com:DataDog/dd-trace-java into dougqh/basedecorator-entry-reuse Fixing ordering issue introduced by moving setting into constructor spotless Reverting to the lazy caching approach Adding comment to explain the approach taken Reverting field order This file no longer needs to change with the caching approach, and this serves as a useful test that the behavior hasn't been altered Merge branch 'master' into dougqh/basedecorator-entry-reuse Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
1 parent 19de0d9 commit 8fbdc86

6 files changed

Lines changed: 69 additions & 15 deletions

File tree

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/BaseDecorator.java

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datadog.trace.api.Config;
88
import datadog.trace.api.DDTags;
99
import datadog.trace.api.Functions;
10+
import datadog.trace.api.TagMap;
1011
import datadog.trace.api.cache.QualifiedClassNameCache;
1112
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
1213
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
@@ -40,17 +41,29 @@ public String apply(Class<?> clazz) {
4041
Functions.PrefixJoin.of("."));
4142

4243
protected final boolean traceAnalyticsEnabled;
43-
protected final Double traceAnalyticsSampleRate;
44+
protected final double traceAnalyticsSampleRate;
45+
46+
private final TagMap.Entry traceAnalyticsEntry;
47+
48+
// Deliberately not volatile, reading null and repeating the calculation is safe
49+
private TagMap.Entry cachedComponentEntry = null;
4450

4551
protected BaseDecorator() {
4652
final Config config = Config.get();
4753
final String[] instrumentationNames = instrumentationNames();
54+
4855
this.traceAnalyticsEnabled =
4956
instrumentationNames.length > 0
5057
&& config.isTraceAnalyticsIntegrationEnabled(
5158
traceAnalyticsDefault(), instrumentationNames);
59+
5260
this.traceAnalyticsSampleRate =
5361
(double) config.getInstrumentationAnalyticsSampleRate(instrumentationNames);
62+
63+
this.traceAnalyticsEntry =
64+
this.traceAnalyticsEnabled
65+
? TagMap.Entry.create(DDTags.ANALYTICS_SAMPLE_RATE, traceAnalyticsSampleRate)
66+
: null;
5467
}
5568

5669
protected abstract String[] instrumentationNames();
@@ -59,6 +72,20 @@ protected BaseDecorator() {
5972

6073
protected abstract CharSequence component();
6174

75+
/** Caches the component TagMap.Entry, so it isn't recreated for every trace */
76+
protected final TagMap.Entry componentEntry() {
77+
// DQH = Tried calling component() in the constructor, but that had issues with static
78+
// field ordering. That was caught be an integration test, but I didn't want to risk
79+
// breaking other integrations where the test is not as thorough.
80+
81+
// This approach while more complicated doesn't have any field initialization ordering issues.
82+
TagMap.Entry componentEntry = cachedComponentEntry;
83+
if (componentEntry == null) {
84+
cachedComponentEntry = componentEntry = TagMap.Entry.create(Tags.COMPONENT, component());
85+
}
86+
return componentEntry;
87+
}
88+
6289
protected boolean traceAnalyticsDefault() {
6390
return false;
6491
}
@@ -67,12 +94,17 @@ public AgentSpan afterStart(final AgentSpan span) {
6794
if (spanType() != null) {
6895
span.setSpanType(spanType());
6996
}
97+
98+
span.setTag(componentEntry());
99+
100+
// DQH - Could retrieve the value from componentEntry and cast to avoid the virtual call,
101+
// unclear which option is better here
70102
final CharSequence component = component();
71-
span.setTag(Tags.COMPONENT, component);
72103
span.context().setIntegrationName(component);
73-
if (traceAnalyticsEnabled) {
74-
span.setMetric(DDTags.ANALYTICS_SAMPLE_RATE, traceAnalyticsSampleRate);
75-
}
104+
105+
// null handled by setMetric
106+
span.setMetric(traceAnalyticsEntry);
107+
76108
return span;
77109
}
78110

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/BaseDecoratorTest.groovy

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package datadog.trace.bootstrap.instrumentation.decorator
22

3-
3+
import datadog.trace.api.TagMap
44
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
55
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext
66
import datadog.trace.bootstrap.instrumentation.api.ErrorPriorities
@@ -25,11 +25,13 @@ class BaseDecoratorTest extends DDSpecification {
2525

2626
then:
2727
1 * span.setSpanType(decorator.spanType())
28-
1 * span.setTag(Tags.COMPONENT, "test-component")
28+
1 * span.setTag(TagMap.Entry.create(Tags.COMPONENT, "test-component"))
2929
1 * span.context() >> spanContext
3030
1 * spanContext.setIntegrationName("test-component")
31+
_ * span.setTag(_)
3132
_ * span.setTag(_, _) // Want to allow other calls from child implementations.
3233
_ * span.setMeasured(true)
34+
_ * span.setMetric(_)
3335
_ * span.setMetric(_, _)
3436
_ * span.setServiceName(_, _)
3537
_ * span.setOperationName(_)

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/ClientDecoratorTest.groovy

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.bootstrap.instrumentation.decorator
22

33
import datadog.trace.api.DDTags
4+
import datadog.trace.api.TagMap
45
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
56
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext
67
import datadog.trace.bootstrap.instrumentation.api.Tags
@@ -22,12 +23,13 @@ class ClientDecoratorTest extends BaseDecoratorTest {
2223
1 * span.setServiceName(serviceName, "test-component")
2324
}
2425
1 * span.setMeasured(true)
25-
1 * span.setTag(Tags.COMPONENT, "test-component")
26+
1 * span.setTag(TagMap.Entry.create(Tags.COMPONENT, "test-component"))
2627
1 * span.context() >> spanContext
2728
1 * spanContext.setIntegrationName("test-component")
2829
1 * span.setTag(Tags.SPAN_KIND, "client")
2930
1 * span.setSpanType(decorator.spanType())
30-
1 * span.setMetric(DDTags.ANALYTICS_SAMPLE_RATE, 1.0)
31+
1 * span.setMetric(TagMap.Entry.create(DDTags.ANALYTICS_SAMPLE_RATE, 1.0))
32+
_ * span.setTag(_)
3133
_ * span.setTag(_, _) // Want to allow other calls from child implementations.
3234
_ * span.setServiceName(_)
3335
_ * span.setOperationName(_)

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/DatabaseClientDecoratorTest.groovy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.bootstrap.instrumentation.decorator
22

33
import datadog.trace.api.DDTags
4+
import datadog.trace.api.TagMap
45
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
56
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext
67
import datadog.trace.bootstrap.instrumentation.api.Tags
@@ -26,12 +27,12 @@ class DatabaseClientDecoratorTest extends ClientDecoratorTest {
2627
1 * span.setServiceName(serviceName, "test-component")
2728
}
2829
1 * span.setMeasured(true)
29-
1 * span.setTag(Tags.COMPONENT, "test-component")
30+
1 * span.setTag(TagMap.Entry.create(Tags.COMPONENT, "test-component"))
3031
1 * span.context() >> spanContext
3132
1 * spanContext.setIntegrationName("test-component")
3233
1 * span.setTag(Tags.SPAN_KIND, "client")
3334
1 * span.setSpanType("test-type")
34-
1 * span.setMetric(DDTags.ANALYTICS_SAMPLE_RATE, 1.0)
35+
1 * span.setMetric(TagMap.Entry.create(DDTags.ANALYTICS_SAMPLE_RATE, 1.0))
3536
0 * _
3637

3738
where:

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/ServerDecoratorTest.groovy

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package datadog.trace.bootstrap.instrumentation.decorator
22

3-
3+
import datadog.trace.api.TagMap
44
import datadog.trace.bootstrap.instrumentation.api.AgentSpan
55
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext
66

@@ -23,13 +23,15 @@ class ServerDecoratorTest extends BaseDecoratorTest {
2323

2424
then:
2525
1 * span.setTag(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE)
26-
1 * span.setTag(COMPONENT, "test-component")
26+
1 * span.setTag(TagMap.Entry.create(COMPONENT, "test-component"))
2727
1 * span.context() >> spanContext
2828
1 * spanContext.setIntegrationName("test-component")
2929
1 * span.setTag(SPAN_KIND, "server")
3030
1 * span.setSpanType(decorator.spanType())
3131
if (decorator.traceAnalyticsEnabled) {
32-
1 * span.setMetric(ANALYTICS_SAMPLE_RATE, 1.0)
32+
1 * span.setMetric(TagMap.Entry.create(ANALYTICS_SAMPLE_RATE, 1.0))
33+
} else {
34+
1 * span.setMetric(null)
3335
}
3436
0 * _
3537
}

internal-api/src/test/java/datadog/trace/api/TagMapEntryTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void createBoolean(boolean value) {
155155
@ValueSource(booleans = {false, true})
156156
public void newBooleanEntry(boolean value) {
157157
test(
158-
() -> TagMap.Entry.newBooleanEntry("foo", value),
158+
() -> TagMap.Entry.create("foo", value),
159159
TagMap.Entry.BOOLEAN,
160160
(entry) ->
161161
multiCheck(
@@ -498,6 +498,21 @@ public void createDouble(double value) {
498498

499499
@ParameterizedTest
500500
@DisplayName("newDoubleEntry: double")
501+
@ValueSource(
502+
doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE})
503+
public void doubleEntry_via_create(double value) {
504+
test(
505+
() -> TagMap.Entry.create("foo", value),
506+
TagMap.Entry.DOUBLE,
507+
(entry) ->
508+
multiCheck(
509+
checkKey("foo", entry),
510+
checkValue(value, entry),
511+
checkIsNumericPrimitive(entry),
512+
checkType(TagMap.Entry.DOUBLE, entry)));
513+
}
514+
515+
@ParameterizedTest
501516
@ValueSource(
502517
doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE})
503518
public void doubleEntry(double value) {

0 commit comments

Comments
 (0)