Tags: DataDog/dd-trace-dotnet
Tags
[Tests] Handle UTF-16 output from ProcDump v12.01 (#8890) ## Summary of changes Normalize ProcDump output before evaluating its startup and shutdown messages. ## Reason for change Windows x64 integration tests started hanging after the unversioned Microsoft download began serving ProcDump v12.01. The test harness: 1. Starts the instrumented process in a suspended state. 2. Attaches ProcDump. 3. Waits for ProcDump’s readiness message. 4. Resumes the instrumented process. ProcDump v12.01 emits redirected output as UTF-16. The test helper read this with embedded null characters, such as `P\0r\0e\0s\0s...`. Consequently, the exact readiness-message comparison failed and the instrumented process remained suspended indefinitely. The same encoding change prevented the helper from recognizing the normal `"Dump count not reached"` shutdown message. It therefore treated normal shutdown as abnormal and logged ProcDump’s entire buffered exception history. This primarily affected x64 tests because ProcDump crash monitoring is disabled for x86 tests. ## Implementation details - Remove embedded null characters before comparing ProcDump’s readiness message. - Normalize buffered stdout and stderr after ProcDump exits. - Use normalized stdout for readiness and dump-count checks. - Log normalized output only when a dump occurred or ProcDump exited unexpectedly. Output from older ProcDump versions is unchanged because removing null characters is a no-op. ## Test coverage Tested locally with: `Datadog.Trace.Security.IntegrationTests.AspNetCore5BlockingTemplatesJson.TestGet` - **ProcDump v12.0 with the original code:** Passed without excessive ProcDump logging. - **ProcDump v12.01 with the original code:** Reproduced the hang. ProcDump attached successfully, but the target remained suspended with one thread and zero CPU. - **ProcDump v12.01 with this change:** Passed without logging the full ProcDump exception buffer. ## Other details This only changes test infrastructure behavior. Crash-dump monitoring remains enabled, and this change does not pin a ProcDump version. #incident-57303 <!-- Fixes #{issue} --> <!--⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. -->
[CI] Add net10.0 to AWS Lambda test runtimes (#8819) ## Summary of changes Add `net10.0` to the .NET TFMs used in AWS Lambda tests. ## Reason for change We support .NET 10, so the AWS Lambda tests should run against it. ## Implementation details - add a `net10` matrix entry (`net10.0` TFM, `public.ecr.aws/lambda/dotnet:10` base image) to the AWS Lambda test stage in `ultimate-pipeline.yml` - existing `net6`/`net7`/`net8`/`net9` entries are unchanged ## Test coverage This PR adds a runtime version that the existing AWS Lambda tests run on. ## Other details <!-- Fixes #{issue} --> n/a > *"net6 and net7 walked back in like they forgot their keys. We let them stay and gave net10 the spare bedroom."* — Claude 🤖 <!--⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. -->
[Debugger] Avoid instantiating state machine attributes (#8816) ## Summary of changes - Add a debugger helper that reads compiler state-machine attributes through `CustomAttributeData` instead of constructing attribute instances. - Use the helper in exception replay method matching, async kickoff method lookup, fully-qualified method name resolution, and ILAnalyzer async `MoveNext` selection. - Add regression coverage for overloaded async method matching with a custom method attribute whose constructor must not run. ## Reason for change Debugger state-machine resolution only needs compiler metadata such as `AsyncStateMachineAttribute`, `IteratorStateMachineAttribute`, and `AsyncIteratorStateMachineAttribute`. Instantiating attributes can execute user attribute constructors, so these resolution paths should stay metadata-only. ## Implementation details The helper compares attribute type full names and reads the state-machine type from `CustomAttributeData.ConstructorArguments`. It preserves the previous async/iterator behavior, including marking iterator and async-iterator state machines so `GetFullyQualifiedName()` still appends the `+MoveNext()` annotation where expected. ## Test coverage - `MethodMatcherTests|ILAnalyzerTests` --------- Co-authored-by: Cursor <cursoragent@cursor.com>
[Profiler] Improve memory consumption `LibrariesInfoCache` (#8777) ## Summary of changes Improve memory overhead of the `LibrariesCacheInfo`. ## Reason for change `LibrariesCacheInfo` component caches ELF symbols to improve stack walking. But this comes at a cost CPU + Memory. Today (master) ``` [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] LibrariesInfoCache stats: [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Cache reloads: 10 [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Total CPU (worker): 42 ms [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Libraries in cache: 21 [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Module regions: 18 [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Symbol entries: 27179 [2026-06-11 10:58:49.687 | info | PId: 140997 | TId: 140997] Memory current: 1410520 bytes ``` We can see a 42ms CPU usage and 1.4MB memory usage for 27179 symbols. 42ms of CPU over the lifetime of the application is totally negligible, but 1.4MB leaves a mark. This PR does 2 improvements: - Replace std::function Deleters - Compact FuncEntry for ARM64 With this PR ``` [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] LibrariesInfoCache stats: [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Cache reloads: 13 [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Total CPU (worker): 57 ms [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Libraries in cache: 21 [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Module regions: 18 [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Symbol entries: 27179 [2026-06-11 07:53:01.910 | info | PId: 20347 | TId: 20347] Memory current: 565528 bytes ``` ## Implementation details - Replace std::unique_ptr<T, std::function<void(void*)>> with a trivial deleter struct `PmrDeleter` - Store function entries relative to their module base: Works because: modules are always < 4GB (shared libraries mapped within 32-bit offset range from their base) ## Test coverage ## Other details <!-- Fixes #{issue} --> <!--⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. -->
[Opentelemetry] Prevent OTLP array attribute stack overflow on cyclic… …/deep arrays (#8707) ## Summary of changes Both OTLP trace serializers (`OtlpTracesProtobufSerializer` and `OtlpTracesJsonSerializer`) now serialize each `AnyValue` array element by calling `WriteAnyValue` with `expandArrays: false` instead of recursing with array expansion enabled. Adds regression tests covering self-referential, deeply nested, nested `object[]`, and nested `byte[]` inputs in both serializers. ## Reason for change `WriteAnyValue` takes a new `bool expandArrays` parameter (default `true`). When `false` — the value passed for each array element — the `byte[]` and `Array` cases `goto default;` and stringify via `Convert.ToString(value, CultureInfo.InvariantCulture)` instead of recursing. This caps recursion depth at 1 by construction (no cycle tracker or depth limit needed) and mirrors OTel .NET SDK's [`TagWriter.WriteToArrayTypeChecked`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/Shared/TagWriter/TagWriter.cs), whose per-element writer also has no `byte[]`/`Array` case. Top-level dispatch is unchanged, so only nested-array semantics shift and the shift aligns dd-trace's output with the OTel SDK. Also splits `ulong` out of the JSON integer cases so it stringifies (it overflows OTLP `intValue`/int64), matching the protobuf serializer and the OTel SDK. ## Implementation details `WriteAnyValue` takes a new `bool expandArrays` parameter (default `true`). When `false` — the value passed for each array element — the `byte[]` and `Array` cases `goto default;` and stringify via `Convert.ToString(value, CultureInfo.InvariantCulture)` instead of recursing. This caps recursion depth at 1 by construction (no cycle tracker or depth limit needed) and mirrors OTel .NET SDK's [`TagWriter.WriteToArrayTypeChecked`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/Shared/TagWriter/TagWriter.cs), whose per-element writer also has no `byte[]`/`Array` case. Top-level dispatch is unchanged, so only nested-array semantics shift and the shift aligns dd-trace's output with the OTel SDK. Also splits `ulong` out of the JSON integer cases so it stringifies (it overflows OTLP `intValue`/int64), matching the protobuf serializer and the OTel SDK. ## Test coverage Four regression tests per serializer: `SelfReferentialObjectArray_IsBoundedAtOneLevel` (`a[0] = a` no longer recurses), `DeeplyNestedArray_IsBoundedAtOneLevel` (5 000-deep array serializes in constant stack), `NestedObjectArray_StringifiesInsteadOfArrayValue`, and `NestedByteArray_StringifiesInsteadOfBytesValue`, plus a JSON `WriteAnyValue_Ulong_EmitsStringValue` test for the `ulong` change. All existing flat-array tests and the `OpenTelemetrySdkTests.SubmitsOtlpTraces` integration test pass unchanged.
[Debugger] Fix Timer leaks and missing rate updates in probe rate lim… …iter (#8619) ## Summary of changes Fixes Timer/sampler leaks and a latent rate-update bug in `ProbeRateLimiter` and `AdaptiveSampler`. `AdaptiveSampler` allocates a `System.Threading.Timer` that the runtime roots until disposed; three code paths previously dropped samplers without disposing them, leaking one Timer (plus captured state) on every probe removal and on every dictionary insert race. Separately, RCM-driven rate updates were silently ignored when a sampler already existed. ## Reason for change - Long-running services using Dynamic Instrumentation accumulate `Timer` instances on every RCM probe rotation — unbounded growth over the process lifetime. - Line probes that go through the unbound → bound transition could end up stuck at the default rate of 1 because `CheckUnboundProbes` registered the sampler **after** making the IL live, opening a race window where the first probe hit inserts a default-rate sampler and the configured rate is then dropped by `SetRate`. ## Implementation details - `IAdaptiveSampler` extends `IDisposable`; `AdaptiveSampler.Dispose` releases the internal `Timer`; `NopAdaptiveSampler.Dispose` is a no-op (singleton). - `AdaptiveSampler.SetRate` mutates `_samplesPerWindow` / `_samplesBudget` in place. Uses the same relaxed memory semantics as the rest of the class. - `ProbeRateLimiter.GerOrAddSampler` uses `TryGetValue` → `TryAdd` → `Dispose-on-lose` instead of `ConcurrentDictionary.GetOrAdd`, which can invoke its factory multiple times. - `ProbeRateLimiter.SetRate` applies the new rate to the existing sampler instead of logging and returning; disposes the candidate if it loses the insert race. - `ProbeRateLimiter.ResetRate` disposes the removed sampler. - `DynamicInstrumentation.CheckUnboundProbes` now registers samplers and processors **before** calling `DebuggerNativeMethods.InstrumentProbes`, matching the ordering in `InstrumentAddedProbes` and closing the race at its source. ## Test coverage - `AdaptiveSamplerTests` — `SetRate` updates budget and preserves running stats; `Dispose` is idempotent. - `ProbeRateLimiterTests` (new) — `SetRate` updates the existing sampler in place; `ResetRate` disposes the removed sampler; `GerOrAddSampler` does not dispose existing entries. --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Apply baggage limits on extract (#8555) ## Summary of changes Honor `DD_TRACE_BAGGAGE_MAX_ITEMS` and `DD_TRACE_BAGGAGE_MAX_BYTES` when parsing inbound baggage headers ## Reason for change ## Implementation details ## Test coverage Added unit tests for it. ## Other details <!-- Fixes #{issue} --> <!--⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. -->
[Test Package Versions Bump] Updating package versions (#8441) Updates the package versions for integration tests. ## Package Version Cooldown Report The following versions were published less than **2 days** ago and have been overridden. These require manual review before inclusion. | Package | Integration | Overridden Version | Published | Age (days) | Using Instead | |---------|-------------|--------------------|-----------|------------|---------------| | Quartz | Quartz | 3.18.0 | 2026-04-11 | 0 | 3.17.1 | | AWSSDK.Core | AwsSdk | 4.0.3.29 | 2026-04-10 | 1 | 4.0.3.28 | | AWSSDK.DynamoDBv2 | AwsDynamoDb | 4.0.17.8 | 2026-04-10 | 1 | 4.0.17.7 | | AWSSDK.Kinesis | AwsKinesis | 4.0.8.11 | 2026-04-10 | 1 | 4.0.8.10 | | AWSSDK.SQS | AwsSqs | 4.0.2.25 | 2026-04-10 | 1 | 4.0.2.24 | | AWSSDK.SimpleNotificationService | AwsSns | 4.0.2.27 | 2026-04-10 | 1 | 4.0.2.26 | | AWSSDK.EventBridge | AwsEventBridge | 4.0.5.26 | 2026-04-10 | 1 | 4.0.5.25 | | AWSSDK.S3 | AwsS3 | 4.0.21.1 | 2026-04-10 | 1 | 4.0.21 | | AWSSDK.StepFunctions | AwsStepFunctions | 4.0.2.20 | 2026-04-10 | 1 | 4.0.2.19 | | HotChocolate.AspNetCore | HotChocolate | 15.1.14 | 2026-04-10 | 1 | 15.1.13 | | Selenium.WebDriver | Selenium | 4.43.0 | 2026-04-10 | 1 | 4.42.0 | --------- Co-authored-by: bouwkast <8877527+bouwkast@users.noreply.github.com> Co-authored-by: Andrew Lock <andrew.lock@datadoghq.com>
maybe fix macos smoketests (#8413) ## Summary of changes ## Reason for change ## Implementation details ## Test coverage ## Other details <!-- Fixes #{issue} --> <!--⚠️ Note: Where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. MergeQueue is NOT enabled in this repository. If you have write access to the repo, the PR has 1-2 approvals (see above), and all of the required checks have passed, you can use the Squash and Merge button to merge the PR. If you don't have write access, or you need help, reach out in the #apm-dotnet channel in Slack. -->
Support adding kafka_cluster_id for Confluent.Kafka (#7702) ## Summary of changes - Adds kafka_cluster_id as a tag for APM Spans and DSM checkpoints/offsets. (Note that **DSM is enabled by default**). Without this, we cannot differentiate between reported offsets on the same topic but across different clusters, which leads us to wildly incorrect metric values. (For example, a prod cluster with consume/produce offsets at 1000,1001 should have an offset lag of 1. If there is also a matching dev cluster with offsets at 0 and 1, then we can calculate the offset lag as 1000). - In most tracer libraries (python, java, node) we support tracking `kafka_cluster_id`. Without this, metrics become incorrect when there are the same topics across different clusters (i.e. dev/prod environments). - It's available for Confluent.Kafka 2.3.0 and above only - roughly half of orgs that use this library according to telemetry. (For DSM where this is most useful, we can add a recommendation to our docs to use this version or above.) **Note:** I drafted an alternative approach calling librdkafka directly [here](#8264). That gives the cluster id without any external API call or version dependency (It's available and unchanged from librdkafka 1.0.0), but calls into unmanaged code ## Reason for change This functionality exists in other tracers: 1. Java (doesn't block, intercepts the metadata response to enrich cluster id going forwards, see [here](https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/instrumentation/kafka/kafka-clients-3.8/src/main/java17/datadog/trace/instrumentation/kafka_clients38/ProducerAdvice.java#L44) and [here](https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/instrumentation/kafka/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/MetadataInstrumentation.java#L82)) 2. Node (blocks, see [here](https://github.com/DataDog/dd-trace-js/blob/master/packages/datadog-instrumentations/src/kafkajs.js#L234) and [here](https://github.com/DataDog/dd-trace-py/blob/main/ddtrace/contrib/internal/kafka/patch.py#L183)) 3. Python (blocks with a 1 second timeout, see [here](https://github.com/DataDog/dd-trace-py/blob/main/ddtrace/contrib/internal/kafka/patch.py#L360) and [here](https://github.com/DataDog/dd-trace-py/blob/main/ddtrace/contrib/internal/kafka/patch.py#L183)) ## Implementation details Constructs the Kafka Admin API client and queries for the cluster id directly on consumer/producer startup. We cache this by bootstrap servers, so we expect to make this API call once. ## Test coverage ## Other details These DSM metrics will now tag by kafka_cluster_id <img width="2412" height="1070" alt="Screenshot 2026-02-25 at 12 42 00 pm" src="https://github.com/user-attachments/assets/416091c6-9b9b-4f90-aea1-fa4735b21df8" /> Added to spans (I checked this on produce too, I just don't have a screenshot of it) <img width="889" height="809" alt="Screenshot 2026-02-24 at 5 21 59 pm" src="https://github.com/user-attachments/assets/b9383fa2-6390-4a2a-8a54-b342b4c7dc1b" /> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PreviousNext