From e07464b4e324acc7aecb47516cacbadf46a24647 Mon Sep 17 00:00:00 2001 From: alioktar Date: Sun, 9 Feb 2025 20:38:51 +0300 Subject: [PATCH] otelfiber: migrate go version from `1.19 -> 1.20`, upgrade semiconv package version and fix deprecated usages... --- otelfiber/README.md | 2 - otelfiber/config.go | 11 +--- otelfiber/example/go.mod | 12 ++-- otelfiber/example/go.sum | 6 ++ otelfiber/fiber.go | 21 +++---- otelfiber/go.mod | 14 ++--- otelfiber/go.sum | 12 ++++ otelfiber/internal/http.go | 28 +++++++++ otelfiber/otelfiber_test/fiber_test.go | 79 ++++++++++++-------------- otelfiber/semconv.go | 50 ++++++++-------- 10 files changed, 126 insertions(+), 109 deletions(-) create mode 100644 otelfiber/internal/http.go diff --git a/otelfiber/README.md b/otelfiber/README.md index 200a05c5..b1e8563f 100644 --- a/otelfiber/README.md +++ b/otelfiber/README.md @@ -33,7 +33,6 @@ otelfiber.Middleware(opts ...otelfiber.Option) fiber.Handler ## Config You can configure the middleware using functional parameters - | Function | Argument Type | Description | Default | | :------------------------ | :-------------------------------- | :--------------------------------------------------------------------------------- | :-------------------------------------------------------------------- | | `WithNext` | `func(*fiber.Ctx) bool` | Define a function to skip this middleware when returned true .| nil | @@ -41,7 +40,6 @@ You can configure the middleware using functional parameters | `WithMeterProvider` | `otelmetric.MeterProvider` | Specifies a meter provider to use for reporting. | nil - the global meter provider is used | | `WithPort` | `int` | Specifies the value to use when setting the `net.host.port` attribute on metrics/spans. | Defaults to (`80` for `http`, `443` for `https`) | | `WithPropagators` | `propagation.TextMapPropagator` | Specifies propagators to use for extracting information from the HTTP requests. | If none are specified, global ones will be used | -| `WithServerName` | `string` | Specifies the value to use when setting the `http.server_name` attribute on metrics/spans. | - | | `WithSpanNameFormatter` | `func(*fiber.Ctx) string` | Takes a function that will be called on every request and the returned string will become the span Name. | Default formatter returns the route pathRaw | | `WithCustomAttributes` | `func(*fiber.Ctx) []attribute.KeyValue` | Define a function to add custom attributes to the span. | nil | | `WithCustomMetricAttributes` | `func(*fiber.Ctx) []attribute.KeyValue` | Define a function to add custom attributes to the metrics. | nil | diff --git a/otelfiber/config.go b/otelfiber/config.go index ab588253..1f2487a2 100644 --- a/otelfiber/config.go +++ b/otelfiber/config.go @@ -15,7 +15,6 @@ type config struct { MeterProvider otelmetric.MeterProvider Port *int Propagators propagation.TextMapPropagator - ServerName *string SpanNameFormatter func(*fiber.Ctx) string CustomAttributes func(*fiber.Ctx) []attribute.KeyValue CustomMetricAttributes func(*fiber.Ctx) []attribute.KeyValue @@ -74,15 +73,7 @@ func WithSpanNameFormatter(f func(ctx *fiber.Ctx) string) Option { }) } -// WithServerName specifies the value to use when setting the `http.server_name` -// attribute on metrics/spans. -func WithServerName(serverName string) Option { - return optionFunc(func(cfg *config) { - cfg.ServerName = &serverName - }) -} - -// WithPort specifies the value to use when setting the `net.host.port` +// WithPort specifies the value to use when setting the `server.port` // attribute on metrics/spans. Attribute is "Conditionally Required: If not // default (`80` for `http`, `443` for `https`). func WithPort(port int) Option { diff --git a/otelfiber/example/go.mod b/otelfiber/example/go.mod index 051f394f..d785cb57 100644 --- a/otelfiber/example/go.mod +++ b/otelfiber/example/go.mod @@ -6,7 +6,7 @@ replace github.com/gofiber/contrib/otelfiber => ../ require ( github.com/gofiber/contrib/otelfiber v1.0.9 - github.com/gofiber/fiber/v2 v2.52.5 + github.com/gofiber/fiber/v2 v2.52.6 go.opentelemetry.io/otel v1.24.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 go.opentelemetry.io/otel/sdk v1.24.0 @@ -15,19 +15,19 @@ require ( ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/uuid v1.5.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect go.opentelemetry.io/contrib v1.20.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.28.0 // indirect ) diff --git a/otelfiber/example/go.sum b/otelfiber/example/go.sum index 0fa227f1..a0890f12 100644 --- a/otelfiber/example/go.sum +++ b/otelfiber/example/go.sum @@ -1,5 +1,6 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= @@ -8,11 +9,14 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -20,6 +24,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= @@ -47,4 +52,5 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/otelfiber/fiber.go b/otelfiber/fiber.go index 508528c0..79b99b83 100644 --- a/otelfiber/fiber.go +++ b/otelfiber/fiber.go @@ -2,6 +2,7 @@ package otelfiber import ( "context" + "github.com/gofiber/contrib/otelfiber/v2/internal" "net/http" "time" @@ -12,7 +13,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" - semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" oteltrace "go.opentelemetry.io/otel/trace" ) @@ -128,10 +129,10 @@ func Middleware(opts ...Option) fiber.Handler { } // extract common attributes from response - responseAttrs := append( - semconv.HTTPAttributesFromHTTPStatusCode(c.Response().StatusCode()), + responseAttrs := []attribute.KeyValue{ + semconv.HTTPResponseStatusCode(c.Response().StatusCode()), semconv.HTTPRouteKey.String(c.Route().Path), // no need to copy c.Route().Path: route strings should be immutable across app lifecycle - ) + } var responseSize int64 requestSize := int64(len(c.Request().Body())) @@ -140,9 +141,7 @@ func Middleware(opts ...Option) fiber.Handler { } defer func() { - responseMetricAttrs = append( - responseMetricAttrs, - responseAttrs...) + responseMetricAttrs = append(responseMetricAttrs, responseAttrs...) httpServerActiveRequests.Add(savedCtx, -1, metric.WithAttributes(requestMetricsAttrs...)) httpServerDuration.Record(savedCtx, float64(time.Since(start).Microseconds())/1000, metric.WithAttributes(responseMetricAttrs...)) @@ -153,14 +152,10 @@ func Middleware(opts ...Option) fiber.Handler { cancel() }() - span.SetAttributes( - append( - responseAttrs, - semconv.HTTPResponseContentLengthKey.Int64(responseSize), - )...) + span.SetAttributes(append(responseAttrs, semconv.HTTPResponseBodySizeKey.Int64(responseSize))...) span.SetName(cfg.SpanNameFormatter(c)) - spanStatus, spanMessage := semconv.SpanStatusFromHTTPStatusCodeAndSpanKind(c.Response().StatusCode(), oteltrace.SpanKindServer) + spanStatus, spanMessage := internal.SpanStatusFromHTTPStatusCodeAndSpanKind(c.Response().StatusCode(), oteltrace.SpanKindServer) span.SetStatus(spanStatus, spanMessage) //Propagate tracing context as headers in outbound response diff --git a/otelfiber/go.mod b/otelfiber/go.mod index ab748432..43739f6a 100644 --- a/otelfiber/go.mod +++ b/otelfiber/go.mod @@ -1,9 +1,9 @@ module github.com/gofiber/contrib/otelfiber/v2 -go 1.19 +go 1.20 require ( - github.com/gofiber/fiber/v2 v2.52.5 + github.com/gofiber/fiber/v2 v2.52.6 github.com/stretchr/testify v1.9.0 go.opentelemetry.io/contrib v1.20.0 go.opentelemetry.io/contrib/propagators/b3 v1.20.0 @@ -15,20 +15,20 @@ require ( ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/uuid v1.5.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/otelfiber/go.sum b/otelfiber/go.sum index 694cf74a..867f767c 100644 --- a/otelfiber/go.sum +++ b/otelfiber/go.sum @@ -1,5 +1,7 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -9,11 +11,17 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -21,6 +29,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= @@ -51,6 +61,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/otelfiber/internal/http.go b/otelfiber/internal/http.go new file mode 100644 index 00000000..a43424e2 --- /dev/null +++ b/otelfiber/internal/http.go @@ -0,0 +1,28 @@ +package internal + +import ( + "fmt" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + "net/http" +) + +// SpanStatusFromHTTPStatusCodeAndSpanKind generates a status code and a message +// as specified by the OpenTelemetry specification for a span. +// Exclude 4xx for SERVER to set the appropriate status. +func SpanStatusFromHTTPStatusCodeAndSpanKind(code int, spanKind trace.SpanKind) (codes.Code, string) { + // This code block ignores the HTTP 306 status code. The 306 status code is no longer in use. + if len(http.StatusText(code)) == 0 { + return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code) + } + + if (code >= http.StatusContinue && code < http.StatusBadRequest) || + (spanKind == trace.SpanKindServer && isCode4xx(code)) { + return codes.Unset, "" + } + return codes.Error, "" +} + +func isCode4xx(code int) bool { + return code >= http.StatusBadRequest && code <= http.StatusUnavailableForLegalReasons +} diff --git a/otelfiber/otelfiber_test/fiber_test.go b/otelfiber/otelfiber_test/fiber_test.go index 32c87fb7..a5c34bd1 100644 --- a/otelfiber/otelfiber_test/fiber_test.go +++ b/otelfiber/otelfiber_test/fiber_test.go @@ -24,7 +24,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" - semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" oteltrace "go.opentelemetry.io/otel/trace" ) @@ -88,21 +88,18 @@ func TestTrace200(t *testing.T) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(provider) - serverName := "foobar" app := fiber.New() app.Use( - otelfiber.Middleware( - otelfiber.WithTracerProvider(provider), - otelfiber.WithServerName(serverName), - ), + otelfiber.Middleware(otelfiber.WithTracerProvider(provider)), ) app.Get("/user/:id", func(ctx *fiber.Ctx) error { id := ctx.Params("id") return ctx.SendString(id) }) - resp, _ := app.Test(httptest.NewRequest("GET", "/user/123", nil), 3000) + r := httptest.NewRequest("GET", "/user/123", nil) + resp, _ := app.Test(r, 3000) // do and verify the request require.Equal(t, http.StatusOK, resp.StatusCode) @@ -116,10 +113,10 @@ func TestTrace200(t *testing.T) { assert.Equal(t, "/user/:id", span.Name()) assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) - assert.Contains(t, attr, attribute.String("http.server_name", serverName)) - assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusOK)) - assert.Contains(t, attr, attribute.String("http.method", "GET")) - assert.Contains(t, attr, attribute.String("http.target", "/user/123")) + assert.Contains(t, attr, attribute.String("server.address", r.Host)) + assert.Contains(t, attr, attribute.Int("http.response.status_code", http.StatusOK)) + assert.Contains(t, attr, attribute.String("http.request.method", "GET")) + assert.Contains(t, attr, attribute.String("url.path", "/user/123")) assert.Contains(t, attr, attribute.String("http.route", "/user/:id")) } @@ -145,7 +142,7 @@ func TestError(t *testing.T) { attr := span.Attributes() assert.Equal(t, "/server_err", span.Name()) - assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusInternalServerError)) + assert.Contains(t, attr, attribute.Int("http.response.status_code", http.StatusInternalServerError)) assert.Equal(t, attribute.StringValue("oh no"), span.Events()[0].Attributes[1].Value) // server errors set the status assert.Equal(t, codes.Error, span.Status().Code) @@ -280,7 +277,6 @@ func TestMetric(t *testing.T) { reader := metric.NewManualReader() provider := metric.NewMeterProvider(metric.WithReader(reader)) - serverName := "foobar" port := 8080 route := "/foo" @@ -289,7 +285,6 @@ func TestMetric(t *testing.T) { otelfiber.Middleware( otelfiber.WithMeterProvider(provider), otelfiber.WithPort(port), - otelfiber.WithServerName(serverName), ), ) app.Get(route, func(ctx *fiber.Ctx) error { @@ -305,17 +300,17 @@ func TestMetric(t *testing.T) { assert.Len(t, metrics.ScopeMetrics, 1) requestAttrs := []attribute.KeyValue{ - semconv.HTTPFlavorKey.String(fmt.Sprintf("1.%d", r.ProtoMinor)), - semconv.HTTPMethodKey.String(http.MethodGet), - semconv.HTTPSchemeHTTP, - semconv.NetHostNameKey.String(r.Host), - semconv.NetHostPortKey.Int(port), - semconv.HTTPServerNameKey.String(serverName), + semconv.NetworkProtocolName("http"), + semconv.NetworkProtocolVersion(fmt.Sprintf("1.%d", r.ProtoMinor)), + semconv.URLScheme("http"), + semconv.HTTPRequestMethodKey.String(http.MethodGet), + semconv.ServerAddress(r.Host), + semconv.ServerPort(port), } - responseAttrs := append( - semconv.HTTPAttributesFromHTTPStatusCode(200), + responseAttrs := []attribute.KeyValue{ + semconv.HTTPResponseStatusCode(200), semconv.HTTPRouteKey.String(route), - ) + } assertScopeMetrics(t, metrics.ScopeMetrics[0], route, requestAttrs, append(requestAttrs, responseAttrs...)) } @@ -440,18 +435,17 @@ func TestCustomAttributes(t *testing.T) { assert.Equal(t, "/user/:id", span.Name()) assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind()) - assert.Contains(t, attr, attribute.Int("http.status_code", http.StatusOK)) - assert.Contains(t, attr, attribute.String("http.method", "GET")) - assert.Contains(t, attr, attribute.String("http.target", "/user/123?foo=bar")) + assert.Contains(t, attr, attribute.Int("http.response.status_code", http.StatusOK)) + assert.Contains(t, attr, attribute.String("http.request.method", "GET")) + assert.Contains(t, attr, attribute.String("url.path", "/user/123?foo=bar")) assert.Contains(t, attr, attribute.String("http.route", "/user/:id")) - assert.Contains(t, attr, attribute.String("http.query_params", "foo=bar")) + assert.Contains(t, attr, semconv.URLQuery("foo=bar")) } func TestCustomMetricAttributes(t *testing.T) { reader := metric.NewManualReader() provider := metric.NewMeterProvider(metric.WithReader(reader)) - serverName := "foobar" port := 8080 route := "/foo" @@ -460,11 +454,8 @@ func TestCustomMetricAttributes(t *testing.T) { otelfiber.Middleware( otelfiber.WithMeterProvider(provider), otelfiber.WithPort(port), - otelfiber.WithServerName(serverName), otelfiber.WithCustomMetricAttributes(func(ctx *fiber.Ctx) []attribute.KeyValue { - return []attribute.KeyValue{ - attribute.Key("http.query_params").String(ctx.Request().URI().QueryArgs().String()), - } + return []attribute.KeyValue{semconv.URLQuery(ctx.Request().URI().QueryArgs().String())} }), ), ) @@ -485,18 +476,18 @@ func TestCustomMetricAttributes(t *testing.T) { assert.Len(t, metrics.ScopeMetrics, 1) requestAttrs := []attribute.KeyValue{ - semconv.HTTPFlavorKey.String(fmt.Sprintf("1.%d", r.ProtoMinor)), - semconv.HTTPMethodKey.String(http.MethodGet), - semconv.HTTPSchemeHTTP, - semconv.NetHostNameKey.String(r.Host), - semconv.NetHostPortKey.Int(port), - semconv.HTTPServerNameKey.String(serverName), - attribute.String("http.query_params", "foo=bar"), + semconv.NetworkProtocolName("http"), + semconv.NetworkProtocolVersion(fmt.Sprintf("1.%d", r.ProtoMinor)), + semconv.HTTPRequestMethodKey.String(http.MethodGet), + semconv.URLSchemeKey.String("http"), + semconv.ServerAddress(r.Host), + semconv.ServerPort(port), + semconv.URLQuery("foo=bar"), } - responseAttrs := append( - semconv.HTTPAttributesFromHTTPStatusCode(200), + responseAttrs := []attribute.KeyValue{ + semconv.HTTPResponseStatusCode(200), semconv.HTTPRouteKey.String(route), - ) + } assertScopeMetrics(t, metrics.ScopeMetrics[0], route, requestAttrs, append(requestAttrs, responseAttrs...)) } @@ -581,9 +572,9 @@ func TestCollectClientIP(t *testing.T) { span := spans[0] attrs := span.Attributes() if enabled { - assert.Contains(t, attrs, attribute.String("http.client_ip", "0.0.0.0")) + assert.Contains(t, attrs, attribute.String("client.address", "0.0.0.0")) } else { - assert.NotContains(t, attrs, attribute.String("http.client_ip", "0.0.0.0")) + assert.NotContains(t, attrs, attribute.String("client.address", "0.0.0.0")) } }) } diff --git a/otelfiber/semconv.go b/otelfiber/semconv.go index 2cf89544..1e540bf8 100644 --- a/otelfiber/semconv.go +++ b/otelfiber/semconv.go @@ -7,23 +7,20 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/utils" "go.opentelemetry.io/otel/attribute" - semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) func httpServerMetricAttributesFromRequest(c *fiber.Ctx, cfg config) []attribute.KeyValue { + protocolAttributes := httpNetworkProtocolAttributes(c) attrs := []attribute.KeyValue{ - httpFlavorAttribute(c), - semconv.HTTPMethodKey.String(utils.CopyString(c.Method())), - semconv.HTTPSchemeKey.String(utils.CopyString(c.Protocol())), - semconv.NetHostNameKey.String(utils.CopyString(c.Hostname())), + semconv.URLScheme(utils.CopyString(c.Protocol())), + semconv.ServerAddress(utils.CopyString(c.Hostname())), + semconv.HTTPRequestMethodKey.String(utils.CopyString(c.Method())), } + attrs = append(attrs, protocolAttributes...) if cfg.Port != nil { - attrs = append(attrs, semconv.NetHostPortKey.Int(*cfg.Port)) - } - - if cfg.ServerName != nil { - attrs = append(attrs, semconv.HTTPServerNameKey.String(*cfg.ServerName)) + attrs = append(attrs, semconv.ServerPort(*cfg.Port)) } if cfg.CustomMetricAttributes != nil { @@ -34,36 +31,35 @@ func httpServerMetricAttributesFromRequest(c *fiber.Ctx, cfg config) []attribute } func httpServerTraceAttributesFromRequest(c *fiber.Ctx, cfg config) []attribute.KeyValue { + protocolAttributes := httpNetworkProtocolAttributes(c) attrs := []attribute.KeyValue{ - httpFlavorAttribute(c), // utils.CopyString: we need to copy the string as fasthttp strings are by default // mutable so it will be unsafe to use in this middleware as it might be used after // the handler returns. - semconv.HTTPMethodKey.String(utils.CopyString(c.Method())), - semconv.HTTPRequestContentLengthKey.Int(c.Request().Header.ContentLength()), - semconv.HTTPSchemeKey.String(utils.CopyString(c.Protocol())), - semconv.HTTPTargetKey.String(string(utils.CopyBytes(c.Request().RequestURI()))), - semconv.HTTPURLKey.String(utils.CopyString(c.OriginalURL())), - semconv.HTTPUserAgentKey.String(string(utils.CopyBytes(c.Request().Header.UserAgent()))), - semconv.NetHostNameKey.String(utils.CopyString(c.Hostname())), + semconv.HTTPRequestMethodKey.String(utils.CopyString(c.Method())), + semconv.URLScheme(utils.CopyString(c.Protocol())), + semconv.HTTPRequestBodySize(c.Request().Header.ContentLength()), + semconv.URLPath(string(utils.CopyBytes(c.Request().RequestURI()))), + semconv.URLQuery(c.Request().URI().QueryArgs().String()), + semconv.URLFull(utils.CopyString(c.OriginalURL())), + semconv.UserAgentOriginal(string(utils.CopyBytes(c.Request().Header.UserAgent()))), + semconv.ServerAddress(utils.CopyString(c.Hostname())), semconv.NetTransportTCP, } + attrs = append(attrs, protocolAttributes...) if cfg.Port != nil { attrs = append(attrs, semconv.NetHostPortKey.Int(*cfg.Port)) } - if cfg.ServerName != nil { - attrs = append(attrs, semconv.HTTPServerNameKey.String(*cfg.ServerName)) - } - if username, ok := HasBasicAuth(c.Get(fiber.HeaderAuthorization)); ok { attrs = append(attrs, semconv.EnduserIDKey.String(utils.CopyString(username))) } + if cfg.collectClientIP { clientIP := c.IP() if len(clientIP) > 0 { - attrs = append(attrs, semconv.HTTPClientIPKey.String(utils.CopyString(clientIP))) + attrs = append(attrs, semconv.ClientAddress(utils.CopyString(clientIP))) } } @@ -74,12 +70,12 @@ func httpServerTraceAttributesFromRequest(c *fiber.Ctx, cfg config) []attribute. return attrs } -func httpFlavorAttribute(c *fiber.Ctx) attribute.KeyValue { +func httpNetworkProtocolAttributes(c *fiber.Ctx) []attribute.KeyValue { + httpProtocolAttributes := []attribute.KeyValue{semconv.NetworkProtocolName("http")} if c.Request().Header.IsHTTP11() { - return semconv.HTTPFlavorHTTP11 + return append(httpProtocolAttributes, semconv.NetworkProtocolVersion("1.1")) } - - return semconv.HTTPFlavorHTTP10 + return append(httpProtocolAttributes, semconv.NetworkProtocolVersion("1.0")) } func HasBasicAuth(auth string) (string, bool) {