feat(tracer): Update the TagsList infrastructure to store int properties on ITags implementations - #8941
feat(tracer): Update the TagsList infrastructure to store int properties on ITags implementations#8941zacharycmontoya wants to merge 12 commits into
int properties on ITags implementations#8941Conversation
…Nullable<int> type, in addition to string type. This also includes updating classes that implement IItemProcessor<string> to also implement IItemProcessor<int>. Various types include SpanMessagePackFormatter.TagWriter classes, OtlpMapper.TagWriter, TruncatorTagsProcessor, and TraceFilter
…lers of its getters/setters
…on methods: - int? GetHttpStatusCode - string GetRawHttpStatusCodeString
…rmalizerTraceProcessor)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e5a63d155
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8941) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard. Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph). Duration chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (74ms) : 69, 79
master - mean (72ms) : 69, 75
section Bailout
This PR (8941) - mean (76ms) : 74, 78
master - mean (81ms) : 73, 89
section CallTarget+Inlining+NGEN
This PR (8941) - mean (1,099ms) : 1046, 1152
master - mean (1,096ms) : 1052, 1141
FakeDbCommand (.NET Core 3.1)gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (113ms) : 106, 120
master - mean (115ms) : 108, 121
section Bailout
This PR (8941) - mean (112ms) : 109, 114
master - mean (115ms) : 108, 122
section CallTarget+Inlining+NGEN
This PR (8941) - mean (792ms) : 771, 813
master - mean (785ms) : 763, 807
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (99ms) : 94, 104
master - mean (103ms) : 97, 109
section Bailout
This PR (8941) - mean (100ms) : 96, 104
master - mean (99ms) : 96, 103
section CallTarget+Inlining+NGEN
This PR (8941) - mean (955ms) : 915, 994
master - mean (950ms) : 901, 999
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (100ms) : 95, 106
master - mean (98ms) : 92, 105
section Bailout
This PR (8941) - mean (98ms) : 96, 100
master - mean (102ms) : 96, 108
section CallTarget+Inlining+NGEN
This PR (8941) - mean (828ms) : 788, 868
master - mean (822ms) : 782, 862
HttpMessageHandler (.NET Framework 4.8)gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (212ms) : 205, 218
master - mean (211ms) : 205, 217
section Bailout
This PR (8941) - mean (216ms) : 212, 220
master - mean (215ms) : 211, 219
section CallTarget+Inlining+NGEN
This PR (8941) - mean (1,271ms) : 1225, 1316
master - mean (1,268ms) : 1214, 1321
HttpMessageHandler (.NET Core 3.1)gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (304ms) : 295, 313
master - mean (303ms) : 294, 312
section Bailout
This PR (8941) - mean (307ms) : 300, 313
master - mean (305ms) : 295, 315
section CallTarget+Inlining+NGEN
This PR (8941) - mean (1,012ms) : 983, 1041
master - mean (1,009ms) : 984, 1035
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (295ms) : 289, 302
master - mean (298ms) : 291, 305
section Bailout
This PR (8941) - mean (297ms) : 292, 303
master - mean (297ms) : 291, 303
section CallTarget+Inlining+NGEN
This PR (8941) - mean (1,196ms) : 1167, 1225
master - mean (1,200ms) : 1160, 1239
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8941) - mean (298ms) : 292, 304
master - mean (300ms) : 294, 306
section Bailout
This PR (8941) - mean (299ms) : 291, 307
master - mean (301ms) : 293, 308
section CallTarget+Inlining+NGEN
This PR (8941) - mean (1,080ms) : 1023, 1137
master - mean (1,094ms) : 989, 1199
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BenchmarksBenchmark execution time: 2026-07-31 18:09:10 Comparing candidate commit bb1a249 in PR branch Found 0 performance improvements and 1 performance regressions! Performance is the same for 71 metrics, 0 unstable metrics, 66 known flaky benchmarks, 60 flaky benchmarks without significant changes.
|
andrewlock
left a comment
There was a problem hiding this comment.
Looking good to me - a couple of minor questions etc and the AI flagged a couple of genuine bugs I think, but otherwise LGTM
| { | ||
| if (item.SerializedKey.IsEmpty) | ||
| { | ||
| _formatter.WriteTag(ref Bytes, ref Offset, item.Key, item.Value.ToString(System.Globalization.CultureInfo.InvariantCulture), _tagProcessors); |
There was a problem hiding this comment.
I wonder if there's a more efficient API we could use here to avoid the extra ToString() 🤔 Not a problem if not or if it's too much hassle, just wondering out loud
There was a problem hiding this comment.
See 7754485 for a Datadog.Trace.Util.IntStringCache solution
There was a problem hiding this comment.
Ah, interesting, I was thinking of an API that wrote the int directly to bytes instead of going through the intermediate string 🤔 I'm pretty sure .NET (at least newer versions) already has something similar for small (<10) ints baked into the runtime. Seems reasonable to me, though I guess it could well be a case of premature optimization on our part 🤷♂️
|
|
||
| foreach (var span in spans) | ||
| { | ||
| // TODO: This lookup may also need to lookup the OTel http.response.status_code |
There was a problem hiding this comment.
Is it worth extracting this lookup to a helper in TestHelpers now for this, so you only have to update that helper later when adding support for OTel semantics instead of touching all these test files again?
There was a problem hiding this comment.
I added a helper that mimics SpanExtensions.GetHttpStatusCode in ea95be7. It might be confusing that it returns a string rather than an int? but I think it's ok for now?
There was a problem hiding this comment.
Could rename it to SpanExtensions.GetHttpStatusCodeAsString() if you want to disambiguate 🙂 or SpanExtensions.GetHttpStatusCodeTag()?
There was a problem hiding this comment.
In the next PR I've renamed this to SpanExtensions.GetHttpStatusCodeString 😅
… is either null or cannot be parsed.
…Code tag retrieval, similar to SpanExtensions.GetHttpStatusCode
…are handled the same as string Tags
…resentation of tags backed by int values. This change affects: - SpanMessagePackFormatter serializing an int value - TraceFilter applying to an int value - Setting a status code as a string tag in SpanExtensions.SetHttpStatusCode - The SetTag(string key) implementation emitted by the TagsListGenerator
…s code for invalid status codes
bouwkast
left a comment
There was a problem hiding this comment.
LGTM just a question on how it works with a manual span (assuming someone sets the status code tag)
Which I think was discussed but I forget 😅
| } | ||
| } | ||
|
|
||
| _writeKeyValue(ref State, new KeyValue(key, value)); |
There was a problem hiding this comment.
I think we discussed this (maybe) but how does this interact exactly if the tag came from a manual span? I think this will properly get the autoinstrumentation tag to be the int, but I think if we have a manual span that it will potentially still be a string?
There was a problem hiding this comment.
The manual span doesn't get this because only the internal Tracer.StartActiveInternal API allows passing in an instance of ITags. When there's no specified ITags instance, the Span constructor creates a TagsList instance, which does not have a field for the well-known status code tag. We could move it up to there since it is such an important tag! But I opted not to for this PR. What's your thought on that?
There was a problem hiding this comment.
I think we can just leave it as is thanks!
Summary of changes
Updates the TagsListGenerator and code analyzers to allow ITags implementations to specify a
TagAttributewith aintproperty, in addition to the existingstringproperty support. This allows us to maintain the originalintprimitive so in the future we can emitintprimitives in our tracing protocols, such as OTLP.To ensure that all of the code generation and serialization are implemented correctly, this PR also migrates the
http.status_codetag to this new feature.Reason for change
We want to support emitting spans that align with OpenTelemetry semantic conventions. Since span attributes may be specified as integers in the OpenTelemetry spec, we need a mechanism for storing and emitting integers tags. This mechanism allows our internal integrations to do that by storing a backing
int?property for those concepts so they can be emitted as integers when emitting OTLP.Implementation details
TagsListGenerator changes
int?properties are now supported with the following details:GetTag(string key)now callsvalue?.ToString(System.Globalization.CultureInfo.InvariantCulture)forintpropertiesSetTag(string key)now callsint.TryParse(value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out var intValue)to convert the input string forintproperties. If the conversion fails or the input was null, the tag is unsetEnumerateTags<TProcessor>(ref TProcessor processor)now emits the key-value pair as aTagItem<int>so consumers can customize how they handle integer tagsITags changes
ITags.EnumerateTags<TProcessor>(ref TProcessor processor)to requireTProcessorarguments to implementIItemProcessor<int>. Affected classes includeSpanMessagePackFormatter.TagWriterOtlpMapper.TagWriterTraceFilter.RegexTagFilterProcessorTruncatorTagsProcessorHTTP status code updates
IHasStatusCodeinterface to require aint? HttpStatusCodepropertyHttpStatusCodeproperties to typeint?for the following classes:AwsSdkTagsHttpTagsInferredProxyTagsWebTagsSpan.GetTag(Tags.HttpStatusCode)with a call to a new extension methodSpan.GetHttpStatusCode()that directly returns anint?. This affects stats aggregators (which build stats aggregation keys), the NormalizerTraceProcessor (only runs during client-side stats to validate status code tags) and API Security.Tags.HttpStatusCode(i.e. "http.status_code") so we do not lose track of them when introducing HTTP semanticsTest coverage
To test the code generator, unit tests have been added
TagsListGeneratorTests.cs.The existing HTTP and OpenTelemetry SDK integration tests will exercise the updated TagsList implementation by emitting the same tracing data over DD MsgPack and OTLP as before.
Other details
N/A