From 6f984757ea3299c398e45dee52b883369bbc460a Mon Sep 17 00:00:00 2001 From: Puneet Agarwal Date: Fri, 10 Nov 2023 16:18:18 +0530 Subject: [PATCH 1/2] ENG-37132: Adding bodyAttribute functions to support already truncated bodies --- .../bodyattribute/bodyattribute.go | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sdk/instrumentation/bodyattribute/bodyattribute.go b/sdk/instrumentation/bodyattribute/bodyattribute.go index 9df2474..3d440e6 100644 --- a/sdk/instrumentation/bodyattribute/bodyattribute.go +++ b/sdk/instrumentation/bodyattribute/bodyattribute.go @@ -44,3 +44,48 @@ func SetTruncatedEncodedBodyAttribute(attrName string, body []byte, bodyMaxSize span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(truncatedBody)) } + +// SetPossiblyTruncatedBodyAttribute sets the body as a span attribute. +// When body is being truncated, or already truncated we also add a second attribute suffixed by `.truncated` to +// make it clear to the user, body has been modified. +func SetPossiblyTruncatedBodyAttribute(attrName string, body []byte, bodyMaxSize int, truncated bool, span sdk.Span) { + bodyLen := len(body) + if bodyLen == 0 { + return + } + + if bodyLen <= bodyMaxSize { + span.SetAttribute(attrName, string(body)) + // if already truncated then set attribute + if truncated { + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) + } + return + } + + truncatedBody := body[:bodyMaxSize] + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) + span.SetAttribute(attrName, string(truncatedBody)) +} + +// SetPossiblyTruncatedEncodedBodyAttribute is like SetPossiblyTruncatedBodyAttribute above but also base64 encodes the +// body. This is usually due to non utf8 bytes in the body eg. for multipart/form-data content type. +// The body attribute name has a ".base64" suffix. +func SetPossiblyTruncatedEncodedBodyAttribute(attrName string, body []byte, bodyMaxSize int, truncated bool, span sdk.Span) { + bodyLen := len(body) + if bodyLen == 0 { + return + } + + if bodyLen <= bodyMaxSize { + span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(body)) + if truncated { + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) + } + return + } + + truncatedBody := body[:bodyMaxSize] + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) + span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(truncatedBody)) +} From e3beab5575b9fdf58c67d68798f66c81d0b26465 Mon Sep 17 00:00:00 2001 From: Puneet Agarwal Date: Sat, 11 Nov 2023 13:13:54 +0530 Subject: [PATCH 2/2] adding tests and refactoring --- .../bodyattribute/bodyattribute.go | 60 +++---- .../bodyattribute/bodyattribute_test.go | 148 ++++++++++++++++++ 2 files changed, 168 insertions(+), 40 deletions(-) diff --git a/sdk/instrumentation/bodyattribute/bodyattribute.go b/sdk/instrumentation/bodyattribute/bodyattribute.go index 3d440e6..dde5cf4 100644 --- a/sdk/instrumentation/bodyattribute/bodyattribute.go +++ b/sdk/instrumentation/bodyattribute/bodyattribute.go @@ -17,13 +17,11 @@ func SetTruncatedBodyAttribute(attrName string, body []byte, bodyMaxSize int, sp } if bodyLen <= bodyMaxSize { - span.SetAttribute(attrName, string(body)) + SetBodyAttribute(attrName, body, false, span) return } - truncatedBody := body[:bodyMaxSize] - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - span.SetAttribute(attrName, string(truncatedBody)) + SetBodyAttribute(attrName, body[:bodyMaxSize], true, span) } // SetTruncatedEncodedBodyAttribute is like SetTruncatedBodyAttribute above but also base64 encodes the @@ -31,61 +29,43 @@ func SetTruncatedBodyAttribute(attrName string, body []byte, bodyMaxSize int, sp // The body attribute name has a ".base64" suffix. func SetTruncatedEncodedBodyAttribute(attrName string, body []byte, bodyMaxSize int, span sdk.Span) { bodyLen := len(body) - if bodyLen == 0 { + if len(body) == 0 { return } if bodyLen <= bodyMaxSize { - span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(body)) + SetEncodedBodyAttribute(attrName, body, false, span) return } - truncatedBody := body[:bodyMaxSize] - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(truncatedBody)) + SetEncodedBodyAttribute(attrName, body[:bodyMaxSize], true, span) } -// SetPossiblyTruncatedBodyAttribute sets the body as a span attribute. -// When body is being truncated, or already truncated we also add a second attribute suffixed by `.truncated` to -// make it clear to the user, body has been modified. -func SetPossiblyTruncatedBodyAttribute(attrName string, body []byte, bodyMaxSize int, truncated bool, span sdk.Span) { - bodyLen := len(body) - if bodyLen == 0 { +// SetBodyAttribute sets the body as a span attribute. +// also sets truncated attribute if truncated is true +func SetBodyAttribute(attrName string, body []byte, truncated bool, span sdk.Span) { + if len(body) == 0 { return } - if bodyLen <= bodyMaxSize { - span.SetAttribute(attrName, string(body)) - // if already truncated then set attribute - if truncated { - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - } - return + span.SetAttribute(attrName, string(body)) + // if already truncated then set attribute + if truncated { + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) } - - truncatedBody := body[:bodyMaxSize] - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - span.SetAttribute(attrName, string(truncatedBody)) } -// SetPossiblyTruncatedEncodedBodyAttribute is like SetPossiblyTruncatedBodyAttribute above but also base64 encodes the +// SetEncodedBodyAttribute is like SetBodyAttribute above but also base64 encodes the // body. This is usually due to non utf8 bytes in the body eg. for multipart/form-data content type. // The body attribute name has a ".base64" suffix. -func SetPossiblyTruncatedEncodedBodyAttribute(attrName string, body []byte, bodyMaxSize int, truncated bool, span sdk.Span) { - bodyLen := len(body) - if bodyLen == 0 { +func SetEncodedBodyAttribute(attrName string, body []byte, truncated bool, span sdk.Span) { + if len(body) == 0 { return } - if bodyLen <= bodyMaxSize { - span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(body)) - if truncated { - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - } - return + span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(body)) + // if already truncated then set attribute + if truncated { + span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) } - - truncatedBody := body[:bodyMaxSize] - span.SetAttribute(fmt.Sprintf("%s.truncated", attrName), true) - span.SetAttribute(attrName+".base64", base64.RawStdEncoding.EncodeToString(truncatedBody)) } diff --git a/sdk/instrumentation/bodyattribute/bodyattribute_test.go b/sdk/instrumentation/bodyattribute/bodyattribute_test.go index acc06bf..6c775fd 100644 --- a/sdk/instrumentation/bodyattribute/bodyattribute_test.go +++ b/sdk/instrumentation/bodyattribute/bodyattribute_test.go @@ -51,3 +51,151 @@ func TestSetTruncatedEncodedBodyAttributeEmptyBody(t *testing.T) { assert.Nil(t, s.ReadAttribute("http.request.body.base64")) assert.Zero(t, s.RemainingAttributes()) } + +func TestSetBodyAttribute(t *testing.T) { + testBody := "test1test2" + type args struct { + attrName string + body []byte + truncated bool + span *mock.Span + } + tests := []struct { + name string + args args + expectedAssertions func(t *testing.T, gotSpan *mock.Span) + }{ + { + name: "empty body, truncated", + args: args{ + attrName: "http.request.body", + body: []byte(""), + truncated: true, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Nil(t, gotSpan.ReadAttribute("http.request.body")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "empty body, not truncated", + args: args{ + attrName: "http.request.body", + body: []byte(""), + truncated: false, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Nil(t, gotSpan.ReadAttribute("http.request.body")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "non empty body, not truncated", + args: args{ + attrName: "http.request.body", + body: []byte(testBody), + truncated: false, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Equal(t, testBody, gotSpan.ReadAttribute("http.request.body")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "non empty body, truncated", + args: args{ + attrName: "http.request.body", + body: []byte(testBody), + truncated: true, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Equal(t, testBody, gotSpan.ReadAttribute("http.request.body")) + assert.True(t, (gotSpan.ReadAttribute("http.request.body.truncated")).(bool)) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + SetBodyAttribute(tt.args.attrName, tt.args.body, tt.args.truncated, tt.args.span) + tt.expectedAssertions(t, tt.args.span) + }) + } +} + +func TestSetEncodedBodyAttribute(t *testing.T) { + testBody := "test1test2" + type args struct { + attrName string + body []byte + truncated bool + span *mock.Span + } + tests := []struct { + name string + args args + expectedAssertions func(t *testing.T, gotSpan *mock.Span) + }{ + { + name: "empty body, truncated", + args: args{ + attrName: "http.request.body", + body: []byte(""), + truncated: true, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Nil(t, gotSpan.ReadAttribute("http.request.body.base64")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "empty body, not truncated", + args: args{ + attrName: "http.request.body", + body: []byte(""), + truncated: false, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Nil(t, gotSpan.ReadAttribute("http.request.body.base64")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "non empty body, not truncated", + args: args{ + attrName: "http.request.body", + body: []byte(testBody), + truncated: false, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Equal(t, base64.RawStdEncoding.EncodeToString([]byte(testBody)), gotSpan.ReadAttribute("http.request.body.base64")) + assert.Zero(t, gotSpan.RemainingAttributes()) + }, + }, + { + name: "non empty body, truncated", + args: args{ + attrName: "http.request.body", + body: []byte(testBody), + truncated: true, + span: mock.NewSpan(), + }, + expectedAssertions: func(t *testing.T, gotSpan *mock.Span) { + assert.Equal(t, base64.RawStdEncoding.EncodeToString([]byte(testBody)), gotSpan.ReadAttribute("http.request.body.base64")) + assert.True(t, (gotSpan.ReadAttribute("http.request.body.truncated")).(bool)) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + SetEncodedBodyAttribute(tt.args.attrName, tt.args.body, tt.args.truncated, tt.args.span) + tt.expectedAssertions(t, tt.args.span) + }) + } +}