From 560cc4b604ede25ec70afd09f213d892f30ceedc Mon Sep 17 00:00:00 2001 From: Jonas Kunz Date: Fri, 20 Dec 2024 22:16:50 +0100 Subject: [PATCH] Add field for span http request body to IntakeV2 (#366) * Added intakeV2 context.http.request.body field * Added body to existing modeljson test * Switch body from string to any value (string or dictionary) * Switch field order for lint --- input/elasticapm/docs/spec/v2/span.json | 3 +++ input/elasticapm/internal/modeldecoder/v2/decoder.go | 9 +++++++-- input/elasticapm/internal/modeldecoder/v2/model.go | 2 ++ .../internal/modeldecoder/v2/model_generated.go | 3 ++- .../elasticapm/internal/modeldecoder/v2/span_test.go | 12 +++++++++++- model/modeljson/http.pb.json_test.go | 6 ++++++ 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/input/elasticapm/docs/spec/v2/span.json b/input/elasticapm/docs/spec/v2/span.json index e86da9a6..14eea1b1 100644 --- a/input/elasticapm/docs/spec/v2/span.json +++ b/input/elasticapm/docs/spec/v2/span.json @@ -188,6 +188,9 @@ "object" ], "properties": { + "body": { + "description": "The http request body usually as a string, but may be a dictionary for multipart/form-data content" + }, "id": { "description": "ID holds the unique identifier for the http request.", "type": [ diff --git a/input/elasticapm/internal/modeldecoder/v2/decoder.go b/input/elasticapm/internal/modeldecoder/v2/decoder.go index 88d947f8..59d587d2 100644 --- a/input/elasticapm/internal/modeldecoder/v2/decoder.go +++ b/input/elasticapm/internal/modeldecoder/v2/decoder.go @@ -1071,14 +1071,19 @@ func mapToSpanModel(from *span, event *modelpb.APMEvent) { } event.Http.Request.Method = from.Context.HTTP.Method.Val } - if from.Context.HTTP.Request.ID.IsSet() { + if from.Context.HTTP.Request.IsSet() { if event.Http == nil { event.Http = &modelpb.HTTP{} } if event.Http.Request == nil { event.Http.Request = &modelpb.HTTPRequest{} } - event.Http.Request.Id = from.Context.HTTP.Request.ID.Val + if from.Context.HTTP.Request.ID.IsSet() { + event.Http.Request.Id = from.Context.HTTP.Request.ID.Val + } + if from.Context.HTTP.Request.Body.IsSet() { + event.Http.Request.Body = modeldecoderutil.ToValue(from.Context.HTTP.Request.Body.Val) + } } if from.Context.HTTP.Response.IsSet() { if event.Http == nil { diff --git a/input/elasticapm/internal/modeldecoder/v2/model.go b/input/elasticapm/internal/modeldecoder/v2/model.go index 46a9b99e..72c162ab 100644 --- a/input/elasticapm/internal/modeldecoder/v2/model.go +++ b/input/elasticapm/internal/modeldecoder/v2/model.go @@ -843,6 +843,8 @@ type spanContextHTTP struct { } type spanContextHTTPRequest struct { + // The http request body usually as a string, but may be a dictionary for multipart/form-data content + Body nullable.Interface `json:"body"` // ID holds the unique identifier for the http request. ID nullable.String `json:"id"` } diff --git a/input/elasticapm/internal/modeldecoder/v2/model_generated.go b/input/elasticapm/internal/modeldecoder/v2/model_generated.go index f5b571f7..9d761090 100644 --- a/input/elasticapm/internal/modeldecoder/v2/model_generated.go +++ b/input/elasticapm/internal/modeldecoder/v2/model_generated.go @@ -2500,10 +2500,11 @@ func (val *spanContextHTTP) processNestedSource() error { } func (val *spanContextHTTPRequest) IsSet() bool { - return val.ID.IsSet() + return val.Body.IsSet() || val.ID.IsSet() } func (val *spanContextHTTPRequest) Reset() { + val.Body.Reset() val.ID.Reset() } diff --git a/input/elasticapm/internal/modeldecoder/v2/span_test.go b/input/elasticapm/internal/modeldecoder/v2/span_test.go index 57df65d7..b85b72f2 100644 --- a/input/elasticapm/internal/modeldecoder/v2/span_test.go +++ b/input/elasticapm/internal/modeldecoder/v2/span_test.go @@ -25,6 +25,8 @@ import ( "testing" "time" + "google.golang.org/protobuf/types/known/structpb" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -258,7 +260,7 @@ func TestDecodeMapToSpanModel(t *testing.T) { } }) - t.Run("http-request", func(t *testing.T) { + t.Run("http-request-id", func(t *testing.T) { var input span input.Context.HTTP.Request.ID.Set("some-request-id") var out modelpb.APMEvent @@ -266,6 +268,14 @@ func TestDecodeMapToSpanModel(t *testing.T) { assert.Equal(t, "some-request-id", out.Http.Request.Id) }) + t.Run("http-request-body", func(t *testing.T) { + var input span + input.Context.HTTP.Request.Body.Set("some-request-body") + var out modelpb.APMEvent + mapToSpanModel(&input, &out) + assert.Equal(t, structpb.NewStringValue("some-request-body"), out.Http.Request.Body) + }) + t.Run("http-headers", func(t *testing.T) { var input span input.Context.HTTP.Response.Headers.Set(http.Header{"a": []string{"b", "c"}}) diff --git a/model/modeljson/http.pb.json_test.go b/model/modeljson/http.pb.json_test.go index 91a9e9d8..bca3c9ee 100644 --- a/model/modeljson/http.pb.json_test.go +++ b/model/modeljson/http.pb.json_test.go @@ -20,6 +20,8 @@ package modeljson import ( "testing" + "google.golang.org/protobuf/types/known/structpb" + modeljson "github.com/elastic/apm-data/model/modeljson/internal" "github.com/elastic/apm-data/model/modelpb" "github.com/google/go-cmp/cmp" @@ -51,6 +53,7 @@ func TestHTTPToModelJSON(t *testing.T) { Id: "id", Method: "method", Referrer: "referrer", + Body: structpb.NewStringValue("request-body"), }, }, expected: &modeljson.HTTP{ @@ -61,6 +64,9 @@ func TestHTTPToModelJSON(t *testing.T) { ID: "id", Method: "method", Referrer: "referrer", + Body: &modeljson.HTTPRequestBody{ + Original: "request-body", + }, }, }, },