Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pkg/trace/otel/traceutil/otel_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ func TestGetOTelResource(t *testing.T) {
name string
rattrs map[string]string
sattrs map[string]string
spanKind ptrace.SpanKind
normalize bool
expectedV1 string
expectedV2 string
Expand All @@ -427,6 +428,13 @@ func TestGetOTelResource(t *testing.T) {
expectedV1: "GET",
expectedV2: "GET",
},
{
name: "HTTP client method and URL template resource",
sattrs: map[string]string{"http.request.method": "GET", "url.template": "/users/{user_id}"},
spanKind: ptrace.SpanKindClient,
expectedV1: "GET",
expectedV2: "GET /users/{user_id}",
},
{
name: "HTTP method and route resource",
sattrs: map[string]string{string(semconv.HTTPMethodKey): "GET", string(semconv.HTTPRouteKey): "/"},
Expand Down Expand Up @@ -534,6 +542,7 @@ func TestGetOTelResource(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
span := ptrace.NewSpan()
span.SetName("span_name")
span.SetKind(tt.spanKind)
for k, v := range tt.sattrs {
span.Attributes().PutStr(k, v)
}
Expand Down Expand Up @@ -821,6 +830,32 @@ func TestGetOTelResourceV2_HTTPRequestMethodResource(t *testing.T) {
spanKind: ptrace.SpanKindClient,
expected: "POST",
},
{
name: "http.request.method with URL template for client",
sattrs: map[string]string{"http.request.method": "POST", "url.template": "/api/users/{user_id}"},
spanKind: ptrace.SpanKindClient,
expected: "POST /api/users/{user_id}",
},
{
name: "client uses URL template and ignores route",
sattrs: map[string]string{
"http.request.method": "POST",
"url.template": "/api/users/{user_id}",
string(semconv.HTTPRouteKey): "/api/users/:user_id",
},
spanKind: ptrace.SpanKindClient,
expected: "POST /api/users/{user_id}",
},
{
name: "server uses route and ignores URL template",
sattrs: map[string]string{
"http.request.method": "POST",
"url.template": "/api/users/{user_id}",
string(semconv.HTTPRouteKey): "/api/users/:user_id",
},
spanKind: ptrace.SpanKindServer,
expected: "POST /api/users/:user_id",
},
{
name: "http.method (semconv 1.6.1) only",
sattrs: map[string]string{string(semconv.HTTPMethodKey): "DELETE"},
Expand Down
10 changes: 10 additions & 0 deletions pkg/trace/semantics/mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,16 @@
}
]
},
"url.template": {
"canonical": "url.template",
"fallbacks": [
{
"name": "url.template",
"provider": "otel",
"type": "string"
}
]
},
"http.status_code": {
"canonical": "http.status_code",
"fallbacks": [
Expand Down
1 change: 1 addition & 0 deletions pkg/trace/semantics/semantics.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
ConceptHTTPStatusCode Concept = "http.status_code"
ConceptHTTPMethod Concept = "http.method"
ConceptHTTPRoute Concept = "http.route"
ConceptURLTemplate Concept = "url.template"
ConceptGRPCStatusCode Concept = "rpc.grpc.status_code"
ConceptSpanKind Concept = "span.kind"
ConceptDDBaseService Concept = "_dd.base_service"
Expand Down
8 changes: 6 additions & 2 deletions pkg/trace/transform/otelutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,17 @@ func getOTelResourceV2[A semantics.Accessor](span ptrace.Span, accessor A) (resN
return
}

// HTTP: use method + route (if available)
// HTTP: use method + URL template for clients or route for servers.
if m := lookupString(accessor, semantics.ConceptHTTPMethod, false); m != "" {
if m == "_OTHER" {
m = "HTTP"
}
resName = m
if span.Kind() == ptrace.SpanKindServer {
if span.Kind() == ptrace.SpanKindClient {
if template := lookupString(accessor, semantics.ConceptURLTemplate, false); template != "" {
resName = resName + " " + template
}
} else if span.Kind() == ptrace.SpanKindServer {
if route := lookupString(accessor, semantics.ConceptHTTPRoute, false); route != "" {
resName = resName + " " + route
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
enhancements:
- |
APM : Use the OpenTelemetry ``url.template`` attribute in HTTP client
resource names when available, while retaining method-only resource names
as the fallback.
Loading