From 9b626b8e27d722f4743f3e45134082ff17282760 Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Tue, 12 Sep 2023 10:33:25 +0100 Subject: [PATCH] Add new attribute mappings (#139) * Collect additional new attributes and add tests * PR feedback fixes * PR feedback --------- Co-authored-by: Andrew Wilkins --- input/otlp/traces.go | 34 +++++++++++++++---- input/otlp/traces_test.go | 69 +++++++++++++++++++++++++++++++++++---- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/input/otlp/traces.go b/input/otlp/traces.go index f034ba9a..6a3e1a44 100644 --- a/input/otlp/traces.go +++ b/input/otlp/traces.go @@ -70,6 +70,12 @@ const ( attributeNetworkMNC = "net.host.carrier.mnc" attributeNetworkCarrierName = "net.host.carrier.name" attributeNetworkICC = "net.host.carrier.icc" + attributeHttpRequestMethod = "http.request.method" + attributeHttpResponseStatusCode = "http.response.status_code" + attributeServerAddress = "server.address" + attributeServerPort = "server.port" + attributeUrlFull = "url.full" + attributeUserAgentOriginal = "user_agent.original" ) // ConsumeTraces consumes OpenTelemetry trace data, @@ -257,7 +263,7 @@ func TranslateTransaction( setLabel(k, event, ifaceAttributeValue(v)) case pcommon.ValueTypeInt: switch kDots { - case semconv.AttributeHTTPStatusCode: + case semconv.AttributeHTTPStatusCode, attributeHttpResponseStatusCode: isHTTP = true httpResponse.StatusCode = uint32(v.Int()) http.Response = &httpResponse @@ -277,7 +283,7 @@ func TranslateTransaction( stringval := truncate(v.Str()) switch kDots { // http.* - case semconv.AttributeHTTPMethod: + case semconv.AttributeHTTPMethod, attributeHttpRequestMethod: isHTTP = true httpRequest.Method = stringval http.Request = &httpRequest @@ -290,7 +296,7 @@ func TranslateTransaction( case semconv.AttributeHTTPScheme: isHTTP = true httpScheme = stringval - case semconv.AttributeHTTPStatusCode: + case semconv.AttributeHTTPStatusCode, attributeHttpResponseStatusCode: if intv, err := strconv.Atoi(stringval); err == nil { isHTTP = true httpResponse.StatusCode = uint32(intv) @@ -315,7 +321,7 @@ func TranslateTransaction( event.Client = populateNil(event.Client) event.Client.Ip = ip } - case semconv.AttributeHTTPUserAgent: + case semconv.AttributeHTTPUserAgent, attributeUserAgentOriginal: event.UserAgent = populateNil(event.UserAgent) event.UserAgent.Original = stringval @@ -372,6 +378,11 @@ func TranslateTransaction( case semconv.AttributeRPCService: case semconv.AttributeRPCMethod: + // URL + case attributeUrlFull: + isHTTP = true + httpURL = stringval + // miscellaneous case "type": event.Transaction.Type = stringval @@ -533,11 +544,11 @@ func TranslateSpan(spanKind ptrace.SpanKind, attributes pcommon.Map, event *mode setLabel(k, event, v.Double()) case pcommon.ValueTypeInt: switch kDots { - case "http.status_code": + case "http.status_code", attributeHttpResponseStatusCode: httpResponse.StatusCode = uint32(v.Int()) http.Response = &httpResponse isHTTP = true - case semconv.AttributeNetPeerPort, "peer.port": + case semconv.AttributeNetPeerPort, "peer.port", attributeServerPort: netPeerPort = int(v.Int()) case semconv.AttributeRPCGRPCStatusCode: rpcSystem = "grpc" @@ -562,7 +573,7 @@ func TranslateSpan(spanKind ptrace.SpanKind, attributes pcommon.Map, event *mode case semconv.AttributeHTTPURL: httpURL = stringval isHTTP = true - case semconv.AttributeHTTPMethod: + case semconv.AttributeHTTPMethod, attributeHttpRequestMethod: httpRequest.Method = stringval http.Request = &httpRequest isHTTP = true @@ -619,6 +630,10 @@ func TranslateSpan(spanKind ptrace.SpanKind, attributes pcommon.Map, event *mode event.Network.Carrier = populateNil(event.Network.Carrier) event.Network.Carrier.Icc = stringval + // server.* + case attributeServerAddress: + netPeerName = stringval + // session.* case "session.id": event.Session = populateNil(event.Session) @@ -651,6 +666,11 @@ func TranslateSpan(spanKind ptrace.SpanKind, attributes pcommon.Map, event *mode isRPC = true case semconv.AttributeRPCMethod: + // url.* + case attributeUrlFull: + httpURL = stringval + isHTTP = true + // miscellaneous case "span.kind": // filter out case semconv.AttributePeerService: diff --git a/input/otlp/traces_test.go b/input/otlp/traces_test.go index 555e6c4b..2adc64a1 100644 --- a/input/otlp/traces_test.go +++ b/input/otlp/traces_test.go @@ -246,6 +246,19 @@ func TestHTTPTransactionURL(t *testing.T) { "http.target": "/foo", }) }) + t.Run("url.full", func(t *testing.T) { + test(t, &modelpb.URL{ + Scheme: "https", + Original: "https://testing.invalid:80/foo?bar", + Full: "https://testing.invalid:80/foo?bar", + Path: "/foo", + Query: "bar", + Domain: "testing.invalid", + Port: 80, + }, map[string]interface{}{ + "url.full": "https://testing.invalid:80/foo?bar", + }) + }) } func TestHTTPSpanURL(t *testing.T) { @@ -416,10 +429,23 @@ func TestHTTPTransactionFlavor(t *testing.T) { } func TestHTTPTransactionUserAgent(t *testing.T) { - event := transformTransactionWithAttributes(t, map[string]interface{}{ - "http.user_agent": "Foo/bar (baz)", + test := func(t *testing.T, attrs map[string]interface{}) { + t.Helper() + event := transformTransactionWithAttributes(t, attrs) + assert.Equal(t, &modelpb.UserAgent{Original: "Foo/bar (baz)"}, event.UserAgent) + } + + t.Run("http.user_agent", func(t *testing.T) { + test(t, map[string]interface{}{ + "http.user_agent": "Foo/bar (baz)", + }) + }) + + t.Run("user_agent.original", func(t *testing.T) { + test(t, map[string]interface{}{ + "user_agent.original": "Foo/bar (baz)", + }) }) - assert.Equal(t, &modelpb.UserAgent{Original: "Foo/bar (baz)"}, event.UserAgent) } func TestHTTPTransactionClientIP(t *testing.T) { @@ -435,10 +461,23 @@ func TestHTTPTransactionClientIP(t *testing.T) { } func TestHTTPTransactionStatusCode(t *testing.T) { - event := transformTransactionWithAttributes(t, map[string]interface{}{ - "http.status_code": 200, + test := func(t *testing.T, expected uint32, attrs map[string]interface{}) { + t.Helper() + event := transformSpanWithAttributes(t, attrs) + assert.Equal(t, expected, event.Http.Response.StatusCode) + } + + t.Run("http.status_code", func(t *testing.T) { + test(t, 200, map[string]interface{}{ + "http.status_code": 200, + }) + }) + + t.Run("http.response.status_code", func(t *testing.T) { + test(t, 200, map[string]interface{}{ + "http.response.status_code": 200, + }) }) - assert.Equal(t, uint32(200), event.Http.Response.StatusCode) } func TestDatabaseSpan(t *testing.T) { @@ -485,6 +524,24 @@ func TestDatabaseSpan(t *testing.T) { }, event.Span.DestinationService, protocmp.Transform())) } +func TestDatabaseSpanWithServerAttributes(t *testing.T) { + event := transformSpanWithAttributes(t, map[string]interface{}{ + "db.system": "mysql", + "db.name": "ShopDb", + "server.address": "shopdb.example.com", + "server.port": 3306, + }) + + assert.Equal(t, "db", event.Span.Type) + assert.Equal(t, "mysql", event.Span.Subtype) + assert.Equal(t, "", event.Span.Action) + + assert.Equal(t, &modelpb.Destination{ + Address: "shopdb.example.com", + Port: 3306, + }, event.Destination) +} + func TestInstrumentationLibrary(t *testing.T) { traces, spans := newTracesSpans() spans.Scope().SetName("library-name")