vendor: go.opentelemetry.io/contrib/instrumentation/xxx v0.53.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2024-11-01 14:10:09 +01:00
parent 5e40d288c7
commit 10c5a57927
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
38 changed files with 12243 additions and 1899 deletions

View File

@ -91,7 +91,7 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.etcd.io/etcd/raft/v3 v3.5.16 // indirect go.etcd.io/etcd/raft/v3 v3.5.16 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect

View File

@ -287,8 +287,8 @@ github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU= github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk= go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk=
go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI= go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= 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/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
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 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -23,7 +12,7 @@ import (
) )
// DefaultClient is the default Client and is used by Get, Head, Post and PostForm. // DefaultClient is the default Client and is used by Get, Head, Post and PostForm.
// Please be careful of intitialization order - for example, if you change // Please be careful of initialization order - for example, if you change
// the global propagator, the DefaultClient might still be using the old one. // the global propagator, the DefaultClient might still be using the old one.
var DefaultClient = &http.Client{Transport: NewTransport(http.DefaultTransport)} var DefaultClient = &http.Client{Transport: NewTransport(http.DefaultTransport)}

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -31,10 +20,16 @@ const (
// Server HTTP metrics. // Server HTTP metrics.
const ( const (
RequestCount = "http.server.request_count" // Incoming request count total serverRequestSize = "http.server.request.size" // Incoming request bytes total
RequestContentLength = "http.server.request_content_length" // Incoming request bytes total serverResponseSize = "http.server.response.size" // Incoming response bytes total
ResponseContentLength = "http.server.response_content_length" // Incoming response bytes total serverDuration = "http.server.duration" // Incoming end to end duration, milliseconds
ServerLatency = "http.server.duration" // Incoming end to end duration, milliseconds )
// Client HTTP metrics.
const (
clientRequestSize = "http.client.request.size" // Outgoing request bytes total
clientResponseSize = "http.client.response.size" // Outgoing response bytes total
clientDuration = "http.client.duration" // Outgoing end to end duration, milliseconds
) )
// Filter is a predicate used to determine whether a given http.request should // Filter is a predicate used to determine whether a given http.request should

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -111,7 +100,7 @@ func WithPublicEndpoint() Option {
}) })
} }
// WithPublicEndpointFn runs with every request, and allows conditionnally // WithPublicEndpointFn runs with every request, and allows conditionally
// configuring the Handler to link the span with an incoming span context. If // configuring the Handler to link the span with an incoming span context. If
// this option is not provided or returns false, then the association is a // this option is not provided or returns false, then the association is a
// child association instead of a link. // child association instead of a link.

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package otelhttp provides an http.Handler and functions that are intended // Package otelhttp provides an http.Handler and functions that are intended
// to be used to add tracing by wrapping existing handlers (with Handler) and // to be used to add tracing by wrapping existing handlers (with Handler) and

View File

@ -1,32 +1,20 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
import ( import (
"io"
"net/http" "net/http"
"time" "time"
"github.com/felixge/httpsnoop" "github.com/felixge/httpsnoop"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -43,10 +31,13 @@ type middleware struct {
writeEvent bool writeEvent bool
filters []Filter filters []Filter
spanNameFormatter func(string, *http.Request) string spanNameFormatter func(string, *http.Request) string
counters map[string]metric.Int64Counter
valueRecorders map[string]metric.Float64Histogram
publicEndpoint bool publicEndpoint bool
publicEndpointFn func(*http.Request) bool publicEndpointFn func(*http.Request) bool
traceSemconv semconv.HTTPServer
requestBytesCounter metric.Int64Counter
responseBytesCounter metric.Int64Counter
serverLatencyMeasure metric.Float64Histogram
} }
func defaultHandlerFormatter(operation string, _ *http.Request) string { func defaultHandlerFormatter(operation string, _ *http.Request) string {
@ -65,6 +56,8 @@ func NewHandler(handler http.Handler, operation string, opts ...Option) http.Han
func NewMiddleware(operation string, opts ...Option) func(http.Handler) http.Handler { func NewMiddleware(operation string, opts ...Option) func(http.Handler) http.Handler {
h := middleware{ h := middleware{
operation: operation, operation: operation,
traceSemconv: semconv.NewHTTPServer(),
} }
defaultOpts := []Option{ defaultOpts := []Option{
@ -104,33 +97,27 @@ func handleErr(err error) {
} }
func (h *middleware) createMeasures() { func (h *middleware) createMeasures() {
h.counters = make(map[string]metric.Int64Counter) var err error
h.valueRecorders = make(map[string]metric.Float64Histogram) h.requestBytesCounter, err = h.meter.Int64Counter(
serverRequestSize,
requestBytesCounter, err := h.meter.Int64Counter(
RequestContentLength,
metric.WithUnit("By"), metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP request content length (uncompressed)"), metric.WithDescription("Measures the size of HTTP request messages."),
) )
handleErr(err) handleErr(err)
responseBytesCounter, err := h.meter.Int64Counter( h.responseBytesCounter, err = h.meter.Int64Counter(
ResponseContentLength, serverResponseSize,
metric.WithUnit("By"), metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP response content length (uncompressed)"), metric.WithDescription("Measures the size of HTTP response messages."),
) )
handleErr(err) handleErr(err)
serverLatencyMeasure, err := h.meter.Float64Histogram( h.serverLatencyMeasure, err = h.meter.Float64Histogram(
ServerLatency, serverDuration,
metric.WithUnit("ms"), metric.WithUnit("ms"),
metric.WithDescription("Measures the duration of HTTP request handling"), metric.WithDescription("Measures the duration of inbound HTTP requests."),
) )
handleErr(err) handleErr(err)
h.counters[RequestContentLength] = requestBytesCounter
h.counters[ResponseContentLength] = responseBytesCounter
h.valueRecorders[ServerLatency] = serverLatencyMeasure
} }
// serveHTTP sets up tracing and calls the given next http.Handler with the span // serveHTTP sets up tracing and calls the given next http.Handler with the span
@ -147,12 +134,9 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http
ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
opts := []trace.SpanStartOption{ opts := []trace.SpanStartOption{
trace.WithAttributes(semconvutil.HTTPServerRequest(h.server, r)...), trace.WithAttributes(h.traceSemconv.RequestTraceAttrs(h.server, r)...),
}
if h.server != "" {
hostAttr := semconv.NetHostName(h.server)
opts = append(opts, trace.WithAttributes(hostAttr))
} }
opts = append(opts, h.spanStartOptions...) opts = append(opts, h.spanStartOptions...)
if h.publicEndpoint || (h.publicEndpointFn != nil && h.publicEndpointFn(r.WithContext(ctx))) { if h.publicEndpoint || (h.publicEndpointFn != nil && h.publicEndpointFn(r.WithContext(ctx))) {
opts = append(opts, trace.WithNewRoot()) opts = append(opts, trace.WithNewRoot())
@ -221,61 +205,48 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http
WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc { WriteHeader: func(httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc {
return rww.WriteHeader return rww.WriteHeader
}, },
Flush: func(httpsnoop.FlushFunc) httpsnoop.FlushFunc {
return rww.Flush
},
}) })
labeler := &Labeler{} labeler, found := LabelerFromContext(ctx)
ctx = injectLabeler(ctx, labeler) if !found {
ctx = ContextWithLabeler(ctx, labeler)
}
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
setAfterServeAttributes(span, bw.read, rww.written, rww.statusCode, bw.err, rww.err) span.SetStatus(semconv.ServerStatus(rww.statusCode))
span.SetAttributes(h.traceSemconv.ResponseTraceAttrs(semconv.ResponseTelemetry{
StatusCode: rww.statusCode,
ReadBytes: bw.read.Load(),
ReadError: bw.err,
WriteBytes: rww.written,
WriteError: rww.err,
})...)
// Add metrics // Add metrics
attributes := append(labeler.Get(), semconvutil.HTTPServerRequestMetrics(h.server, r)...) attributes := append(labeler.Get(), semconvutil.HTTPServerRequestMetrics(h.server, r)...)
if rww.statusCode > 0 { if rww.statusCode > 0 {
attributes = append(attributes, semconv.HTTPStatusCode(rww.statusCode)) attributes = append(attributes, semconv.HTTPStatusCode(rww.statusCode))
} }
o := metric.WithAttributes(attributes...) o := metric.WithAttributeSet(attribute.NewSet(attributes...))
h.counters[RequestContentLength].Add(ctx, bw.read, o) addOpts := []metric.AddOption{o} // Allocate vararg slice once.
h.counters[ResponseContentLength].Add(ctx, rww.written, o) h.requestBytesCounter.Add(ctx, bw.read.Load(), addOpts...)
h.responseBytesCounter.Add(ctx, rww.written, addOpts...)
// Use floating point division here for higher precision (instead of Millisecond method). // Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond) elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond)
h.valueRecorders[ServerLatency].Record(ctx, elapsedTime, o) h.serverLatencyMeasure.Record(ctx, elapsedTime, o)
}
func setAfterServeAttributes(span trace.Span, read, wrote int64, statusCode int, rerr, werr error) {
attributes := []attribute.KeyValue{}
// TODO: Consider adding an event after each read and write, possibly as an
// option (defaulting to off), so as to not create needlessly verbose spans.
if read > 0 {
attributes = append(attributes, ReadBytesKey.Int64(read))
}
if rerr != nil && rerr != io.EOF {
attributes = append(attributes, ReadErrorKey.String(rerr.Error()))
}
if wrote > 0 {
attributes = append(attributes, WroteBytesKey.Int64(wrote))
}
if statusCode > 0 {
attributes = append(attributes, semconv.HTTPStatusCode(statusCode))
}
span.SetStatus(semconvutil.HTTPServerStatus(statusCode))
if werr != nil && werr != io.EOF {
attributes = append(attributes, WriteErrorKey.String(werr.Error()))
}
span.SetAttributes(attributes...)
} }
// WithRouteTag annotates spans and metrics with the provided route name // WithRouteTag annotates spans and metrics with the provided route name
// with HTTP route attribute. // with HTTP route attribute.
func WithRouteTag(route string, h http.Handler) http.Handler { func WithRouteTag(route string, h http.Handler) http.Handler {
attr := semconv.NewHTTPServer().Route(route)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
attr := semconv.HTTPRouteKey.String(route)
span := trace.SpanFromContext(r.Context()) span := trace.SpanFromContext(r.Context())
span.SetAttributes(attr) span.SetAttributes(attr)

View File

@ -0,0 +1,82 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import (
"fmt"
"net/http"
"os"
"strings"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
)
type ResponseTelemetry struct {
StatusCode int
ReadBytes int64
ReadError error
WriteBytes int64
WriteError error
}
type HTTPServer struct {
duplicate bool
}
// RequestTraceAttrs returns trace attributes for an HTTP request received by a
// server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
func (s HTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue {
if s.duplicate {
return append(oldHTTPServer{}.RequestTraceAttrs(server, req), newHTTPServer{}.RequestTraceAttrs(server, req)...)
}
return oldHTTPServer{}.RequestTraceAttrs(server, req)
}
// ResponseTraceAttrs returns trace attributes for telemetry from an HTTP response.
//
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted.
func (s HTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue {
if s.duplicate {
return append(oldHTTPServer{}.ResponseTraceAttrs(resp), newHTTPServer{}.ResponseTraceAttrs(resp)...)
}
return oldHTTPServer{}.ResponseTraceAttrs(resp)
}
// Route returns the attribute for the route.
func (s HTTPServer) Route(route string) attribute.KeyValue {
return oldHTTPServer{}.Route(route)
}
func NewHTTPServer() HTTPServer {
env := strings.ToLower(os.Getenv("OTEL_HTTP_CLIENT_COMPATIBILITY_MODE"))
return HTTPServer{duplicate: env == "http/dup"}
}
// ServerStatus returns a span status code and message for an HTTP status code
// value returned by a server. Status codes in the 400-499 range are not
// returned as errors.
func ServerStatus(code int) (codes.Code, string) {
if code < 100 || code >= 600 {
return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code)
}
if code >= 500 {
return codes.Error, ""
}
return codes.Unset, ""
}

View File

@ -0,0 +1,91 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import (
"net"
"net/http"
"strconv"
"strings"
"go.opentelemetry.io/otel/attribute"
semconvNew "go.opentelemetry.io/otel/semconv/v1.24.0"
)
// splitHostPort splits a network address hostport of the form "host",
// "host%zone", "[host]", "[host%zone], "host:port", "host%zone:port",
// "[host]:port", "[host%zone]:port", or ":port" into host or host%zone and
// port.
//
// An empty host is returned if it is not provided or unparsable. A negative
// port is returned if it is not provided or unparsable.
func splitHostPort(hostport string) (host string, port int) {
port = -1
if strings.HasPrefix(hostport, "[") {
addrEnd := strings.LastIndex(hostport, "]")
if addrEnd < 0 {
// Invalid hostport.
return
}
if i := strings.LastIndex(hostport[addrEnd:], ":"); i < 0 {
host = hostport[1:addrEnd]
return
}
} else {
if i := strings.LastIndex(hostport, ":"); i < 0 {
host = hostport
return
}
}
host, pStr, err := net.SplitHostPort(hostport)
if err != nil {
return
}
p, err := strconv.ParseUint(pStr, 10, 16)
if err != nil {
return
}
return host, int(p)
}
func requiredHTTPPort(https bool, port int) int { // nolint:revive
if https {
if port > 0 && port != 443 {
return port
}
} else {
if port > 0 && port != 80 {
return port
}
}
return -1
}
func serverClientIP(xForwardedFor string) string {
if idx := strings.Index(xForwardedFor, ","); idx >= 0 {
xForwardedFor = xForwardedFor[:idx]
}
return xForwardedFor
}
func netProtocol(proto string) (name string, version string) {
name, version, _ = strings.Cut(proto, "/")
name = strings.ToLower(name)
return name, version
}
var methodLookup = map[string]attribute.KeyValue{
http.MethodConnect: semconvNew.HTTPRequestMethodConnect,
http.MethodDelete: semconvNew.HTTPRequestMethodDelete,
http.MethodGet: semconvNew.HTTPRequestMethodGet,
http.MethodHead: semconvNew.HTTPRequestMethodHead,
http.MethodOptions: semconvNew.HTTPRequestMethodOptions,
http.MethodPatch: semconvNew.HTTPRequestMethodPatch,
http.MethodPost: semconvNew.HTTPRequestMethodPost,
http.MethodPut: semconvNew.HTTPRequestMethodPut,
http.MethodTrace: semconvNew.HTTPRequestMethodTrace,
}

View File

@ -0,0 +1,74 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import (
"errors"
"io"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
)
type oldHTTPServer struct{}
// RequestTraceAttrs returns trace attributes for an HTTP request received by a
// server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
func (o oldHTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue {
return semconvutil.HTTPServerRequest(server, req)
}
// ResponseTraceAttrs returns trace attributes for telemetry from an HTTP response.
//
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted.
func (o oldHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue {
attributes := []attribute.KeyValue{}
if resp.ReadBytes > 0 {
attributes = append(attributes, semconv.HTTPRequestContentLength(int(resp.ReadBytes)))
}
if resp.ReadError != nil && !errors.Is(resp.ReadError, io.EOF) {
// This is not in the semantic conventions, but is historically provided
attributes = append(attributes, attribute.String("http.read_error", resp.ReadError.Error()))
}
if resp.WriteBytes > 0 {
attributes = append(attributes, semconv.HTTPResponseContentLength(int(resp.WriteBytes)))
}
if resp.StatusCode > 0 {
attributes = append(attributes, semconv.HTTPStatusCode(resp.StatusCode))
}
if resp.WriteError != nil && !errors.Is(resp.WriteError, io.EOF) {
// This is not in the semantic conventions, but is historically provided
attributes = append(attributes, attribute.String("http.write_error", resp.WriteError.Error()))
}
return attributes
}
// Route returns the attribute for the route.
func (o oldHTTPServer) Route(route string) attribute.KeyValue {
return semconv.HTTPRoute(route)
}
// HTTPStatusCode returns the attribute for the HTTP status code.
// This is a temporary function needed by metrics. This will be removed when MetricsRequest is added.
func HTTPStatusCode(status int) attribute.KeyValue {
return semconv.HTTPStatusCode(status)
}

View File

@ -0,0 +1,197 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import (
"net/http"
"strings"
"go.opentelemetry.io/otel/attribute"
semconvNew "go.opentelemetry.io/otel/semconv/v1.24.0"
)
type newHTTPServer struct{}
// TraceRequest returns trace attributes for an HTTP request received by a
// server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
func (n newHTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue {
count := 3 // ServerAddress, Method, Scheme
var host string
var p int
if server == "" {
host, p = splitHostPort(req.Host)
} else {
// Prioritize the primary server name.
host, p = splitHostPort(server)
if p < 0 {
_, p = splitHostPort(req.Host)
}
}
hostPort := requiredHTTPPort(req.TLS != nil, p)
if hostPort > 0 {
count++
}
method, methodOriginal := n.method(req.Method)
if methodOriginal != (attribute.KeyValue{}) {
count++
}
scheme := n.scheme(req.TLS != nil)
if peer, peerPort := splitHostPort(req.RemoteAddr); peer != "" {
// The Go HTTP server sets RemoteAddr to "IP:port", this will not be a
// file-path that would be interpreted with a sock family.
count++
if peerPort > 0 {
count++
}
}
useragent := req.UserAgent()
if useragent != "" {
count++
}
clientIP := serverClientIP(req.Header.Get("X-Forwarded-For"))
if clientIP != "" {
count++
}
if req.URL != nil && req.URL.Path != "" {
count++
}
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" && protoName != "http" {
count++
}
if protoVersion != "" {
count++
}
attrs := make([]attribute.KeyValue, 0, count)
attrs = append(attrs,
semconvNew.ServerAddress(host),
method,
scheme,
)
if hostPort > 0 {
attrs = append(attrs, semconvNew.ServerPort(hostPort))
}
if methodOriginal != (attribute.KeyValue{}) {
attrs = append(attrs, methodOriginal)
}
if peer, peerPort := splitHostPort(req.RemoteAddr); peer != "" {
// The Go HTTP server sets RemoteAddr to "IP:port", this will not be a
// file-path that would be interpreted with a sock family.
attrs = append(attrs, semconvNew.NetworkPeerAddress(peer))
if peerPort > 0 {
attrs = append(attrs, semconvNew.NetworkPeerPort(peerPort))
}
}
if useragent := req.UserAgent(); useragent != "" {
attrs = append(attrs, semconvNew.UserAgentOriginal(useragent))
}
if clientIP != "" {
attrs = append(attrs, semconvNew.ClientAddress(clientIP))
}
if req.URL != nil && req.URL.Path != "" {
attrs = append(attrs, semconvNew.URLPath(req.URL.Path))
}
if protoName != "" && protoName != "http" {
attrs = append(attrs, semconvNew.NetworkProtocolName(protoName))
}
if protoVersion != "" {
attrs = append(attrs, semconvNew.NetworkProtocolVersion(protoVersion))
}
return attrs
}
func (n newHTTPServer) method(method string) (attribute.KeyValue, attribute.KeyValue) {
if method == "" {
return semconvNew.HTTPRequestMethodGet, attribute.KeyValue{}
}
if attr, ok := methodLookup[method]; ok {
return attr, attribute.KeyValue{}
}
orig := semconvNew.HTTPRequestMethodOriginal(method)
if attr, ok := methodLookup[strings.ToUpper(method)]; ok {
return attr, orig
}
return semconvNew.HTTPRequestMethodGet, orig
}
func (n newHTTPServer) scheme(https bool) attribute.KeyValue { // nolint:revive
if https {
return semconvNew.URLScheme("https")
}
return semconvNew.URLScheme("http")
}
// TraceResponse returns trace attributes for telemetry from an HTTP response.
//
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted.
func (n newHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue {
var count int
if resp.ReadBytes > 0 {
count++
}
if resp.WriteBytes > 0 {
count++
}
if resp.StatusCode > 0 {
count++
}
attributes := make([]attribute.KeyValue, 0, count)
if resp.ReadBytes > 0 {
attributes = append(attributes,
semconvNew.HTTPRequestBodySize(int(resp.ReadBytes)),
)
}
if resp.WriteBytes > 0 {
attributes = append(attributes,
semconvNew.HTTPResponseBodySize(int(resp.WriteBytes)),
)
}
if resp.StatusCode > 0 {
attributes = append(attributes,
semconvNew.HTTPResponseStatusCode(resp.StatusCode),
)
}
return attributes
}
// Route returns the attribute for the route.
func (n newHTTPServer) Route(route string) attribute.KeyValue {
return semconvNew.HTTPRoute(route)
}

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"

View File

@ -2,18 +2,7 @@
// source: internal/shared/semconvutil/httpconv.go.tmpl // source: internal/shared/semconvutil/httpconv.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
@ -24,7 +13,7 @@ import (
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0" semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
) )
// HTTPClientResponse returns trace attributes for an HTTP response received by a // HTTPClientResponse returns trace attributes for an HTTP response received by a
@ -43,14 +32,22 @@ func HTTPClientResponse(resp *http.Response) []attribute.KeyValue {
} }
// HTTPClientRequest returns trace attributes for an HTTP request made by a client. // HTTPClientRequest returns trace attributes for an HTTP request made by a client.
// The following attributes are always returned: "http.url", "http.flavor", // The following attributes are always returned: "http.url", "http.method",
// "http.method", "net.peer.name". The following attributes are returned if the // "net.peer.name". The following attributes are returned if the related values
// related values are defined in req: "net.peer.port", "http.user_agent", // are defined in req: "net.peer.port", "user_agent.original",
// "http.request_content_length", "enduser.id". // "http.request_content_length".
func HTTPClientRequest(req *http.Request) []attribute.KeyValue { func HTTPClientRequest(req *http.Request) []attribute.KeyValue {
return hc.ClientRequest(req) return hc.ClientRequest(req)
} }
// HTTPClientRequestMetrics returns metric attributes for an HTTP request made by a client.
// The following attributes are always returned: "http.method", "net.peer.name".
// The following attributes are returned if the
// related values are defined in req: "net.peer.port".
func HTTPClientRequestMetrics(req *http.Request) []attribute.KeyValue {
return hc.ClientRequestMetrics(req)
}
// HTTPClientStatus returns a span status code and message for an HTTP status code // HTTPClientStatus returns a span status code and message for an HTTP status code
// value received by a client. // value received by a client.
func HTTPClientStatus(code int) (codes.Code, string) { func HTTPClientStatus(code int) (codes.Code, string) {
@ -75,10 +72,9 @@ func HTTPClientStatus(code int) (codes.Code, string) {
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
// //
// The following attributes are always returned: "http.method", "http.scheme", // The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are // "http.target", "net.host.name". The following attributes are returned if
// returned if they related values are defined in req: "net.host.port", // they related values are defined in req: "net.host.port", "net.sock.peer.addr",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id", // "net.sock.peer.port", "user_agent.original", "http.client_ip".
// "http.client_ip".
func HTTPServerRequest(server string, req *http.Request) []attribute.KeyValue { func HTTPServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req) return hc.ServerRequest(server, req)
} }
@ -101,8 +97,8 @@ func HTTPServerRequest(server string, req *http.Request) []attribute.KeyValue {
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
// //
// The following attributes are always returned: "http.method", "http.scheme", // The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "net.host.name". The following attributes are // "net.host.name". The following attributes are returned if they related
// returned if they related values are defined in req: "net.host.port". // values are defined in req: "net.host.port".
func HTTPServerRequestMetrics(server string, req *http.Request) []attribute.KeyValue { func HTTPServerRequestMetrics(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequestMetrics(server, req) return hc.ServerRequestMetrics(server, req)
} }
@ -114,44 +110,12 @@ func HTTPServerStatus(code int) (codes.Code, string) {
return hc.ServerStatus(code) return hc.ServerStatus(code)
} }
// HTTPRequestHeader returns the contents of h as attributes.
//
// Instrumentation should require an explicit configuration of which headers to
// captured and then prune what they pass here. Including all headers can be a
// security risk - explicit configuration helps avoid leaking sensitive
// information.
//
// The User-Agent header is already captured in the http.user_agent attribute
// from ClientRequest and ServerRequest. Instrumentation may provide an option
// to capture that header here even though it is not recommended. Otherwise,
// instrumentation should filter that out of what is passed.
func HTTPRequestHeader(h http.Header) []attribute.KeyValue {
return hc.RequestHeader(h)
}
// HTTPResponseHeader returns the contents of h as attributes.
//
// Instrumentation should require an explicit configuration of which headers to
// captured and then prune what they pass here. Including all headers can be a
// security risk - explicit configuration helps avoid leaking sensitive
// information.
//
// The User-Agent header is already captured in the http.user_agent attribute
// from ClientRequest and ServerRequest. Instrumentation may provide an option
// to capture that header here even though it is not recommended. Otherwise,
// instrumentation should filter that out of what is passed.
func HTTPResponseHeader(h http.Header) []attribute.KeyValue {
return hc.ResponseHeader(h)
}
// httpConv are the HTTP semantic convention attributes defined for a version // httpConv are the HTTP semantic convention attributes defined for a version
// of the OpenTelemetry specification. // of the OpenTelemetry specification.
type httpConv struct { type httpConv struct {
NetConv *netConv NetConv *netConv
EnduserIDKey attribute.Key
HTTPClientIPKey attribute.Key HTTPClientIPKey attribute.Key
HTTPFlavorKey attribute.Key
HTTPMethodKey attribute.Key HTTPMethodKey attribute.Key
HTTPRequestContentLengthKey attribute.Key HTTPRequestContentLengthKey attribute.Key
HTTPResponseContentLengthKey attribute.Key HTTPResponseContentLengthKey attribute.Key
@ -161,15 +125,13 @@ type httpConv struct {
HTTPStatusCodeKey attribute.Key HTTPStatusCodeKey attribute.Key
HTTPTargetKey attribute.Key HTTPTargetKey attribute.Key
HTTPURLKey attribute.Key HTTPURLKey attribute.Key
HTTPUserAgentKey attribute.Key UserAgentOriginalKey attribute.Key
} }
var hc = &httpConv{ var hc = &httpConv{
NetConv: nc, NetConv: nc,
EnduserIDKey: semconv.EnduserIDKey,
HTTPClientIPKey: semconv.HTTPClientIPKey, HTTPClientIPKey: semconv.HTTPClientIPKey,
HTTPFlavorKey: semconv.HTTPFlavorKey,
HTTPMethodKey: semconv.HTTPMethodKey, HTTPMethodKey: semconv.HTTPMethodKey,
HTTPRequestContentLengthKey: semconv.HTTPRequestContentLengthKey, HTTPRequestContentLengthKey: semconv.HTTPRequestContentLengthKey,
HTTPResponseContentLengthKey: semconv.HTTPResponseContentLengthKey, HTTPResponseContentLengthKey: semconv.HTTPResponseContentLengthKey,
@ -179,7 +141,7 @@ var hc = &httpConv{
HTTPStatusCodeKey: semconv.HTTPStatusCodeKey, HTTPStatusCodeKey: semconv.HTTPStatusCodeKey,
HTTPTargetKey: semconv.HTTPTargetKey, HTTPTargetKey: semconv.HTTPTargetKey,
HTTPURLKey: semconv.HTTPURLKey, HTTPURLKey: semconv.HTTPURLKey,
HTTPUserAgentKey: semconv.HTTPUserAgentKey, UserAgentOriginalKey: semconv.UserAgentOriginalKey,
} }
// ClientResponse returns attributes for an HTTP response received by a client // ClientResponse returns attributes for an HTTP response received by a client
@ -193,6 +155,10 @@ var hc = &httpConv{
// //
// append(ClientResponse(resp), ClientRequest(resp.Request)...) // append(ClientResponse(resp), ClientRequest(resp.Request)...)
func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue { func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue {
/* The following semantic conventions are returned if present:
http.status_code int
http.response_content_length int
*/
var n int var n int
if resp.StatusCode > 0 { if resp.StatusCode > 0 {
n++ n++
@ -212,11 +178,31 @@ func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue {
} }
// ClientRequest returns attributes for an HTTP request made by a client. The // ClientRequest returns attributes for an HTTP request made by a client. The
// following attributes are always returned: "http.url", "http.flavor", // following attributes are always returned: "http.url", "http.method",
// "http.method", "net.peer.name". The following attributes are returned if the // "net.peer.name". The following attributes are returned if the related values
// related values are defined in req: "net.peer.port", "http.user_agent", // are defined in req: "net.peer.port", "user_agent.original",
// "http.request_content_length", "enduser.id". // "http.request_content_length", "user_agent.original".
func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue { func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue {
/* The following semantic conventions are returned if present:
http.method string
user_agent.original string
http.url string
net.peer.name string
net.peer.port int
http.request_content_length int
*/
/* The following semantic conventions are not returned:
http.status_code This requires the response. See ClientResponse.
http.response_content_length This requires the response. See ClientResponse.
net.sock.family This requires the socket used.
net.sock.peer.addr This requires the socket used.
net.sock.peer.name This requires the socket used.
net.sock.peer.port This requires the socket used.
http.resend_count This is something outside of a single request.
net.protocol.name The value is the Request is ignored, and the go client will always use "http".
net.protocol.version The value in the Request is ignored, and the go client will always use 1.1 or 2.0.
*/
n := 3 // URL, peer name, proto, and method. n := 3 // URL, peer name, proto, and method.
var h string var h string
if req.URL != nil { if req.URL != nil {
@ -234,14 +220,10 @@ func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue {
if req.ContentLength > 0 { if req.ContentLength > 0 {
n++ n++
} }
userID, _, hasUserID := req.BasicAuth()
if hasUserID {
n++
}
attrs := make([]attribute.KeyValue, 0, n) attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.method(req.Method)) attrs = append(attrs, c.method(req.Method))
attrs = append(attrs, c.flavor(req.Proto))
var u string var u string
if req.URL != nil { if req.URL != nil {
@ -260,15 +242,43 @@ func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue {
} }
if useragent != "" { if useragent != "" {
attrs = append(attrs, c.HTTPUserAgentKey.String(useragent)) attrs = append(attrs, c.UserAgentOriginalKey.String(useragent))
} }
if l := req.ContentLength; l > 0 { if l := req.ContentLength; l > 0 {
attrs = append(attrs, c.HTTPRequestContentLengthKey.Int64(l)) attrs = append(attrs, c.HTTPRequestContentLengthKey.Int64(l))
} }
if hasUserID { return attrs
attrs = append(attrs, c.EnduserIDKey.String(userID)) }
// ClientRequestMetrics returns metric attributes for an HTTP request made by a client. The
// following attributes are always returned: "http.method", "net.peer.name".
// The following attributes are returned if the related values
// are defined in req: "net.peer.port".
func (c *httpConv) ClientRequestMetrics(req *http.Request) []attribute.KeyValue {
/* The following semantic conventions are returned if present:
http.method string
net.peer.name string
net.peer.port int
*/
n := 2 // method, peer name.
var h string
if req.URL != nil {
h = req.URL.Host
}
peer, p := firstHostPort(h, req.Header.Get("Host"))
port := requiredHTTPPort(req.URL != nil && req.URL.Scheme == "https", p)
if port > 0 {
n++
}
attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.method(req.Method), c.NetConv.PeerName(peer))
if port > 0 {
attrs = append(attrs, c.NetConv.PeerPort(port))
} }
return attrs return attrs
@ -291,18 +301,35 @@ func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue {
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
// //
// The following attributes are always returned: "http.method", "http.scheme", // The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are // "http.target", "net.host.name". The following attributes are returned if they
// returned if they related values are defined in req: "net.host.port", // related values are defined in req: "net.host.port", "net.sock.peer.addr",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id", // "net.sock.peer.port", "user_agent.original", "http.client_ip",
// "http.client_ip". // "net.protocol.name", "net.protocol.version".
func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.KeyValue { func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.KeyValue {
// TODO: This currently does not add the specification required /* The following semantic conventions are returned if present:
// `http.target` attribute. It has too high of a cardinality to safely be http.method string
// added. An alternate should be added, or this comment removed, when it is http.scheme string
// addressed by the specification. If it is ultimately decided to continue net.host.name string
// not including the attribute, the HTTPTargetKey field of the httpConv net.host.port int
// should be removed as well. net.sock.peer.addr string
net.sock.peer.port int
user_agent.original string
http.client_ip string
net.protocol.name string Note: not set if the value is "http".
net.protocol.version string
http.target string Note: doesn't include the query parameter.
*/
/* The following semantic conventions are not returned:
http.status_code This requires the response.
http.request_content_length This requires the len() of body, which can mutate it.
http.response_content_length This requires the response.
http.route This is not available.
net.sock.peer.name This would require a DNS lookup.
net.sock.host.addr The request doesn't have access to the underlying socket.
net.sock.host.port The request doesn't have access to the underlying socket.
*/
n := 4 // Method, scheme, proto, and host name. n := 4 // Method, scheme, proto, and host name.
var host string var host string
var p int var p int
@ -330,19 +357,31 @@ func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.K
if useragent != "" { if useragent != "" {
n++ n++
} }
userID, _, hasUserID := req.BasicAuth()
if hasUserID {
n++
}
clientIP := serverClientIP(req.Header.Get("X-Forwarded-For")) clientIP := serverClientIP(req.Header.Get("X-Forwarded-For"))
if clientIP != "" { if clientIP != "" {
n++ n++
} }
var target string
if req.URL != nil {
target = req.URL.Path
if target != "" {
n++
}
}
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" && protoName != "http" {
n++
}
if protoVersion != "" {
n++
}
attrs := make([]attribute.KeyValue, 0, n) attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.method(req.Method)) attrs = append(attrs, c.method(req.Method))
attrs = append(attrs, c.scheme(req.TLS != nil)) attrs = append(attrs, c.scheme(req.TLS != nil))
attrs = append(attrs, c.flavor(req.Proto))
attrs = append(attrs, c.NetConv.HostName(host)) attrs = append(attrs, c.NetConv.HostName(host))
if hostPort > 0 { if hostPort > 0 {
@ -359,17 +398,24 @@ func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.K
} }
if useragent != "" { if useragent != "" {
attrs = append(attrs, c.HTTPUserAgentKey.String(useragent)) attrs = append(attrs, c.UserAgentOriginalKey.String(useragent))
}
if hasUserID {
attrs = append(attrs, c.EnduserIDKey.String(userID))
} }
if clientIP != "" { if clientIP != "" {
attrs = append(attrs, c.HTTPClientIPKey.String(clientIP)) attrs = append(attrs, c.HTTPClientIPKey.String(clientIP))
} }
if target != "" {
attrs = append(attrs, c.HTTPTargetKey.String(target))
}
if protoName != "" && protoName != "http" {
attrs = append(attrs, c.NetConv.NetProtocolName.String(protoName))
}
if protoVersion != "" {
attrs = append(attrs, c.NetConv.NetProtocolVersion.String(protoVersion))
}
return attrs return attrs
} }
@ -391,17 +437,21 @@ func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.K
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
// //
// The following attributes are always returned: "http.method", "http.scheme", // The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "net.host.name". The following attributes are // "net.host.name". The following attributes are returned if they related
// returned if they related values are defined in req: "net.host.port". // values are defined in req: "net.host.port".
func (c *httpConv) ServerRequestMetrics(server string, req *http.Request) []attribute.KeyValue { func (c *httpConv) ServerRequestMetrics(server string, req *http.Request) []attribute.KeyValue {
// TODO: This currently does not add the specification required /* The following semantic conventions are returned if present:
// `http.target` attribute. It has too high of a cardinality to safely be http.scheme string
// added. An alternate should be added, or this comment removed, when it is http.route string
// addressed by the specification. If it is ultimately decided to continue http.method string
// not including the attribute, the HTTPTargetKey field of the httpConv http.status_code int
// should be removed as well. net.host.name string
net.host.port int
net.protocol.name string Note: not set if the value is "http".
net.protocol.version string
*/
n := 4 // Method, scheme, proto, and host name. n := 3 // Method, scheme, and host name.
var host string var host string
var p int var p int
if server == "" { if server == "" {
@ -417,16 +467,29 @@ func (c *httpConv) ServerRequestMetrics(server string, req *http.Request) []attr
if hostPort > 0 { if hostPort > 0 {
n++ n++
} }
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" {
n++
}
if protoVersion != "" {
n++
}
attrs := make([]attribute.KeyValue, 0, n) attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.methodMetric(req.Method)) attrs = append(attrs, c.methodMetric(req.Method))
attrs = append(attrs, c.scheme(req.TLS != nil)) attrs = append(attrs, c.scheme(req.TLS != nil))
attrs = append(attrs, c.flavor(req.Proto))
attrs = append(attrs, c.NetConv.HostName(host)) attrs = append(attrs, c.NetConv.HostName(host))
if hostPort > 0 { if hostPort > 0 {
attrs = append(attrs, c.NetConv.HostPort(hostPort)) attrs = append(attrs, c.NetConv.HostPort(hostPort))
} }
if protoName != "" {
attrs = append(attrs, c.NetConv.NetProtocolName.String(protoName))
}
if protoVersion != "" {
attrs = append(attrs, c.NetConv.NetProtocolVersion.String(protoVersion))
}
return attrs return attrs
} }
@ -455,21 +518,6 @@ func (c *httpConv) scheme(https bool) attribute.KeyValue { // nolint:revive
return c.HTTPSchemeHTTP return c.HTTPSchemeHTTP
} }
func (c *httpConv) flavor(proto string) attribute.KeyValue {
switch proto {
case "HTTP/1.0":
return c.HTTPFlavorKey.String("1.0")
case "HTTP/1.1":
return c.HTTPFlavorKey.String("1.1")
case "HTTP/2":
return c.HTTPFlavorKey.String("2.0")
case "HTTP/3":
return c.HTTPFlavorKey.String("3.0")
default:
return c.HTTPFlavorKey.String(proto)
}
}
func serverClientIP(xForwardedFor string) string { func serverClientIP(xForwardedFor string) string {
if idx := strings.Index(xForwardedFor, ","); idx >= 0 { if idx := strings.Index(xForwardedFor, ","); idx >= 0 {
xForwardedFor = xForwardedFor[:idx] xForwardedFor = xForwardedFor[:idx]
@ -501,31 +549,6 @@ func firstHostPort(source ...string) (host string, port int) {
return return
} }
// RequestHeader returns the contents of h as OpenTelemetry attributes.
func (c *httpConv) RequestHeader(h http.Header) []attribute.KeyValue {
return c.header("http.request.header", h)
}
// ResponseHeader returns the contents of h as OpenTelemetry attributes.
func (c *httpConv) ResponseHeader(h http.Header) []attribute.KeyValue {
return c.header("http.response.header", h)
}
func (c *httpConv) header(prefix string, h http.Header) []attribute.KeyValue {
key := func(k string) attribute.Key {
k = strings.ToLower(k)
k = strings.ReplaceAll(k, "-", "_")
k = fmt.Sprintf("%s.%s", prefix, k)
return attribute.Key(k)
}
attrs := make([]attribute.KeyValue, 0, len(h))
for k, v := range h {
attrs = append(attrs, key(k).StringSlice(v))
}
return attrs
}
// ClientStatus returns a span status code and message for an HTTP status code // ClientStatus returns a span status code and message for an HTTP status code
// value received by a client. // value received by a client.
func (c *httpConv) ClientStatus(code int) (codes.Code, string) { func (c *httpConv) ClientStatus(code int) (codes.Code, string) {

View File

@ -2,17 +2,7 @@
// source: internal/shared/semconvutil/netconv.go.tmpl // source: internal/shared/semconvutil/netconv.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// Licensed under the Apache License, Version 2.0 (the "License"); // SPDX-License-Identifier: Apache-2.0
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
@ -22,7 +12,7 @@ import (
"strings" "strings"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0" semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
) )
// NetTransport returns a trace attribute describing the transport protocol of the // NetTransport returns a trace attribute describing the transport protocol of the
@ -32,24 +22,6 @@ func NetTransport(network string) attribute.KeyValue {
return nc.Transport(network) return nc.Transport(network)
} }
// NetClient returns trace attributes for a client network connection to address.
// See net.Dial for information about acceptable address values, address should
// be the same as the one used to create conn. If conn is nil, only network
// peer attributes will be returned that describe address. Otherwise, the
// socket level information about conn will also be included.
func NetClient(address string, conn net.Conn) []attribute.KeyValue {
return nc.Client(address, conn)
}
// NetServer returns trace attributes for a network listener listening at address.
// See net.Listen for information about acceptable address values, address
// should be the same as the one used to create ln. If ln is nil, only network
// host attributes will be returned that describe address. Otherwise, the
// socket level information about ln will also be included.
func NetServer(address string, ln net.Listener) []attribute.KeyValue {
return nc.Server(address, ln)
}
// netConv are the network semantic convention attributes defined for a version // netConv are the network semantic convention attributes defined for a version
// of the OpenTelemetry specification. // of the OpenTelemetry specification.
type netConv struct { type netConv struct {
@ -57,6 +29,8 @@ type netConv struct {
NetHostPortKey attribute.Key NetHostPortKey attribute.Key
NetPeerNameKey attribute.Key NetPeerNameKey attribute.Key
NetPeerPortKey attribute.Key NetPeerPortKey attribute.Key
NetProtocolName attribute.Key
NetProtocolVersion attribute.Key
NetSockFamilyKey attribute.Key NetSockFamilyKey attribute.Key
NetSockPeerAddrKey attribute.Key NetSockPeerAddrKey attribute.Key
NetSockPeerPortKey attribute.Key NetSockPeerPortKey attribute.Key
@ -73,6 +47,8 @@ var nc = &netConv{
NetHostPortKey: semconv.NetHostPortKey, NetHostPortKey: semconv.NetHostPortKey,
NetPeerNameKey: semconv.NetPeerNameKey, NetPeerNameKey: semconv.NetPeerNameKey,
NetPeerPortKey: semconv.NetPeerPortKey, NetPeerPortKey: semconv.NetPeerPortKey,
NetProtocolName: semconv.NetProtocolNameKey,
NetProtocolVersion: semconv.NetProtocolVersionKey,
NetSockFamilyKey: semconv.NetSockFamilyKey, NetSockFamilyKey: semconv.NetSockFamilyKey,
NetSockPeerAddrKey: semconv.NetSockPeerAddrKey, NetSockPeerAddrKey: semconv.NetSockPeerAddrKey,
NetSockPeerPortKey: semconv.NetSockPeerPortKey, NetSockPeerPortKey: semconv.NetSockPeerPortKey,
@ -116,57 +92,11 @@ func (c *netConv) Host(address string) []attribute.KeyValue {
attrs := make([]attribute.KeyValue, 0, n) attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.HostName(h)) attrs = append(attrs, c.HostName(h))
if p > 0 { if p > 0 {
attrs = append(attrs, c.HostPort(int(p))) attrs = append(attrs, c.HostPort(p))
} }
return attrs return attrs
} }
// Server returns attributes for a network listener listening at address. See
// net.Listen for information about acceptable address values, address should
// be the same as the one used to create ln. If ln is nil, only network host
// attributes will be returned that describe address. Otherwise, the socket
// level information about ln will also be included.
func (c *netConv) Server(address string, ln net.Listener) []attribute.KeyValue {
if ln == nil {
return c.Host(address)
}
lAddr := ln.Addr()
if lAddr == nil {
return c.Host(address)
}
hostName, hostPort := splitHostPort(address)
sockHostAddr, sockHostPort := splitHostPort(lAddr.String())
network := lAddr.Network()
sockFamily := family(network, sockHostAddr)
n := nonZeroStr(hostName, network, sockHostAddr, sockFamily)
n += positiveInt(hostPort, sockHostPort)
attr := make([]attribute.KeyValue, 0, n)
if hostName != "" {
attr = append(attr, c.HostName(hostName))
if hostPort > 0 {
// Only if net.host.name is set should net.host.port be.
attr = append(attr, c.HostPort(hostPort))
}
}
if network != "" {
attr = append(attr, c.Transport(network))
}
if sockFamily != "" {
attr = append(attr, c.NetSockFamilyKey.String(sockFamily))
}
if sockHostAddr != "" {
attr = append(attr, c.NetSockHostAddrKey.String(sockHostAddr))
if sockHostPort > 0 {
// Only if net.sock.host.addr is set should net.sock.host.port be.
attr = append(attr, c.NetSockHostPortKey.Int(sockHostPort))
}
}
return attr
}
func (c *netConv) HostName(name string) attribute.KeyValue { func (c *netConv) HostName(name string) attribute.KeyValue {
return c.NetHostNameKey.String(name) return c.NetHostNameKey.String(name)
} }
@ -175,85 +105,6 @@ func (c *netConv) HostPort(port int) attribute.KeyValue {
return c.NetHostPortKey.Int(port) return c.NetHostPortKey.Int(port)
} }
// Client returns attributes for a client network connection to address. See
// net.Dial for information about acceptable address values, address should be
// the same as the one used to create conn. If conn is nil, only network peer
// attributes will be returned that describe address. Otherwise, the socket
// level information about conn will also be included.
func (c *netConv) Client(address string, conn net.Conn) []attribute.KeyValue {
if conn == nil {
return c.Peer(address)
}
lAddr, rAddr := conn.LocalAddr(), conn.RemoteAddr()
var network string
switch {
case lAddr != nil:
network = lAddr.Network()
case rAddr != nil:
network = rAddr.Network()
default:
return c.Peer(address)
}
peerName, peerPort := splitHostPort(address)
var (
sockFamily string
sockPeerAddr string
sockPeerPort int
sockHostAddr string
sockHostPort int
)
if lAddr != nil {
sockHostAddr, sockHostPort = splitHostPort(lAddr.String())
}
if rAddr != nil {
sockPeerAddr, sockPeerPort = splitHostPort(rAddr.String())
}
switch {
case sockHostAddr != "":
sockFamily = family(network, sockHostAddr)
case sockPeerAddr != "":
sockFamily = family(network, sockPeerAddr)
}
n := nonZeroStr(peerName, network, sockPeerAddr, sockHostAddr, sockFamily)
n += positiveInt(peerPort, sockPeerPort, sockHostPort)
attr := make([]attribute.KeyValue, 0, n)
if peerName != "" {
attr = append(attr, c.PeerName(peerName))
if peerPort > 0 {
// Only if net.peer.name is set should net.peer.port be.
attr = append(attr, c.PeerPort(peerPort))
}
}
if network != "" {
attr = append(attr, c.Transport(network))
}
if sockFamily != "" {
attr = append(attr, c.NetSockFamilyKey.String(sockFamily))
}
if sockPeerAddr != "" {
attr = append(attr, c.NetSockPeerAddrKey.String(sockPeerAddr))
if sockPeerPort > 0 {
// Only if net.sock.peer.addr is set should net.sock.peer.port be.
attr = append(attr, c.NetSockPeerPortKey.Int(sockPeerPort))
}
}
if sockHostAddr != "" {
attr = append(attr, c.NetSockHostAddrKey.String(sockHostAddr))
if sockHostPort > 0 {
// Only if net.sock.host.addr is set should net.sock.host.port be.
attr = append(attr, c.NetSockHostPortKey.Int(sockHostPort))
}
}
return attr
}
func family(network, address string) string { func family(network, address string) string {
switch network { switch network {
case "unix", "unixgram", "unixpacket": case "unix", "unixgram", "unixpacket":
@ -269,26 +120,6 @@ func family(network, address string) string {
return "" return ""
} }
func nonZeroStr(strs ...string) int {
var n int
for _, str := range strs {
if str != "" {
n++
}
}
return n
}
func positiveInt(ints ...int) int {
var n int
for _, i := range ints {
if i > 0 {
n++
}
}
return n
}
// Peer returns attributes for a network peer address. // Peer returns attributes for a network peer address.
func (c *netConv) Peer(address string) []attribute.KeyValue { func (c *netConv) Peer(address string) []attribute.KeyValue {
h, p := splitHostPort(address) h, p := splitHostPort(address)
@ -307,7 +138,7 @@ func (c *netConv) Peer(address string) []attribute.KeyValue {
attrs := make([]attribute.KeyValue, 0, n) attrs := make([]attribute.KeyValue, 0, n)
attrs = append(attrs, c.PeerName(h)) attrs = append(attrs, c.PeerName(h))
if p > 0 { if p > 0 {
attrs = append(attrs, c.PeerPort(int(p))) attrs = append(attrs, c.PeerPort(p))
} }
return attrs return attrs
} }
@ -366,3 +197,9 @@ func splitHostPort(hostport string) (host string, port int) {
} }
return host, int(p) return host, int(p)
} }
func netProtocol(proto string) (name string, version string) {
name, version, _ = strings.Cut(proto, "/")
name = strings.ToLower(name)
return name, version
}

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -48,8 +37,12 @@ type labelerContextKeyType int
const lablelerContextKey labelerContextKeyType = 0 const lablelerContextKey labelerContextKeyType = 0
func injectLabeler(ctx context.Context, l *Labeler) context.Context { // ContextWithLabeler returns a new context with the provided Labeler instance.
return context.WithValue(ctx, lablelerContextKey, l) // Attributes added to the specified labeler will be injected into metrics
// emitted by the instrumentation. Only one labeller can be injected into the
// context. Injecting it multiple times will override the previous calls.
func ContextWithLabeler(parent context.Context, l *Labeler) context.Context {
return context.WithValue(parent, lablelerContextKey, l)
} }
// LabelerFromContext retrieves a Labeler instance from the provided context if // LabelerFromContext retrieves a Labeler instance from the provided context if

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -19,31 +8,42 @@ import (
"io" "io"
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"sync/atomic"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
// Transport implements the http.RoundTripper interface and wraps // Transport implements the http.RoundTripper interface and wraps
// outbound HTTP(S) requests with a span. // outbound HTTP(S) requests with a span and enriches it with metrics.
type Transport struct { type Transport struct {
rt http.RoundTripper rt http.RoundTripper
tracer trace.Tracer tracer trace.Tracer
meter metric.Meter
propagators propagation.TextMapPropagator propagators propagation.TextMapPropagator
spanStartOptions []trace.SpanStartOption spanStartOptions []trace.SpanStartOption
filters []Filter filters []Filter
spanNameFormatter func(string, *http.Request) string spanNameFormatter func(string, *http.Request) string
clientTrace func(context.Context) *httptrace.ClientTrace clientTrace func(context.Context) *httptrace.ClientTrace
requestBytesCounter metric.Int64Counter
responseBytesCounter metric.Int64Counter
latencyMeasure metric.Float64Histogram
} }
var _ http.RoundTripper = &Transport{} var _ http.RoundTripper = &Transport{}
// NewTransport wraps the provided http.RoundTripper with one that // NewTransport wraps the provided http.RoundTripper with one that
// starts a span and injects the span context into the outbound request headers. // starts a span, injects the span context into the outbound request headers,
// and enriches it with metrics.
// //
// If the provided http.RoundTripper is nil, http.DefaultTransport will be used // If the provided http.RoundTripper is nil, http.DefaultTransport will be used
// as the base http.RoundTripper. // as the base http.RoundTripper.
@ -63,12 +63,14 @@ func NewTransport(base http.RoundTripper, opts ...Option) *Transport {
c := newConfig(append(defaultOpts, opts...)...) c := newConfig(append(defaultOpts, opts...)...)
t.applyConfig(c) t.applyConfig(c)
t.createMeasures()
return &t return &t
} }
func (t *Transport) applyConfig(c *config) { func (t *Transport) applyConfig(c *config) {
t.tracer = c.Tracer t.tracer = c.Tracer
t.meter = c.Meter
t.propagators = c.Propagators t.propagators = c.Propagators
t.spanStartOptions = c.SpanStartOptions t.spanStartOptions = c.SpanStartOptions
t.filters = c.Filters t.filters = c.Filters
@ -76,6 +78,30 @@ func (t *Transport) applyConfig(c *config) {
t.clientTrace = c.ClientTrace t.clientTrace = c.ClientTrace
} }
func (t *Transport) createMeasures() {
var err error
t.requestBytesCounter, err = t.meter.Int64Counter(
clientRequestSize,
metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP request messages."),
)
handleErr(err)
t.responseBytesCounter, err = t.meter.Int64Counter(
clientResponseSize,
metric.WithUnit("By"),
metric.WithDescription("Measures the size of HTTP response messages."),
)
handleErr(err)
t.latencyMeasure, err = t.meter.Float64Histogram(
clientDuration,
metric.WithUnit("ms"),
metric.WithDescription("Measures the duration of outbound HTTP requests."),
)
handleErr(err)
}
func defaultTransportFormatter(_ string, r *http.Request) string { func defaultTransportFormatter(_ string, r *http.Request) string {
return "HTTP " + r.Method return "HTTP " + r.Method
} }
@ -84,6 +110,7 @@ func defaultTransportFormatter(_ string, r *http.Request) string {
// before handing the request to the configured base RoundTripper. The created span will // before handing the request to the configured base RoundTripper. The created span will
// end when the response body is closed or when a read from the body returns io.EOF. // end when the response body is closed or when a read from the body returns io.EOF.
func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) { func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
requestStartTime := time.Now()
for _, f := range t.filters { for _, f := range t.filters {
if !f(r) { if !f(r) {
// Simply pass through to the base RoundTripper if a filter rejects the request // Simply pass through to the base RoundTripper if a filter rejects the request
@ -109,7 +136,25 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
ctx = httptrace.WithClientTrace(ctx, t.clientTrace(ctx)) ctx = httptrace.WithClientTrace(ctx, t.clientTrace(ctx))
} }
labeler, found := LabelerFromContext(ctx)
if !found {
ctx = ContextWithLabeler(ctx, labeler)
}
r = r.Clone(ctx) // According to RoundTripper spec, we shouldn't modify the origin request. r = r.Clone(ctx) // According to RoundTripper spec, we shouldn't modify the origin request.
// use a body wrapper to determine the request size
var bw bodyWrapper
// if request body is nil or NoBody, we don't want to mutate the body as it
// will affect the identity of it in an unforeseeable way because we assert
// ReadCloser fulfills a certain interface and it is indeed nil or NoBody.
if r.Body != nil && r.Body != http.NoBody {
bw.ReadCloser = r.Body
// noop to prevent nil panic. not using this record fun yet.
bw.record = func(int64) {}
r.Body = &bw
}
span.SetAttributes(semconvutil.HTTPClientRequest(r)...) span.SetAttributes(semconvutil.HTTPClientRequest(r)...)
t.propagators.Inject(ctx, propagation.HeaderCarrier(r.Header)) t.propagators.Inject(ctx, propagation.HeaderCarrier(r.Header))
@ -121,9 +166,29 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
return res, err return res, err
} }
// metrics
metricAttrs := append(labeler.Get(), semconvutil.HTTPClientRequestMetrics(r)...)
if res.StatusCode > 0 {
metricAttrs = append(metricAttrs, semconv.HTTPStatusCode(res.StatusCode))
}
o := metric.WithAttributeSet(attribute.NewSet(metricAttrs...))
addOpts := []metric.AddOption{o} // Allocate vararg slice once.
t.requestBytesCounter.Add(ctx, bw.read.Load(), addOpts...)
// For handling response bytes we leverage a callback when the client reads the http response
readRecordFunc := func(n int64) {
t.responseBytesCounter.Add(ctx, n, addOpts...)
}
// traces
span.SetAttributes(semconvutil.HTTPClientResponse(res)...) span.SetAttributes(semconvutil.HTTPClientResponse(res)...)
span.SetStatus(semconvutil.HTTPClientStatus(res.StatusCode)) span.SetStatus(semconvutil.HTTPClientStatus(res.StatusCode))
res.Body = newWrappedBody(span, res.Body)
res.Body = newWrappedBody(span, readRecordFunc, res.Body)
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond)
t.latencyMeasure.Record(ctx, elapsedTime, o)
return res, err return res, err
} }
@ -131,17 +196,17 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
// newWrappedBody returns a new and appropriately scoped *wrappedBody as an // newWrappedBody returns a new and appropriately scoped *wrappedBody as an
// io.ReadCloser. If the passed body implements io.Writer, the returned value // io.ReadCloser. If the passed body implements io.Writer, the returned value
// will implement io.ReadWriteCloser. // will implement io.ReadWriteCloser.
func newWrappedBody(span trace.Span, body io.ReadCloser) io.ReadCloser { func newWrappedBody(span trace.Span, record func(n int64), body io.ReadCloser) io.ReadCloser {
// The successful protocol switch responses will have a body that // The successful protocol switch responses will have a body that
// implement an io.ReadWriteCloser. Ensure this interface type continues // implement an io.ReadWriteCloser. Ensure this interface type continues
// to be satisfied if that is the case. // to be satisfied if that is the case.
if _, ok := body.(io.ReadWriteCloser); ok { if _, ok := body.(io.ReadWriteCloser); ok {
return &wrappedBody{span: span, body: body} return &wrappedBody{span: span, record: record, body: body}
} }
// Remove the implementation of the io.ReadWriteCloser and only implement // Remove the implementation of the io.ReadWriteCloser and only implement
// the io.ReadCloser. // the io.ReadCloser.
return struct{ io.ReadCloser }{&wrappedBody{span: span, body: body}} return struct{ io.ReadCloser }{&wrappedBody{span: span, record: record, body: body}}
} }
// wrappedBody is the response body type returned by the transport // wrappedBody is the response body type returned by the transport
@ -153,8 +218,11 @@ func newWrappedBody(span trace.Span, body io.ReadCloser) io.ReadCloser {
// If the response body implements the io.Writer interface (i.e. for // If the response body implements the io.Writer interface (i.e. for
// successful protocol switches), the wrapped body also will. // successful protocol switches), the wrapped body also will.
type wrappedBody struct { type wrappedBody struct {
span trace.Span span trace.Span
body io.ReadCloser recorded atomic.Bool
record func(n int64)
body io.ReadCloser
read atomic.Int64
} }
var _ io.ReadWriteCloser = &wrappedBody{} var _ io.ReadWriteCloser = &wrappedBody{}
@ -171,11 +239,14 @@ func (wb *wrappedBody) Write(p []byte) (int, error) {
func (wb *wrappedBody) Read(b []byte) (int, error) { func (wb *wrappedBody) Read(b []byte) (int, error) {
n, err := wb.body.Read(b) n, err := wb.body.Read(b)
// Record the number of bytes read
wb.read.Add(int64(n))
switch err { switch err {
case nil: case nil:
// nothing to do here but fall through to the return // nothing to do here but fall through to the return
case io.EOF: case io.EOF:
wb.recordBytesRead()
wb.span.End() wb.span.End()
default: default:
wb.span.RecordError(err) wb.span.RecordError(err)
@ -184,7 +255,20 @@ func (wb *wrappedBody) Read(b []byte) (int, error) {
return n, err return n, err
} }
// recordBytesRead is a function that ensures the number of bytes read is recorded once and only once.
func (wb *wrappedBody) recordBytesRead() {
// note: it is more performant (and equally correct) to use atomic.Bool over sync.Once here. In the event that
// two goroutines are racing to call this method, the number of bytes read will no longer increase. Using
// CompareAndSwap allows later goroutines to return quickly and not block waiting for the race winner to finish
// calling wb.record(wb.read.Load()).
if wb.recorded.CompareAndSwap(false, true) {
// Record the total number of bytes read
wb.record(wb.read.Load())
}
}
func (wb *wrappedBody) Close() error { func (wb *wrappedBody) Close() error {
wb.recordBytesRead()
wb.span.End() wb.span.End()
if wb.body != nil { if wb.body != nil {
return wb.body.Close() return wb.body.Close()

View File

@ -1,22 +1,11 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
// Version is the current release version of the otelhttp instrumentation. // Version is the current release version of the otelhttp instrumentation.
func Version() string { func Version() string {
return "0.46.1" return "0.53.0"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }

View File

@ -1,16 +1,5 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// // SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@ -18,6 +7,7 @@ import (
"context" "context"
"io" "io"
"net/http" "net/http"
"sync/atomic"
"go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/propagation"
) )
@ -30,14 +20,14 @@ type bodyWrapper struct {
io.ReadCloser io.ReadCloser
record func(n int64) // must not be nil record func(n int64) // must not be nil
read int64 read atomic.Int64
err error err error
} }
func (w *bodyWrapper) Read(b []byte) (int, error) { func (w *bodyWrapper) Read(b []byte) (int, error) {
n, err := w.ReadCloser.Read(b) n, err := w.ReadCloser.Read(b)
n1 := int64(n) n1 := int64(n)
w.read += n1 w.read.Add(n1)
w.err = err w.err = err
w.record(n1) w.record(n1)
return n, err return n, err
@ -97,3 +87,13 @@ func (w *respWriterWrapper) WriteHeader(statusCode int) {
} }
w.ResponseWriter.WriteHeader(statusCode) w.ResponseWriter.WriteHeader(statusCode)
} }
func (w *respWriterWrapper) Flush() {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
if f, ok := w.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}

View File

@ -1,3 +0,0 @@
# Semconv v1.17.0
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/semconv/v1.17.0)](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.17.0)

View File

@ -0,0 +1,3 @@
# Semconv v1.20.0
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/semconv/v1.20.0)](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.20.0)

File diff suppressed because it is too large Load Diff

View File

@ -5,5 +5,5 @@
// //
// OpenTelemetry semantic conventions are agreed standardized naming // OpenTelemetry semantic conventions are agreed standardized naming
// patterns for OpenTelemetry things. This package represents the conventions // patterns for OpenTelemetry things. This package represents the conventions
// as of the v1.17.0 version of the OpenTelemetry specification. // as of the v1.20.0 version of the OpenTelemetry specification.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"

View File

@ -3,7 +3,7 @@
// Code generated from semantic convention specification. DO NOT EDIT. // Code generated from semantic convention specification. DO NOT EDIT.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"
import "go.opentelemetry.io/otel/attribute" import "go.opentelemetry.io/otel/attribute"

View File

@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"
const ( const (
// ExceptionEventName is the name of the Span event representing an exception. // ExceptionEventName is the name of the Span event representing an exception.

View File

@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"
// HTTP scheme attributes. // HTTP scheme attributes.
var ( var (

View File

@ -3,7 +3,7 @@
// Code generated from semantic convention specification. DO NOT EDIT. // Code generated from semantic convention specification. DO NOT EDIT.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"
import "go.opentelemetry.io/otel/attribute" import "go.opentelemetry.io/otel/attribute"
@ -60,22 +60,6 @@ const (
// SHOULD be left unset. // SHOULD be left unset.
BrowserMobileKey = attribute.Key("browser.mobile") BrowserMobileKey = attribute.Key("browser.mobile")
// BrowserUserAgentKey is the attribute Key conforming to the
// "browser.user_agent" semantic conventions. It represents the full
// user-agent string provided by the browser
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
// AppleWebKit/537.36 (KHTML, '
// 'like Gecko) Chrome/95.0.4638.54 Safari/537.36'
// Note: The user-agent value SHOULD be provided only from browsers that do
// not have a mechanism to retrieve brands and platform individually from
// the User-Agent Client Hints API. To retrieve the value, the legacy
// `navigator.userAgent` API can be used.
BrowserUserAgentKey = attribute.Key("browser.user_agent")
// BrowserLanguageKey is the attribute Key conforming to the // BrowserLanguageKey is the attribute Key conforming to the
// "browser.language" semantic conventions. It represents the preferred // "browser.language" semantic conventions. It represents the preferred
// language of the user using the browser // language of the user using the browser
@ -110,13 +94,6 @@ func BrowserMobile(val bool) attribute.KeyValue {
return BrowserMobileKey.Bool(val) return BrowserMobileKey.Bool(val)
} }
// BrowserUserAgent returns an attribute KeyValue conforming to the
// "browser.user_agent" semantic conventions. It represents the full user-agent
// string provided by the browser
func BrowserUserAgent(val string) attribute.KeyValue {
return BrowserUserAgentKey.String(val)
}
// BrowserLanguage returns an attribute KeyValue conforming to the // BrowserLanguage returns an attribute KeyValue conforming to the
// "browser.language" semantic conventions. It represents the preferred // "browser.language" semantic conventions. It represents the preferred
// language of the user using the browser // language of the user using the browser
@ -160,9 +137,56 @@ const (
// regions](https://azure.microsoft.com/en-us/global-infrastructure/geographies/), // regions](https://azure.microsoft.com/en-us/global-infrastructure/geographies/),
// [Google Cloud regions](https://cloud.google.com/about/locations), or // [Google Cloud regions](https://cloud.google.com/about/locations), or
// [Tencent Cloud // [Tencent Cloud
// regions](https://intl.cloud.tencent.com/document/product/213/6091). // regions](https://www.tencentcloud.com/document/product/213/6091).
CloudRegionKey = attribute.Key("cloud.region") CloudRegionKey = attribute.Key("cloud.region")
// CloudResourceIDKey is the attribute Key conforming to the
// "cloud.resource_id" semantic conventions. It represents the cloud
// provider-specific native identifier of the monitored cloud resource
// (e.g. an
// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// on AWS, a [fully qualified resource
// ID](https://learn.microsoft.com/en-us/rest/api/resources/resources/get-by-id)
// on Azure, a [full resource
// name](https://cloud.google.com/apis/design/resource_names#full_resource_name)
// on GCP)
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'arn:aws:lambda:REGION:ACCOUNT_ID:function:my-function',
// '//run.googleapis.com/projects/PROJECT_ID/locations/LOCATION_ID/services/SERVICE_ID',
// '/subscriptions/<SUBSCIPTION_GUID>/resourceGroups/<RG>/providers/Microsoft.Web/sites/<FUNCAPP>/functions/<FUNC>'
// Note: On some cloud providers, it may not be possible to determine the
// full ID at startup,
// so it may be necessary to set `cloud.resource_id` as a span attribute
// instead.
//
// The exact value to use for `cloud.resource_id` depends on the cloud
// provider.
// The following well-known definitions MUST be used if you set this
// attribute and they apply:
//
// * **AWS Lambda:** The function
// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html).
// Take care not to use the "invoked ARN" directly but replace any
// [alias
// suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html)
// with the resolved function version, as the same runtime instance may
// be invokable with
// multiple different aliases.
// * **GCP:** The [URI of the
// resource](https://cloud.google.com/iam/docs/full-resource-names)
// * **Azure:** The [Fully Qualified Resource
// ID](https://docs.microsoft.com/en-us/rest/api/resources/resources/get-by-id)
// of the invoked function,
// *not* the function app, having the form
// `/subscriptions/<SUBSCIPTION_GUID>/resourceGroups/<RG>/providers/Microsoft.Web/sites/<FUNCAPP>/functions/<FUNC>`.
// This means that a span attribute MUST be used, as an Azure function
// app can host multiple functions that would usually share
// a TracerProvider.
CloudResourceIDKey = attribute.Key("cloud.resource_id")
// CloudAvailabilityZoneKey is the attribute Key conforming to the // CloudAvailabilityZoneKey is the attribute Key conforming to the
// "cloud.availability_zone" semantic conventions. It represents the cloud // "cloud.availability_zone" semantic conventions. It represents the cloud
// regions often have multiple, isolated locations known as zones to // regions often have multiple, isolated locations known as zones to
@ -197,6 +221,8 @@ var (
CloudProviderAzure = CloudProviderKey.String("azure") CloudProviderAzure = CloudProviderKey.String("azure")
// Google Cloud Platform // Google Cloud Platform
CloudProviderGCP = CloudProviderKey.String("gcp") CloudProviderGCP = CloudProviderKey.String("gcp")
// Heroku Platform as a Service
CloudProviderHeroku = CloudProviderKey.String("heroku")
// IBM Cloud // IBM Cloud
CloudProviderIbmCloud = CloudProviderKey.String("ibm_cloud") CloudProviderIbmCloud = CloudProviderKey.String("ibm_cloud")
// Tencent Cloud // Tencent Cloud
@ -247,7 +273,7 @@ var (
// Google Cloud App Engine (GAE) // Google Cloud App Engine (GAE)
CloudPlatformGCPAppEngine = CloudPlatformKey.String("gcp_app_engine") CloudPlatformGCPAppEngine = CloudPlatformKey.String("gcp_app_engine")
// Red Hat OpenShift on Google Cloud // Red Hat OpenShift on Google Cloud
CloudPlatformGoogleCloudOpenshift = CloudPlatformKey.String("google_cloud_openshift") CloudPlatformGCPOpenshift = CloudPlatformKey.String("gcp_openshift")
// Red Hat OpenShift on IBM Cloud // Red Hat OpenShift on IBM Cloud
CloudPlatformIbmCloudOpenshift = CloudPlatformKey.String("ibm_cloud_openshift") CloudPlatformIbmCloudOpenshift = CloudPlatformKey.String("ibm_cloud_openshift")
// Tencent Cloud Cloud Virtual Machine (CVM) // Tencent Cloud Cloud Virtual Machine (CVM)
@ -272,6 +298,19 @@ func CloudRegion(val string) attribute.KeyValue {
return CloudRegionKey.String(val) return CloudRegionKey.String(val)
} }
// CloudResourceID returns an attribute KeyValue conforming to the
// "cloud.resource_id" semantic conventions. It represents the cloud
// provider-specific native identifier of the monitored cloud resource (e.g. an
// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
// on AWS, a [fully qualified resource
// ID](https://learn.microsoft.com/en-us/rest/api/resources/resources/get-by-id)
// on Azure, a [full resource
// name](https://cloud.google.com/apis/design/resource_names#full_resource_name)
// on GCP)
func CloudResourceID(val string) attribute.KeyValue {
return CloudResourceIDKey.String(val)
}
// CloudAvailabilityZone returns an attribute KeyValue conforming to the // CloudAvailabilityZone returns an attribute KeyValue conforming to the
// "cloud.availability_zone" semantic conventions. It represents the cloud // "cloud.availability_zone" semantic conventions. It represents the cloud
// regions often have multiple, isolated locations known as zones to increase // regions often have multiple, isolated locations known as zones to increase
@ -495,6 +534,60 @@ func AWSLogStreamARNs(val ...string) attribute.KeyValue {
return AWSLogStreamARNsKey.StringSlice(val) return AWSLogStreamARNsKey.StringSlice(val)
} }
// Heroku dyno metadata
const (
// HerokuReleaseCreationTimestampKey is the attribute Key conforming to the
// "heroku.release.creation_timestamp" semantic conventions. It represents
// the time and date the release was created
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: '2022-10-23T18:00:42Z'
HerokuReleaseCreationTimestampKey = attribute.Key("heroku.release.creation_timestamp")
// HerokuReleaseCommitKey is the attribute Key conforming to the
// "heroku.release.commit" semantic conventions. It represents the commit
// hash for the current release
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'e6134959463efd8966b20e75b913cafe3f5ec'
HerokuReleaseCommitKey = attribute.Key("heroku.release.commit")
// HerokuAppIDKey is the attribute Key conforming to the "heroku.app.id"
// semantic conventions. It represents the unique identifier for the
// application
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: '2daa2797-e42b-4624-9322-ec3f968df4da'
HerokuAppIDKey = attribute.Key("heroku.app.id")
)
// HerokuReleaseCreationTimestamp returns an attribute KeyValue conforming
// to the "heroku.release.creation_timestamp" semantic conventions. It
// represents the time and date the release was created
func HerokuReleaseCreationTimestamp(val string) attribute.KeyValue {
return HerokuReleaseCreationTimestampKey.String(val)
}
// HerokuReleaseCommit returns an attribute KeyValue conforming to the
// "heroku.release.commit" semantic conventions. It represents the commit hash
// for the current release
func HerokuReleaseCommit(val string) attribute.KeyValue {
return HerokuReleaseCommitKey.String(val)
}
// HerokuAppID returns an attribute KeyValue conforming to the
// "heroku.app.id" semantic conventions. It represents the unique identifier
// for the application
func HerokuAppID(val string) attribute.KeyValue {
return HerokuAppIDKey.String(val)
}
// A container instance. // A container instance.
const ( const (
// ContainerNameKey is the attribute Key conforming to the "container.name" // ContainerNameKey is the attribute Key conforming to the "container.name"
@ -730,43 +823,9 @@ const (
// can also be seen in the resource JSON for the function). // can also be seen in the resource JSON for the function).
// This means that a span attribute MUST be used, as an Azure function // This means that a span attribute MUST be used, as an Azure function
// app can host multiple functions that would usually share // app can host multiple functions that would usually share
// a TracerProvider (see also the `faas.id` attribute). // a TracerProvider (see also the `cloud.resource_id` attribute).
FaaSNameKey = attribute.Key("faas.name") FaaSNameKey = attribute.Key("faas.name")
// FaaSIDKey is the attribute Key conforming to the "faas.id" semantic
// conventions. It represents the unique ID of the single function that
// this runtime instance executes.
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: 'arn:aws:lambda:us-west-2:123456789012:function:my-function'
// Note: On some cloud providers, it may not be possible to determine the
// full ID at startup,
// so consider setting `faas.id` as a span attribute instead.
//
// The exact value to use for `faas.id` depends on the cloud provider:
//
// * **AWS Lambda:** The function
// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html).
// Take care not to use the "invoked ARN" directly but replace any
// [alias
// suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html)
// with the resolved function version, as the same runtime instance may
// be invokable with
// multiple different aliases.
// * **GCP:** The [URI of the
// resource](https://cloud.google.com/iam/docs/full-resource-names)
// * **Azure:** The [Fully Qualified Resource
// ID](https://docs.microsoft.com/en-us/rest/api/resources/resources/get-by-id)
// of the invoked function,
// *not* the function app, having the form
// `/subscriptions/<SUBSCIPTION_GUID>/resourceGroups/<RG>/providers/Microsoft.Web/sites/<FUNCAPP>/functions/<FUNC>`.
// This means that a span attribute MUST be used, as an Azure function
// app can host multiple functions that would usually share
// a TracerProvider.
FaaSIDKey = attribute.Key("faas.id")
// FaaSVersionKey is the attribute Key conforming to the "faas.version" // FaaSVersionKey is the attribute Key conforming to the "faas.version"
// semantic conventions. It represents the immutable version of the // semantic conventions. It represents the immutable version of the
// function being executed. // function being executed.
@ -803,16 +862,17 @@ const (
// FaaSMaxMemoryKey is the attribute Key conforming to the // FaaSMaxMemoryKey is the attribute Key conforming to the
// "faas.max_memory" semantic conventions. It represents the amount of // "faas.max_memory" semantic conventions. It represents the amount of
// memory available to the serverless function in MiB. // memory available to the serverless function converted to Bytes.
// //
// Type: int // Type: int
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: stable // Stability: stable
// Examples: 128 // Examples: 134217728
// Note: It's recommended to set this attribute since e.g. too little // Note: It's recommended to set this attribute since e.g. too little
// memory can easily stop a Java AWS Lambda function from working // memory can easily stop a Java AWS Lambda function from working
// correctly. On AWS Lambda, the environment variable // correctly. On AWS Lambda, the environment variable
// `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information. // `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this information (which must
// be multiplied by 1,048,576).
FaaSMaxMemoryKey = attribute.Key("faas.max_memory") FaaSMaxMemoryKey = attribute.Key("faas.max_memory")
) )
@ -823,13 +883,6 @@ func FaaSName(val string) attribute.KeyValue {
return FaaSNameKey.String(val) return FaaSNameKey.String(val)
} }
// FaaSID returns an attribute KeyValue conforming to the "faas.id" semantic
// conventions. It represents the unique ID of the single function that this
// runtime instance executes.
func FaaSID(val string) attribute.KeyValue {
return FaaSIDKey.String(val)
}
// FaaSVersion returns an attribute KeyValue conforming to the // FaaSVersion returns an attribute KeyValue conforming to the
// "faas.version" semantic conventions. It represents the immutable version of // "faas.version" semantic conventions. It represents the immutable version of
// the function being executed. // the function being executed.
@ -847,7 +900,7 @@ func FaaSInstance(val string) attribute.KeyValue {
// FaaSMaxMemory returns an attribute KeyValue conforming to the // FaaSMaxMemory returns an attribute KeyValue conforming to the
// "faas.max_memory" semantic conventions. It represents the amount of memory // "faas.max_memory" semantic conventions. It represents the amount of memory
// available to the serverless function in MiB. // available to the serverless function converted to Bytes.
func FaaSMaxMemory(val int) attribute.KeyValue { func FaaSMaxMemory(val int) attribute.KeyValue {
return FaaSMaxMemoryKey.Int(val) return FaaSMaxMemoryKey.Int(val)
} }
@ -857,8 +910,8 @@ const (
// HostIDKey is the attribute Key conforming to the "host.id" semantic // HostIDKey is the attribute Key conforming to the "host.id" semantic
// conventions. It represents the unique host ID. For Cloud, this must be // conventions. It represents the unique host ID. For Cloud, this must be
// the instance_id assigned by the cloud provider. For non-containerized // the instance_id assigned by the cloud provider. For non-containerized
// Linux systems, the `machine-id` located in `/etc/machine-id` or // systems, this should be the `machine-id`. See the table below for the
// `/var/lib/dbus/machine-id` may be used. // sources to use to determine the `machine-id` based on operating system.
// //
// Type: string // Type: string
// RequirementLevel: Optional // RequirementLevel: Optional
@ -949,9 +1002,9 @@ var (
// HostID returns an attribute KeyValue conforming to the "host.id" semantic // HostID returns an attribute KeyValue conforming to the "host.id" semantic
// conventions. It represents the unique host ID. For Cloud, this must be the // conventions. It represents the unique host ID. For Cloud, this must be the
// instance_id assigned by the cloud provider. For non-containerized Linux // instance_id assigned by the cloud provider. For non-containerized systems,
// systems, the `machine-id` located in `/etc/machine-id` or // this should be the `machine-id`. See the table below for the sources to use
// `/var/lib/dbus/machine-id` may be used. // to determine the `machine-id` based on operating system.
func HostID(val string) attribute.KeyValue { func HostID(val string) attribute.KeyValue {
return HostIDKey.String(val) return HostIDKey.String(val)
} }
@ -1695,7 +1748,17 @@ const (
// `unknown_service:bash`. If `process.executable.name` is not available, // `unknown_service:bash`. If `process.executable.name` is not available,
// the value MUST be set to `unknown_service`. // the value MUST be set to `unknown_service`.
ServiceNameKey = attribute.Key("service.name") ServiceNameKey = attribute.Key("service.name")
)
// ServiceName returns an attribute KeyValue conforming to the
// "service.name" semantic conventions. It represents the logical name of the
// service.
func ServiceName(val string) attribute.KeyValue {
return ServiceNameKey.String(val)
}
// A service instance.
const (
// ServiceNamespaceKey is the attribute Key conforming to the // ServiceNamespaceKey is the attribute Key conforming to the
// "service.namespace" semantic conventions. It represents a namespace for // "service.namespace" semantic conventions. It represents a namespace for
// `service.name`. // `service.name`.
@ -1721,7 +1784,8 @@ const (
// Type: string // Type: string
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: stable // Stability: stable
// Examples: '627cc493-f310-47de-96bd-71410b7dec09' // Examples: 'my-k8s-pod-deployment-1',
// '627cc493-f310-47de-96bd-71410b7dec09'
// Note: MUST be unique for each instance of the same // Note: MUST be unique for each instance of the same
// `service.namespace,service.name` pair (in other words // `service.namespace,service.name` pair (in other words
// `service.namespace,service.name,service.instance.id` triplet MUST be // `service.namespace,service.name,service.instance.id` triplet MUST be
@ -1748,13 +1812,6 @@ const (
ServiceVersionKey = attribute.Key("service.version") ServiceVersionKey = attribute.Key("service.version")
) )
// ServiceName returns an attribute KeyValue conforming to the
// "service.name" semantic conventions. It represents the logical name of the
// service.
func ServiceName(val string) attribute.KeyValue {
return ServiceNameKey.String(val)
}
// ServiceNamespace returns an attribute KeyValue conforming to the // ServiceNamespace returns an attribute KeyValue conforming to the
// "service.namespace" semantic conventions. It represents a namespace for // "service.namespace" semantic conventions. It represents a namespace for
// `service.name`. // `service.name`.
@ -1784,7 +1841,7 @@ const (
// telemetry SDK as defined above. // telemetry SDK as defined above.
// //
// Type: string // Type: string
// RequirementLevel: Optional // RequirementLevel: Required
// Stability: stable // Stability: stable
// Examples: 'opentelemetry' // Examples: 'opentelemetry'
TelemetrySDKNameKey = attribute.Key("telemetry.sdk.name") TelemetrySDKNameKey = attribute.Key("telemetry.sdk.name")
@ -1794,7 +1851,7 @@ const (
// language of the telemetry SDK. // language of the telemetry SDK.
// //
// Type: Enum // Type: Enum
// RequirementLevel: Optional // RequirementLevel: Required
// Stability: stable // Stability: stable
TelemetrySDKLanguageKey = attribute.Key("telemetry.sdk.language") TelemetrySDKLanguageKey = attribute.Key("telemetry.sdk.language")
@ -1803,20 +1860,10 @@ const (
// string of the telemetry SDK. // string of the telemetry SDK.
// //
// Type: string // Type: string
// RequirementLevel: Optional // RequirementLevel: Required
// Stability: stable // Stability: stable
// Examples: '1.2.3' // Examples: '1.2.3'
TelemetrySDKVersionKey = attribute.Key("telemetry.sdk.version") TelemetrySDKVersionKey = attribute.Key("telemetry.sdk.version")
// TelemetryAutoVersionKey is the attribute Key conforming to the
// "telemetry.auto.version" semantic conventions. It represents the version
// string of the auto instrumentation agent, if used.
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: '1.2.3'
TelemetryAutoVersionKey = attribute.Key("telemetry.auto.version")
) )
var ( var (
@ -1858,6 +1905,20 @@ func TelemetrySDKVersion(val string) attribute.KeyValue {
return TelemetrySDKVersionKey.String(val) return TelemetrySDKVersionKey.String(val)
} }
// The telemetry SDK used to capture data recorded by the instrumentation
// libraries.
const (
// TelemetryAutoVersionKey is the attribute Key conforming to the
// "telemetry.auto.version" semantic conventions. It represents the version
// string of the auto instrumentation agent, if used.
//
// Type: string
// RequirementLevel: Optional
// Stability: stable
// Examples: '1.2.3'
TelemetryAutoVersionKey = attribute.Key("telemetry.auto.version")
)
// TelemetryAutoVersion returns an attribute KeyValue conforming to the // TelemetryAutoVersion returns an attribute KeyValue conforming to the
// "telemetry.auto.version" semantic conventions. It represents the version // "telemetry.auto.version" semantic conventions. It represents the version
// string of the auto instrumentation agent, if used. // string of the auto instrumentation agent, if used.
@ -1925,7 +1986,7 @@ func WebEngineDescription(val string) attribute.KeyValue {
// Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's // Attributes used by non-OTLP exporters to represent OpenTelemetry Scope's
// concepts. // concepts.
const ( const (
// OtelScopeNameKey is the attribute Key conforming to the // OTelScopeNameKey is the attribute Key conforming to the
// "otel.scope.name" semantic conventions. It represents the name of the // "otel.scope.name" semantic conventions. It represents the name of the
// instrumentation scope - (`InstrumentationScope.Name` in OTLP). // instrumentation scope - (`InstrumentationScope.Name` in OTLP).
// //
@ -1933,9 +1994,9 @@ const (
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: stable // Stability: stable
// Examples: 'io.opentelemetry.contrib.mongodb' // Examples: 'io.opentelemetry.contrib.mongodb'
OtelScopeNameKey = attribute.Key("otel.scope.name") OTelScopeNameKey = attribute.Key("otel.scope.name")
// OtelScopeVersionKey is the attribute Key conforming to the // OTelScopeVersionKey is the attribute Key conforming to the
// "otel.scope.version" semantic conventions. It represents the version of // "otel.scope.version" semantic conventions. It represents the version of
// the instrumentation scope - (`InstrumentationScope.Version` in OTLP). // the instrumentation scope - (`InstrumentationScope.Version` in OTLP).
// //
@ -1943,27 +2004,27 @@ const (
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: stable // Stability: stable
// Examples: '1.0.0' // Examples: '1.0.0'
OtelScopeVersionKey = attribute.Key("otel.scope.version") OTelScopeVersionKey = attribute.Key("otel.scope.version")
) )
// OtelScopeName returns an attribute KeyValue conforming to the // OTelScopeName returns an attribute KeyValue conforming to the
// "otel.scope.name" semantic conventions. It represents the name of the // "otel.scope.name" semantic conventions. It represents the name of the
// instrumentation scope - (`InstrumentationScope.Name` in OTLP). // instrumentation scope - (`InstrumentationScope.Name` in OTLP).
func OtelScopeName(val string) attribute.KeyValue { func OTelScopeName(val string) attribute.KeyValue {
return OtelScopeNameKey.String(val) return OTelScopeNameKey.String(val)
} }
// OtelScopeVersion returns an attribute KeyValue conforming to the // OTelScopeVersion returns an attribute KeyValue conforming to the
// "otel.scope.version" semantic conventions. It represents the version of the // "otel.scope.version" semantic conventions. It represents the version of the
// instrumentation scope - (`InstrumentationScope.Version` in OTLP). // instrumentation scope - (`InstrumentationScope.Version` in OTLP).
func OtelScopeVersion(val string) attribute.KeyValue { func OTelScopeVersion(val string) attribute.KeyValue {
return OtelScopeVersionKey.String(val) return OTelScopeVersionKey.String(val)
} }
// Span attributes used by non-OTLP exporters to represent OpenTelemetry // Span attributes used by non-OTLP exporters to represent OpenTelemetry
// Scope's concepts. // Scope's concepts.
const ( const (
// OtelLibraryNameKey is the attribute Key conforming to the // OTelLibraryNameKey is the attribute Key conforming to the
// "otel.library.name" semantic conventions. It represents the deprecated, // "otel.library.name" semantic conventions. It represents the deprecated,
// use the `otel.scope.name` attribute. // use the `otel.scope.name` attribute.
// //
@ -1971,9 +2032,9 @@ const (
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: deprecated // Stability: deprecated
// Examples: 'io.opentelemetry.contrib.mongodb' // Examples: 'io.opentelemetry.contrib.mongodb'
OtelLibraryNameKey = attribute.Key("otel.library.name") OTelLibraryNameKey = attribute.Key("otel.library.name")
// OtelLibraryVersionKey is the attribute Key conforming to the // OTelLibraryVersionKey is the attribute Key conforming to the
// "otel.library.version" semantic conventions. It represents the // "otel.library.version" semantic conventions. It represents the
// deprecated, use the `otel.scope.version` attribute. // deprecated, use the `otel.scope.version` attribute.
// //
@ -1981,19 +2042,19 @@ const (
// RequirementLevel: Optional // RequirementLevel: Optional
// Stability: deprecated // Stability: deprecated
// Examples: '1.0.0' // Examples: '1.0.0'
OtelLibraryVersionKey = attribute.Key("otel.library.version") OTelLibraryVersionKey = attribute.Key("otel.library.version")
) )
// OtelLibraryName returns an attribute KeyValue conforming to the // OTelLibraryName returns an attribute KeyValue conforming to the
// "otel.library.name" semantic conventions. It represents the deprecated, use // "otel.library.name" semantic conventions. It represents the deprecated, use
// the `otel.scope.name` attribute. // the `otel.scope.name` attribute.
func OtelLibraryName(val string) attribute.KeyValue { func OTelLibraryName(val string) attribute.KeyValue {
return OtelLibraryNameKey.String(val) return OTelLibraryNameKey.String(val)
} }
// OtelLibraryVersion returns an attribute KeyValue conforming to the // OTelLibraryVersion returns an attribute KeyValue conforming to the
// "otel.library.version" semantic conventions. It represents the deprecated, // "otel.library.version" semantic conventions. It represents the deprecated,
// use the `otel.scope.version` attribute. // use the `otel.scope.version` attribute.
func OtelLibraryVersion(val string) attribute.KeyValue { func OTelLibraryVersion(val string) attribute.KeyValue {
return OtelLibraryVersionKey.String(val) return OTelLibraryVersionKey.String(val)
} }

View File

@ -1,9 +1,9 @@
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.17.0" package semconv // import "go.opentelemetry.io/otel/semconv/v1.20.0"
// SchemaURL is the schema URL that matches the version of the semantic conventions // SchemaURL is the schema URL that matches the version of the semantic conventions
// that this package defines. Semconv packages starting from v1.4.0 must declare // that this package defines. Semconv packages starting from v1.4.0 must declare
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version> // non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
const SchemaURL = "https://opentelemetry.io/schemas/1.17.0" const SchemaURL = "https://opentelemetry.io/schemas/1.20.0"

View File

@ -0,0 +1,3 @@
# Semconv v1.24.0
[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/otel/semconv/v1.24.0)](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.24.0)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Package semconv implements OpenTelemetry semantic conventions.
//
// OpenTelemetry semantic conventions are agreed standardized naming
// patterns for OpenTelemetry things. This package represents the v1.24.0
// version of the OpenTelemetry semantic conventions.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"

View File

@ -0,0 +1,200 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// Code generated from semantic convention specification. DO NOT EDIT.
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
import "go.opentelemetry.io/otel/attribute"
// This event represents an occurrence of a lifecycle transition on the iOS
// platform.
const (
// IosStateKey is the attribute Key conforming to the "ios.state" semantic
// conventions. It represents the this attribute represents the state the
// application has transitioned into at the occurrence of the event.
//
// Type: Enum
// RequirementLevel: Required
// Stability: experimental
// Note: The iOS lifecycle states are defined in the [UIApplicationDelegate
// documentation](https://developer.apple.com/documentation/uikit/uiapplicationdelegate#1656902),
// and from which the `OS terminology` column values are derived.
IosStateKey = attribute.Key("ios.state")
)
var (
// The app has become `active`. Associated with UIKit notification `applicationDidBecomeActive`
IosStateActive = IosStateKey.String("active")
// The app is now `inactive`. Associated with UIKit notification `applicationWillResignActive`
IosStateInactive = IosStateKey.String("inactive")
// The app is now in the background. This value is associated with UIKit notification `applicationDidEnterBackground`
IosStateBackground = IosStateKey.String("background")
// The app is now in the foreground. This value is associated with UIKit notification `applicationWillEnterForeground`
IosStateForeground = IosStateKey.String("foreground")
// The app is about to terminate. Associated with UIKit notification `applicationWillTerminate`
IosStateTerminate = IosStateKey.String("terminate")
)
// This event represents an occurrence of a lifecycle transition on the Android
// platform.
const (
// AndroidStateKey is the attribute Key conforming to the "android.state"
// semantic conventions. It represents the this attribute represents the
// state the application has transitioned into at the occurrence of the
// event.
//
// Type: Enum
// RequirementLevel: Required
// Stability: experimental
// Note: The Android lifecycle states are defined in [Activity lifecycle
// callbacks](https://developer.android.com/guide/components/activities/activity-lifecycle#lc),
// and from which the `OS identifiers` are derived.
AndroidStateKey = attribute.Key("android.state")
)
var (
// Any time before Activity.onResume() or, if the app has no Activity, Context.startService() has been called in the app for the first time
AndroidStateCreated = AndroidStateKey.String("created")
// Any time after Activity.onPause() or, if the app has no Activity, Context.stopService() has been called when the app was in the foreground state
AndroidStateBackground = AndroidStateKey.String("background")
// Any time after Activity.onResume() or, if the app has no Activity, Context.startService() has been called when the app was in either the created or background states
AndroidStateForeground = AndroidStateKey.String("foreground")
)
// This semantic convention defines the attributes used to represent a feature
// flag evaluation as an event.
const (
// FeatureFlagKeyKey is the attribute Key conforming to the
// "feature_flag.key" semantic conventions. It represents the unique
// identifier of the feature flag.
//
// Type: string
// RequirementLevel: Required
// Stability: experimental
// Examples: 'logo-color'
FeatureFlagKeyKey = attribute.Key("feature_flag.key")
// FeatureFlagProviderNameKey is the attribute Key conforming to the
// "feature_flag.provider_name" semantic conventions. It represents the
// name of the service provider that performs the flag evaluation.
//
// Type: string
// RequirementLevel: Recommended
// Stability: experimental
// Examples: 'Flag Manager'
FeatureFlagProviderNameKey = attribute.Key("feature_flag.provider_name")
// FeatureFlagVariantKey is the attribute Key conforming to the
// "feature_flag.variant" semantic conventions. It represents the sHOULD be
// a semantic identifier for a value. If one is unavailable, a stringified
// version of the value can be used.
//
// Type: string
// RequirementLevel: Recommended
// Stability: experimental
// Examples: 'red', 'true', 'on'
// Note: A semantic identifier, commonly referred to as a variant, provides
// a means
// for referring to a value without including the value itself. This can
// provide additional context for understanding the meaning behind a value.
// For example, the variant `red` maybe be used for the value `#c05543`.
//
// A stringified version of the value can be used in situations where a
// semantic identifier is unavailable. String representation of the value
// should be determined by the implementer.
FeatureFlagVariantKey = attribute.Key("feature_flag.variant")
)
// FeatureFlagKey returns an attribute KeyValue conforming to the
// "feature_flag.key" semantic conventions. It represents the unique identifier
// of the feature flag.
func FeatureFlagKey(val string) attribute.KeyValue {
return FeatureFlagKeyKey.String(val)
}
// FeatureFlagProviderName returns an attribute KeyValue conforming to the
// "feature_flag.provider_name" semantic conventions. It represents the name of
// the service provider that performs the flag evaluation.
func FeatureFlagProviderName(val string) attribute.KeyValue {
return FeatureFlagProviderNameKey.String(val)
}
// FeatureFlagVariant returns an attribute KeyValue conforming to the
// "feature_flag.variant" semantic conventions. It represents the sHOULD be a
// semantic identifier for a value. If one is unavailable, a stringified
// version of the value can be used.
func FeatureFlagVariant(val string) attribute.KeyValue {
return FeatureFlagVariantKey.String(val)
}
// RPC received/sent message.
const (
// MessageCompressedSizeKey is the attribute Key conforming to the
// "message.compressed_size" semantic conventions. It represents the
// compressed size of the message in bytes.
//
// Type: int
// RequirementLevel: Optional
// Stability: experimental
MessageCompressedSizeKey = attribute.Key("message.compressed_size")
// MessageIDKey is the attribute Key conforming to the "message.id"
// semantic conventions. It represents the mUST be calculated as two
// different counters starting from `1` one for sent messages and one for
// received message.
//
// Type: int
// RequirementLevel: Optional
// Stability: experimental
// Note: This way we guarantee that the values will be consistent between
// different implementations.
MessageIDKey = attribute.Key("message.id")
// MessageTypeKey is the attribute Key conforming to the "message.type"
// semantic conventions. It represents the whether this is a received or
// sent message.
//
// Type: Enum
// RequirementLevel: Optional
// Stability: experimental
MessageTypeKey = attribute.Key("message.type")
// MessageUncompressedSizeKey is the attribute Key conforming to the
// "message.uncompressed_size" semantic conventions. It represents the
// uncompressed size of the message in bytes.
//
// Type: int
// RequirementLevel: Optional
// Stability: experimental
MessageUncompressedSizeKey = attribute.Key("message.uncompressed_size")
)
var (
// sent
MessageTypeSent = MessageTypeKey.String("SENT")
// received
MessageTypeReceived = MessageTypeKey.String("RECEIVED")
)
// MessageCompressedSize returns an attribute KeyValue conforming to the
// "message.compressed_size" semantic conventions. It represents the compressed
// size of the message in bytes.
func MessageCompressedSize(val int) attribute.KeyValue {
return MessageCompressedSizeKey.Int(val)
}
// MessageID returns an attribute KeyValue conforming to the "message.id"
// semantic conventions. It represents the mUST be calculated as two different
// counters starting from `1` one for sent messages and one for received
// message.
func MessageID(val int) attribute.KeyValue {
return MessageIDKey.Int(val)
}
// MessageUncompressedSize returns an attribute KeyValue conforming to the
// "message.uncompressed_size" semantic conventions. It represents the
// uncompressed size of the message in bytes.
func MessageUncompressedSize(val int) attribute.KeyValue {
return MessageUncompressedSizeKey.Int(val)
}

View File

@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
const (
// ExceptionEventName is the name of the Span event representing an exception.
ExceptionEventName = "exception"
)

1071
vendor/go.opentelemetry.io/otel/semconv/v1.24.0/metric.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package semconv // import "go.opentelemetry.io/otel/semconv/v1.24.0"
// SchemaURL is the schema URL that matches the version of the semantic conventions
// that this package defines. Semconv packages starting from v1.4.0 must declare
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
const SchemaURL = "https://opentelemetry.io/schemas/1.24.0"

1323
vendor/go.opentelemetry.io/otel/semconv/v1.24.0/trace.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

8
vendor/modules.txt vendored
View File

@ -308,9 +308,10 @@ github.com/xeipuuv/gojsonschema
# go.etcd.io/etcd/raft/v3 v3.5.16 # go.etcd.io/etcd/raft/v3 v3.5.16
## explicit; go 1.22 ## explicit; go 1.22
go.etcd.io/etcd/raft/v3/raftpb go.etcd.io/etcd/raft/v3/raftpb
# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 # go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0
## explicit; go 1.20 ## explicit; go 1.21
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil
# go.opentelemetry.io/otel v1.28.0 # go.opentelemetry.io/otel v1.28.0
## explicit; go 1.21 ## explicit; go 1.21
@ -323,8 +324,9 @@ go.opentelemetry.io/otel/internal/attribute
go.opentelemetry.io/otel/internal/baggage go.opentelemetry.io/otel/internal/baggage
go.opentelemetry.io/otel/internal/global go.opentelemetry.io/otel/internal/global
go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/propagation
go.opentelemetry.io/otel/semconv/v1.17.0 go.opentelemetry.io/otel/semconv/v1.20.0
go.opentelemetry.io/otel/semconv/v1.21.0 go.opentelemetry.io/otel/semconv/v1.21.0
go.opentelemetry.io/otel/semconv/v1.24.0
go.opentelemetry.io/otel/semconv/v1.26.0 go.opentelemetry.io/otel/semconv/v1.26.0
# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 # go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
## explicit; go 1.21 ## explicit; go 1.21