Skip to content

Commit 0e2fce6

Browse files
[Test] Add ASP.NET Core OTel semantics snapshots
Generated by running the new test classes against Samples.AspNetCoreMvc31 and Samples.AspNetCoreMinimalApis on net10.0. Also adds VerifyHelper.AddSpanEventScrubbers: with OTel semantics an exception is recorded as a span event, so the stack trace and the event timestamp live inside the "events" JSON blob where the existing error.stack scrubber can't reach them. Opt-in rather than a default scrubber because existing snapshots record the real stack trace. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e5cb028 commit 0e2fce6

32 files changed

Lines changed: 1498 additions & 0 deletions

File tree

tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AspNetCore/AspNetCoreMinimalApisTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ public async Task MeetsAllAspNetCoreMvcOTelExpectations(string path, int statusC
9090
var sanitisedPath = VerifyHelper.SanitisePathsForVerify(path);
9191
var settings = VerifyHelper.GetSpanVerifierSettings(sanitisedPath, statusCode);
9292

93+
// With OTel semantics, exceptions are recorded as span events rather than error.* tags
94+
VerifyHelper.AddSpanEventScrubbers(settings);
95+
9396
await Verifier.Verify(spans, settings)
9497
.UseMethodName("_")
9598
.UseTypeName(_testName);

tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AspNetCore/AspNetCoreMvc31Tests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ public async Task MeetsAllAspNetCoreMvcOTelExpectations(string path, int statusC
9393
var sanitisedPath = VerifyHelper.SanitisePathsForVerify(path);
9494
var settings = VerifyHelper.GetSpanVerifierSettings(sanitisedPath, statusCode);
9595

96+
// With OTel semantics, exceptions are recorded as span events rather than error.* tags
97+
VerifyHelper.AddSpanEventScrubbers(settings);
98+
9699
await Verifier.Verify(spans, settings)
97100
.UseMethodName("_")
98101
.UseTypeName(_testName);

tracer/test/Datadog.Trace.TestHelpers.SharedSource/VerifyHelper.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ public static class VerifyHelper
5353

5454
private static readonly Regex CodeOriginFilePathRegex = new(@"(?<prefix>_dd\.code_origin\.frames\.\d+\.file:\s*)(?<path>[^,\r\n]+)", RegOptions);
5555

56+
private static readonly Regex SpanEventTimeRegex = new(@"time_unix_nano"":([0-9]{10}[0-9]+)", RegOptions);
57+
58+
private static readonly Regex SpanEventStackTraceRegex = new(@"""exception\.stacktrace"":""(?:\\.|[^""\\])*""", RegOptions);
59+
60+
/// <summary>
61+
/// Scrubs the non-deterministic parts of span events: the event timestamp and, for
62+
/// <c>exception</c> events, the stack trace. This is opt-in rather than part of
63+
/// <see cref="SpanScrubbers"/> because existing snapshots record the real stack trace under
64+
/// <c>error.stack</c>. Needed by tests that record exceptions as span events, i.e. with
65+
/// <c>DD_TRACE_OTEL_SEMANTICS_ENABLED=true</c>.
66+
/// </summary>
67+
/// <param name="settings">The verifier settings to add the scrubbers to.</param>
68+
public static void AddSpanEventScrubbers(VerifySettings settings)
69+
{
70+
settings.AddRegexScrubber(SpanEventTimeRegex, @"time_unix_nano"":<DateTimeOffset.Now>");
71+
settings.AddRegexScrubber(SpanEventStackTraceRegex, @"""exception.stacktrace"":""<stacktrace>""");
72+
}
73+
5674
/// <summary>
5775
/// With <see cref="Verify"/>, parameters are used as part of the filename.
5876
/// This method produces a "sanitised" version to remove problematic values

tracer/test/Datadog.Trace.TestHelpers/SpanMetadataOTelRules.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public static Result IsAspNetCoreOTel(this MockSpan span, ISet<string> excludeTa
6666
.IsOptional("network.peer.address")
6767
.IsOptional("server.address")
6868
.IsOptional("user_agent.original")
69+
// In OTel semantics mode exceptions are recorded as span events instead of error.* tags
70+
.IsOptional("events")
6971
// Datadog-only attributes with no OpenTelemetry equivalent, which the RFC retains
7072
.IsOptional("aspnet_core.endpoint")
7173
.IsOptional("aspnet_core.route")
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET {controller=home}/{action=index}/{id?},
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Tags: {
10+
aspnet_core.endpoint: Samples.AspNetCoreMvc.Controllers.HomeController.Index (Samples.AspNetCoreMinimalApis),
11+
aspnet_core.route: {controller=home}/{action=index}/{id?},
12+
component: aspnet_core,
13+
datadog-header-tag: asp-net-core,
14+
env: integration_tests,
15+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
16+
http.request.method: GET,
17+
http.response.headers.sample_correlation_identifier: 0000-0000-0000,
18+
http.response.headers.server: Kestrel,
19+
http.response.status_code: 200,
20+
http.route: {controller=home}/{action=index}/{id?},
21+
language: dotnet,
22+
runtime-id: Guid_1,
23+
server.address: localhost,
24+
server.port: 00000,
25+
span.kind: server,
26+
url.path: /,
27+
url.query: query=test,
28+
url.scheme: http,
29+
user_agent.original: testhelper,
30+
version: 1.0.0,
31+
_dd.code_origin.frames.0.column: 0,
32+
_dd.code_origin.frames.0.file: tracer\test\test-applications\integrations\Samples.AspNetCoreMvc21\Controllers\HomeController.cs,
33+
_dd.code_origin.frames.0.index: 0,
34+
_dd.code_origin.frames.0.line: 0,
35+
_dd.code_origin.frames.0.method: Index,
36+
_dd.code_origin.frames.0.type: Samples.AspNetCoreMvc.Controllers.HomeController,
37+
_dd.code_origin.type: entry
38+
},
39+
Metrics: {
40+
process_id: 0,
41+
_dd.top_level: 1.0,
42+
_dd.tracer_kr: 1.0,
43+
_sampling_priority_v1: 1.0
44+
}
45+
}
46+
]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET {controller=home}/{action=index}/{id?},
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Tags: {
10+
aspnet_core.endpoint: Samples.AspNetCoreMvc.Controllers.HomeController.Index (Samples.AspNetCoreMinimalApis),
11+
aspnet_core.route: {controller=home}/{action=index}/{id?},
12+
component: aspnet_core,
13+
datadog-header-tag: asp-net-core,
14+
env: integration_tests,
15+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
16+
http.request.method: GET,
17+
http.response.headers.sample_correlation_identifier: 0000-0000-0000,
18+
http.response.headers.server: Kestrel,
19+
http.response.status_code: 200,
20+
http.route: {controller=home}/{action=index}/{id?},
21+
language: dotnet,
22+
runtime-id: Guid_1,
23+
server.address: localhost,
24+
server.port: 00000,
25+
span.kind: server,
26+
url.path: /,
27+
url.scheme: http,
28+
user_agent.original: testhelper,
29+
version: 1.0.0,
30+
_dd.code_origin.frames.0.column: 0,
31+
_dd.code_origin.frames.0.file: tracer\test\test-applications\integrations\Samples.AspNetCoreMvc21\Controllers\HomeController.cs,
32+
_dd.code_origin.frames.0.index: 0,
33+
_dd.code_origin.frames.0.line: 0,
34+
_dd.code_origin.frames.0.method: Index,
35+
_dd.code_origin.frames.0.type: Samples.AspNetCoreMvc.Controllers.HomeController,
36+
_dd.code_origin.type: entry
37+
},
38+
Metrics: {
39+
process_id: 0,
40+
_dd.top_level: 1.0,
41+
_dd.tracer_kr: 1.0,
42+
_sampling_priority_v1: 1.0
43+
}
44+
}
45+
]
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET /api/delay/{seconds},
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Tags: {
10+
aspnet_core.endpoint: HTTP: GET /api/delay/{seconds},
11+
aspnet_core.route: /api/delay/{seconds},
12+
component: aspnet_core,
13+
datadog-header-tag: asp-net-core,
14+
env: integration_tests,
15+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
16+
http.request.method: GET,
17+
http.response.headers.sample_correlation_identifier: 0000-0000-0000,
18+
http.response.headers.server: Kestrel,
19+
http.response.status_code: 200,
20+
http.route: /api/delay/{seconds},
21+
language: dotnet,
22+
runtime-id: Guid_1,
23+
server.address: localhost,
24+
server.port: 00000,
25+
span.kind: server,
26+
url.path: /api/delay/0,
27+
url.scheme: http,
28+
user_agent.original: testhelper,
29+
version: 1.0.0
30+
},
31+
Metrics: {
32+
process_id: 0,
33+
_dd.top_level: 1.0,
34+
_dd.tracer_kr: 1.0,
35+
_sampling_priority_v1: 1.0
36+
}
37+
}
38+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET bad-request,
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Error: 1,
10+
Tags: {
11+
aspnet_core.endpoint: Samples.AspNetCoreMvc.Controllers.HomeController.ThrowException (Samples.AspNetCoreMinimalApis),
12+
aspnet_core.route: bad-request,
13+
component: aspnet_core,
14+
datadog-header-tag: asp-net-core,
15+
env: integration_tests,
16+
error.msg: The HTTP response has status code 500.,
17+
events: [{"name":"exception","time_unix_nano":<DateTimeOffset.Now>,"attributes":{"exception.type":"System.Exception","exception.message":"This was a bad request.","exception.stacktrace":"<stacktrace>"}}],
18+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
19+
http.request.method: GET,
20+
http.response.headers.server: Kestrel,
21+
http.response.status_code: 500,
22+
http.route: bad-request,
23+
language: dotnet,
24+
runtime-id: Guid_1,
25+
server.address: localhost,
26+
server.port: 00000,
27+
span.kind: server,
28+
url.path: /bad-request,
29+
url.scheme: http,
30+
user_agent.original: testhelper,
31+
version: 1.0.0,
32+
_dd.code_origin.frames.0.column: 0,
33+
_dd.code_origin.frames.0.file: tracer\test\test-applications\integrations\Samples.AspNetCoreMvc21\Controllers\HomeController.cs,
34+
_dd.code_origin.frames.0.index: 0,
35+
_dd.code_origin.frames.0.line: 0,
36+
_dd.code_origin.frames.0.method: ThrowException,
37+
_dd.code_origin.frames.0.type: Samples.AspNetCoreMvc.Controllers.HomeController,
38+
_dd.code_origin.type: entry
39+
},
40+
Metrics: {
41+
process_id: 0,
42+
_dd.top_level: 1.0,
43+
_dd.tracer_kr: 1.0,
44+
_sampling_priority_v1: 1.0
45+
}
46+
}
47+
]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET,
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Tags: {
10+
component: aspnet_core,
11+
datadog-header-tag: asp-net-core,
12+
env: integration_tests,
13+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
14+
http.request.method: GET,
15+
http.response.headers.server: Kestrel,
16+
http.response.status_code: 404,
17+
language: dotnet,
18+
runtime-id: Guid_1,
19+
server.address: localhost,
20+
server.port: 00000,
21+
span.kind: server,
22+
url.path: /branch/not-found,
23+
url.scheme: http,
24+
user_agent.original: testhelper,
25+
version: 1.0.0
26+
},
27+
Metrics: {
28+
process_id: 0,
29+
_dd.top_level: 1.0,
30+
_dd.tracer_kr: 1.0,
31+
_sampling_priority_v1: 1.0
32+
}
33+
}
34+
]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[
2+
{
3+
TraceId: Id_1,
4+
SpanId: Id_2,
5+
Name: aspnet_core.request,
6+
Resource: GET,
7+
Service: Samples.AspNetCoreMinimalApis,
8+
Type: web,
9+
Tags: {
10+
component: aspnet_core,
11+
datadog-header-tag: asp-net-core,
12+
env: integration_tests,
13+
http.request.headers.sample_correlation_identifier: 0000-0000-0000,
14+
http.request.method: GET,
15+
http.response.headers.server: Kestrel,
16+
http.response.status_code: 200,
17+
language: dotnet,
18+
runtime-id: Guid_1,
19+
server.address: localhost,
20+
server.port: 00000,
21+
span.kind: server,
22+
url.path: /branch/ping,
23+
url.scheme: http,
24+
user_agent.original: testhelper,
25+
version: 1.0.0
26+
},
27+
Metrics: {
28+
process_id: 0,
29+
_dd.top_level: 1.0,
30+
_dd.tracer_kr: 1.0,
31+
_sampling_priority_v1: 1.0
32+
}
33+
}
34+
]

0 commit comments

Comments
 (0)