Upgrade to OpenTelemetry Semantic Conventions v1.26.0
This commit is contained in:
parent
2f9905061e
commit
8cb1829698
21 changed files with 558 additions and 217 deletions
|
@ -6,6 +6,8 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -17,7 +19,7 @@ import (
|
|||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
@ -47,7 +49,7 @@ func NewTracing(conf *static.Tracing) (*Tracer, io.Closer, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
return NewTracer(tr, conf.CapturedRequestHeaders, conf.CapturedResponseHeaders), closer, nil
|
||||
return NewTracer(tr, conf.CapturedRequestHeaders, conf.CapturedResponseHeaders, conf.SafeQueryParams), closer, nil
|
||||
}
|
||||
|
||||
// TracerFromContext extracts the trace.Tracer from the given context.
|
||||
|
@ -122,14 +124,16 @@ func (t TracerProvider) Tracer(name string, options ...trace.TracerOption) trace
|
|||
type Tracer struct {
|
||||
trace.Tracer
|
||||
|
||||
safeQueryParams []string
|
||||
capturedRequestHeaders []string
|
||||
capturedResponseHeaders []string
|
||||
}
|
||||
|
||||
// NewTracer builds and configures a new Tracer.
|
||||
func NewTracer(tracer trace.Tracer, capturedRequestHeaders, capturedResponseHeaders []string) *Tracer {
|
||||
func NewTracer(tracer trace.Tracer, capturedRequestHeaders, capturedResponseHeaders, safeQueryParams []string) *Tracer {
|
||||
return &Tracer{
|
||||
Tracer: tracer,
|
||||
safeQueryParams: safeQueryParams,
|
||||
capturedRequestHeaders: capturedRequestHeaders,
|
||||
capturedResponseHeaders: capturedResponseHeaders,
|
||||
}
|
||||
|
@ -153,37 +157,37 @@ func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanS
|
|||
}
|
||||
|
||||
// CaptureClientRequest used to add span attributes from the request as a Client.
|
||||
// TODO: need to update the semconv package as it does not implement fully Semantic Convention v1.23.0.
|
||||
func (t *Tracer) CaptureClientRequest(span trace.Span, r *http.Request) {
|
||||
if t == nil || span == nil || r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes
|
||||
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#common-attributes
|
||||
span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method))
|
||||
span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto)))
|
||||
|
||||
// Client attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-client
|
||||
span.SetAttributes(semconv.URLFull(r.URL.String()))
|
||||
span.SetAttributes(semconv.URLScheme(r.URL.Scheme))
|
||||
// Client attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#http-client
|
||||
sURL := t.safeURL(r.URL)
|
||||
span.SetAttributes(semconv.URLFull(sURL.String()))
|
||||
span.SetAttributes(semconv.URLScheme(sURL.Scheme))
|
||||
span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent()))
|
||||
|
||||
host, port, err := net.SplitHostPort(r.URL.Host)
|
||||
host, port, err := net.SplitHostPort(sURL.Host)
|
||||
if err != nil {
|
||||
span.SetAttributes(attribute.String("network.peer.address", host))
|
||||
span.SetAttributes(semconv.ServerAddress(r.URL.Host))
|
||||
switch r.URL.Scheme {
|
||||
span.SetAttributes(semconv.NetworkPeerAddress(host))
|
||||
span.SetAttributes(semconv.ServerAddress(sURL.Host))
|
||||
switch sURL.Scheme {
|
||||
case "http":
|
||||
span.SetAttributes(attribute.String("network.peer.port", "80"))
|
||||
span.SetAttributes(semconv.NetworkPeerPort(80))
|
||||
span.SetAttributes(semconv.ServerPort(80))
|
||||
case "https":
|
||||
span.SetAttributes(attribute.String("network.peer.port", "443"))
|
||||
span.SetAttributes(semconv.NetworkPeerPort(443))
|
||||
span.SetAttributes(semconv.ServerPort(443))
|
||||
}
|
||||
} else {
|
||||
span.SetAttributes(attribute.String("network.peer.address", host))
|
||||
span.SetAttributes(attribute.String("network.peer.port", port))
|
||||
span.SetAttributes(semconv.NetworkPeerAddress(host))
|
||||
intPort, _ := strconv.Atoi(port)
|
||||
span.SetAttributes(semconv.NetworkPeerPort(intPort))
|
||||
span.SetAttributes(semconv.ServerAddress(host))
|
||||
span.SetAttributes(semconv.ServerPort(intPort))
|
||||
}
|
||||
|
@ -201,20 +205,20 @@ func (t *Tracer) CaptureClientRequest(span trace.Span, r *http.Request) {
|
|||
}
|
||||
|
||||
// CaptureServerRequest used to add span attributes from the request as a Server.
|
||||
// TODO: need to update the semconv package as it does not implement fully Semantic Convention v1.23.0.
|
||||
func (t *Tracer) CaptureServerRequest(span trace.Span, r *http.Request) {
|
||||
if t == nil || span == nil || r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes
|
||||
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#common-attributes
|
||||
span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method))
|
||||
span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto)))
|
||||
|
||||
// Server attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-server-semantic-conventions
|
||||
sURL := t.safeURL(r.URL)
|
||||
// Server attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#http-server-semantic-conventions
|
||||
span.SetAttributes(semconv.HTTPRequestBodySize(int(r.ContentLength)))
|
||||
span.SetAttributes(semconv.URLPath(r.URL.Path))
|
||||
span.SetAttributes(semconv.URLQuery(r.URL.RawQuery))
|
||||
span.SetAttributes(semconv.URLPath(sURL.Path))
|
||||
span.SetAttributes(semconv.URLQuery(sURL.RawQuery))
|
||||
span.SetAttributes(semconv.URLScheme(r.Header.Get("X-Forwarded-Proto")))
|
||||
span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent()))
|
||||
span.SetAttributes(semconv.ServerAddress(r.Host))
|
||||
|
@ -222,17 +226,15 @@ func (t *Tracer) CaptureServerRequest(span trace.Span, r *http.Request) {
|
|||
host, port, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
span.SetAttributes(semconv.ClientAddress(r.RemoteAddr))
|
||||
span.SetAttributes(attribute.String("network.peer.address", r.RemoteAddr))
|
||||
span.SetAttributes(semconv.NetworkPeerAddress(r.Host))
|
||||
} else {
|
||||
span.SetAttributes(attribute.String("network.peer.address", host))
|
||||
span.SetAttributes(attribute.String("network.peer.port", port))
|
||||
span.SetAttributes(semconv.NetworkPeerAddress(host))
|
||||
span.SetAttributes(semconv.ClientAddress(host))
|
||||
intPort, _ := strconv.Atoi(port)
|
||||
span.SetAttributes(semconv.ClientPort(intPort))
|
||||
span.SetAttributes(semconv.NetworkPeerPort(intPort))
|
||||
}
|
||||
|
||||
span.SetAttributes(semconv.ClientSocketAddress(r.Header.Get("X-Forwarded-For")))
|
||||
|
||||
for _, header := range t.capturedRequestHeaders {
|
||||
// User-agent is already part of the semantic convention as a recommended attribute.
|
||||
if strings.EqualFold(header, "User-Agent") {
|
||||
|
@ -273,6 +275,32 @@ func (t *Tracer) CaptureResponse(span trace.Span, responseHeaders http.Header, c
|
|||
}
|
||||
}
|
||||
|
||||
func (t *Tracer) safeURL(originalURL *url.URL) *url.URL {
|
||||
if originalURL == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
redactedURL := *originalURL
|
||||
|
||||
// Redact password if exists.
|
||||
if redactedURL.User != nil {
|
||||
redactedURL.User = url.UserPassword("REDACTED", "REDACTED")
|
||||
}
|
||||
|
||||
// Redact query parameters.
|
||||
query := redactedURL.Query()
|
||||
for k := range query {
|
||||
if slices.Contains(t.safeQueryParams, k) {
|
||||
continue
|
||||
}
|
||||
|
||||
query.Set(k, "REDACTED")
|
||||
}
|
||||
redactedURL.RawQuery = query.Encode()
|
||||
|
||||
return &redactedURL
|
||||
}
|
||||
|
||||
func proto(proto string) string {
|
||||
switch proto {
|
||||
case "HTTP/1.0":
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue