Skip to content

Commit

Permalink
Merge pull request #39 from krakend/sem_conv_1_27
Browse files Browse the repository at this point in the history
add strict semantic convention 1.27 support
  • Loading branch information
kpacha authored Jan 10, 2025
2 parents 1b34722 + 755d185 commit d238a36
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 55 deletions.
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type GlobalOpts struct {
ReportHeaders bool `json:"report_headers"`
MetricsStaticAttributes Attributes `json:"metrics_static_attributes"`
TracesStaticAttributes Attributes `json:"traces_static_attributes"`
SemConv string `json:"semantic_convention"`
}

// PipeOpts has the options for the KrakenD pipe stage
Expand Down
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
module github.com/krakend/krakend-otel

go 1.21
go 1.22.0

toolchain go1.23.0
toolchain go1.23.3

require (
github.com/gin-gonic/gin v1.9.1
github.com/luraproject/lura/v2 v2.6.2
github.com/prometheus/client_golang v1.18.0
go.opentelemetry.io/otel v1.28.0
go.opentelemetry.io/otel v1.33.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0
go.opentelemetry.io/otel/exporters/prometheus v0.46.0
go.opentelemetry.io/otel/metric v1.28.0
go.opentelemetry.io/otel/metric v1.33.0
go.opentelemetry.io/otel/sdk v1.28.0
go.opentelemetry.io/otel/sdk/metric v1.28.0
go.opentelemetry.io/otel/trace v1.28.0
go.opentelemetry.io/otel/trace v1.33.0
)

require (
Expand Down Expand Up @@ -51,6 +51,7 @@ require (
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/valyala/fastrand v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/arch v0.3.0 // indirect
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand All @@ -89,16 +89,18 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg=
Expand All @@ -107,20 +109,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9RO
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0 h1:I8WIFXR351FoLJYuloU4EgXbtNX2URfU/85pUPheIEQ=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0/go.mod h1:ztwVUHe5DTR/1v7PeuGRnU5Bbd4QKYwApWmuutKsJSs=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
Expand Down
168 changes: 144 additions & 24 deletions http/client/transport_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package client
import (
"context"
"errors"
"net/http"
"strconv"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/semconv/v1.21.0"
v127 "go.opentelemetry.io/otel/semconv/v1.27.0"

kotelconfig "github.com/krakend/krakend-otel/config"
)
Expand All @@ -19,6 +23,7 @@ type TransportMetricsOptions struct {
ReadPayload bool // provide metrics for the reading the full body
DetailedConnection bool // provide detailed metrics about the connection: dns lookup, tls ...
FixedAttributes []attribute.KeyValue // "static" attributes set at config time.
SemConv string // to use the latest metric names conventions
}

// Enabled tells if metrics should be reported for the transport.
Expand All @@ -37,7 +42,8 @@ type transportMetrics struct {
// the value of the Content-Length header for the request (not the
// actual written bytes of the request, that might be cancelled
// when it is already on flight.
requestContentLength metric.Int64Counter
requestContentLength metric.Int64Counter
requestContentLengthHist metric.Int64Histogram

responseLatency metric.Float64Histogram

Expand All @@ -56,18 +62,19 @@ type transportMetrics struct {
clientName string
}

func newTransportMetrics(metricsOpts *TransportMetricsOptions, meter metric.Meter, clientName string) *transportMetrics {
if meter == nil {
return nil
}
type metricFillerFn func(*TransportMetricsOptions, metric.Meter, *transportMetrics)

func noSemConvMetricsFiller(metricsOpts *TransportMetricsOptions, meter metric.Meter, tm *transportMetrics) {
nopMeter := noop.Meter{}

var tm transportMetrics
tm.requestsStarted, _ = meter.Int64Counter("http.client.request.started.count") // number of reqs started
tm.requestsFailed, _ = meter.Int64Counter("http.client.request.failed.count") // number of reqs failed
tm.requestsCanceled, _ = meter.Int64Counter("http.client.request.canceled.count") // number of canceled requests
tm.requestsTimedOut, _ = meter.Int64Counter("http.client.request.timedout.count") // numer of timedout request (inclued in failed)

tm.requestContentLength, _ = meter.Int64Counter("http.client.request.size") // the value of the Content-Length header for the request
// For non implemented metrics that can be used with other config, we use a noop meter:
tm.requestContentLengthHist, _ = nopMeter.Int64Histogram(v127.HTTPClientRequestBodySizeName)

tm.responseLatency, _ = meter.Float64Histogram("http.client.duration", kotelconfig.TimeBucketsOpt)
tm.responseContentLength, _ = meter.Int64Histogram("http.client.response.size", kotelconfig.SizeBucketsOpt)
Expand All @@ -77,38 +84,105 @@ func newTransportMetrics(metricsOpts *TransportMetricsOptions, meter metric.Mete
tm.getConnLatency, _ = meter.Float64Histogram("http.client.request.get-conn.duration", kotelconfig.TimeBucketsOpt)
tm.dnsLatency, _ = meter.Float64Histogram("http.client.request.dns.duration", kotelconfig.TimeBucketsOpt)
tm.tlsLatency, _ = meter.Float64Histogram("http.client.request.tls.duration", kotelconfig.TimeBucketsOpt)
return &tm
}

func (m *transportMetrics) report(rtt *roundTripTracking, attrs []attribute.KeyValue) {
if m == nil || m.requestsStarted == nil {
// if metrics are nil or not initialized, we just return
func semConv1_27MetricsFiller(metricsOpts *TransportMetricsOptions, meter metric.Meter, tm *transportMetrics) {
nopMeter := noop.Meter{}

tm.detailsEnabled = metricsOpts.DetailedConnection

// For non implemented metrics that can be used with other config, we use a noop meter:
tm.requestContentLength, _ = nopMeter.Int64Counter("http.client.request.size")

// WARNING: Stability => Experimental (subject to change in the future)
tm.requestContentLengthHist, _ = meter.Int64Histogram(v127.HTTPClientRequestBodySizeName,
metric.WithUnit(v127.HTTPClientRequestBodySizeUnit),
metric.WithDescription(v127.HTTPClientRequestBodySizeDescription),
kotelconfig.SizeBucketsOpt) // the value of the Content-Length header for the request

// this is `http.client.request.duration`, and is a required metric:
// https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpclientrequestduration
tm.responseLatency, _ = meter.Float64Histogram(v127.HTTPClientRequestDurationName,
metric.WithUnit(v127.HTTPClientRequestDurationUnit),
metric.WithDescription(v127.HTTPClientRequestDurationDescription),
kotelconfig.TimeBucketsOpt)

// WARNING: Stability => Experimental (subject to change in the future)
tm.responseContentLength, _ = meter.Int64Histogram(v127.HTTPClientResponseBodySizeName,
metric.WithUnit(v127.HTTPClientResponseBodySizeUnit),
metric.WithDescription(v127.HTTPClientResponseBodySizeDescription),
kotelconfig.SizeBucketsOpt) // the value of the Content-Length header for the response

// TODO: if we want the exact semantic convention, what should we do with our own extra data, that
// is not standarized by OTEL ? for now we only set it if the `metricsOpts.DetailedConnection` is
// set too:
if metricsOpts.DetailedConnection {
tm.requestsStarted, _ = meter.Int64Counter("http.client.request.started.count") // number of reqs started
tm.requestsFailed, _ = meter.Int64Counter("http.client.request.failed.count") // number of reqs failed
tm.requestsCanceled, _ = meter.Int64Counter("http.client.request.canceled.count") // number of canceled requests
tm.requestsTimedOut, _ = meter.Int64Counter("http.client.request.timedout.count") // numer of timedout request (inclued in failed)

tm.responseNoContentLength, _ = meter.Int64Counter("http.client.response.no-content-length",
metric.WithUnit(v127.HTTPClientResponseBodySizeUnit),
metric.WithDescription("Client received responses that do not have 'Content-Length' value set"))
tm.getConnLatency, _ = meter.Float64Histogram("http.client.request.get-conn.duration",
metric.WithUnit(v127.HTTPClientRequestDurationUnit),
metric.WithDescription("Time spent acquiring a client connection"),
kotelconfig.TimeBucketsOpt)
tm.dnsLatency, _ = meter.Float64Histogram("http.client.request.dns.duration",
metric.WithUnit(v127.HTTPClientRequestDurationUnit),
metric.WithDescription("Time spent resolving the DNS name"),
kotelconfig.TimeBucketsOpt)
tm.tlsLatency, _ = meter.Float64Histogram("http.client.request.tls.duration",
metric.WithUnit(v127.HTTPClientRequestDurationUnit),
metric.WithDescription("Time spent on TLS negotiation and connection"),
kotelconfig.TimeBucketsOpt)
return
}
tm.requestsStarted, _ = nopMeter.Int64Counter("http.client.request.started.count") // number of reqs started
tm.requestsFailed, _ = nopMeter.Int64Counter("http.client.request.failed.count") // number of reqs failed
tm.requestsCanceled, _ = nopMeter.Int64Counter("http.client.request.canceled.count") // number of canceled requests
tm.requestsTimedOut, _ = nopMeter.Int64Counter("http.client.request.timedout.count") // numer of timedout request (inclued in failed)

attrM := make([]attribute.KeyValue, len(attrs), len(attrs)+4)
copy(attrM, attrs)
if len(m.clientName) > 0 {
attrM = append(attrM, attribute.Key("clientname").String(m.clientName))
tm.responseNoContentLength, _ = nopMeter.Int64Counter("http.client.response.no-content-length")
tm.getConnLatency, _ = nopMeter.Float64Histogram("http.client.request.get-conn.duration")
tm.dnsLatency, _ = nopMeter.Float64Histogram("http.client.request.dns.duration")
tm.tlsLatency, _ = nopMeter.Float64Histogram("http.client.request.tls.duration")
}

func newTransportMetrics(metricsOpts *TransportMetricsOptions, meter metric.Meter, clientName string) *transportMetrics {
if meter == nil {
return nil
}
attrM = append(attrM, semconv.HTTPRequestMethodKey.String(rtt.req.Method))
attrM = append(attrM, semconv.ServerAddress(rtt.req.RemoteAddr))

statusCode := 0
if rtt.err == nil {
// if we fail on the client side, we do not have a status code, but we
// want it set to 0 to be displayed on the dashboard
statusCode = int(rtt.resp.StatusCode)
supportedSemConv := map[string]metricFillerFn{
"": noSemConvMetricsFiller,
"1.27": semConv1_27MetricsFiller,
}
attrM = append(attrM, semconv.HTTPResponseStatusCode(statusCode))
attrOpt := metric.WithAttributeSet(attribute.NewSet(attrM...))
tm := transportMetrics{
clientName: clientName,
}
filler := noSemConvMetricsFiller
if versionFiller, ok := supportedSemConv[metricsOpts.SemConv]; ok {
filler = versionFiller
}
filler(metricsOpts, meter, &tm)
return &tm
}

func (m *transportMetrics) report(rtt *roundTripTracking, attrs []attribute.KeyValue) {
if m == nil || m.requestsStarted == nil {
return
}
attrOpt := m.attributesOption(rtt, attrs)
ctx := rtt.req.Context()

m.requestsStarted.Add(ctx, 1, attrOpt)
if rtt.req.ContentLength >= 0 {
// TOOD: should we check the http verb / method to report this ?
m.requestContentLength.Add(ctx, rtt.req.ContentLength, attrOpt)
// the content-length is optional and experimental for 1.27 and also 1.29 sem conv:
// https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpclientrequestbodysize
m.requestContentLengthHist.Record(ctx, rtt.req.ContentLength, attrOpt)
}

if rtt.err != nil {
Expand All @@ -128,11 +202,15 @@ func (m *transportMetrics) report(rtt *roundTripTracking, attrs []attribute.KeyV
}
}

// the `http.client.request.duration` is required for semconv 1.27 and 1.29
m.responseLatency.Record(ctx, rtt.latencyInSecs, attrOpt)

if rtt.req.Method != "HEAD" && rtt.resp != nil {
if rtt.resp.ContentLength >= 0 {
// it might be the case were we receive a chunked response, and then
// we will not record a metric for it.
// the `http.client.response.body.size` is optional and experimental
// for semconv 1.27 and 1.29
m.responseContentLength.Record(ctx, rtt.resp.ContentLength, attrOpt)
} else {
m.responseNoContentLength.Add(ctx, 1, attrOpt)
Expand All @@ -145,3 +223,45 @@ func (m *transportMetrics) report(rtt *roundTripTracking, attrs []attribute.KeyV
m.tlsLatency.Record(ctx, rtt.tlsLatency, attrOpt)
}
}

func (m *transportMetrics) attributesOption(rtt *roundTripTracking, attrs []attribute.KeyValue) metric.MeasurementOption {
numAttrs := len(attrs) + 4 + 1 // static attrs + required attributes + clientname
attrM := make([]attribute.KeyValue, len(attrs), numAttrs)
copy(attrM, attrs)
if len(m.clientName) > 0 {
attrM = append(attrM, attribute.Key("clientname").String(m.clientName))
}

serverAddress, serverPort := requestServerAndPort(rtt.req)

statusCode := 0
if rtt.err == nil {
// if we fail on the client side, we do not have a status code, but we
// want it set to 0 to be displayed on the dashboard
statusCode = int(rtt.resp.StatusCode)
}

attrM = append(attrM,
semconv.HTTPRequestMethodKey.String(rtt.req.Method), // required
// this is wrong, as the RemoteAddr is ignored when the request is used
// for a client (is filled by the server side):
// semconv.ServerAddress(rtt.req.RemoteAddr),
semconv.ServerAddress(serverAddress), // required by sem conv 1.29
semconv.ServerPort(serverPort), // required by sem conv 1.29
semconv.HTTPResponseStatusCode(statusCode), // required if received
)
return metric.WithAttributeSet(attribute.NewSet(attrM...))
}

func requestServerAndPort(r *http.Request) (string, int) {
serverAddress := r.Host
serverPort := int(80)
if r.URL != nil {
serverAddress = r.URL.Hostname()
strPort := r.URL.Port()
if p, err := strconv.ParseInt(strPort, 10, 32); err != nil {
serverPort = int(p)
}
}
return serverAddress, serverPort
}
Loading

0 comments on commit d238a36

Please sign in to comment.