Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update http Semconv to v1.20.0 #4320

Merged
merged 11 commits into from
Dec 12, 2023
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Upgrade dependencies of OpenTelemetry Go to use the new [`v1.19.0`/`v0.42.0`/`v0.0.7` release](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.19.0).
- Use `grpc.StatsHandler` for gRPC instrumentation in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/example`. (#4325)

### Changed

- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/gopkg.in/macaron.v1/otelmacaron` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/example` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/example` have been upgraded to v1.20.0. (#4320)
- The semantic conventions used by `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` have been upgraded to v1.20.0. (#4320)

## [1.19.0/0.44.0/0.13.0] - 2023-09-12

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

"go.opentelemetry.io/otel/attribute"
"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
Expand Down Expand Up @@ -149,9 +149,7 @@
type httpConv struct {
NetConv *netConv

EnduserIDKey attribute.Key
HTTPClientIPKey attribute.Key
HTTPFlavorKey attribute.Key
HTTPMethodKey attribute.Key
HTTPRequestContentLengthKey attribute.Key
HTTPResponseContentLengthKey attribute.Key
Expand All @@ -161,15 +159,13 @@
HTTPStatusCodeKey attribute.Key
HTTPTargetKey attribute.Key
HTTPURLKey attribute.Key
HTTPUserAgentKey attribute.Key
UserAgentOriginalKey attribute.Key
}

var hc = &httpConv{
NetConv: nc,

EnduserIDKey: semconv.EnduserIDKey,
HTTPClientIPKey: semconv.HTTPClientIPKey,
HTTPFlavorKey: semconv.HTTPFlavorKey,
HTTPMethodKey: semconv.HTTPMethodKey,
HTTPRequestContentLengthKey: semconv.HTTPRequestContentLengthKey,
HTTPResponseContentLengthKey: semconv.HTTPResponseContentLengthKey,
Expand All @@ -179,7 +175,7 @@
HTTPStatusCodeKey: semconv.HTTPStatusCodeKey,
HTTPTargetKey: semconv.HTTPTargetKey,
HTTPURLKey: semconv.HTTPURLKey,
HTTPUserAgentKey: semconv.HTTPUserAgentKey,
UserAgentOriginalKey: semconv.UserAgentOriginalKey,
}

// ClientResponse returns attributes for an HTTP response received by a client
Expand All @@ -193,6 +189,10 @@
//
// append(ClientResponse(resp), ClientRequest(resp.Request)...)
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
if resp.StatusCode > 0 {
n++
Expand All @@ -212,11 +212,31 @@
}

// ClientRequest returns attributes for an HTTP request made by a client. The
// following attributes are always returned: "http.url", "http.flavor",
// "http.method", "net.peer.name". The following attributes are returned if the
// related values are defined in req: "net.peer.port", "http.user_agent",
// "http.request_content_length", "enduser.id".
// following attributes are always returned: "http.url", "http.method",
// "net.peer.name". The following attributes are returned if the related values
// are defined in req: "net.peer.port", "http.user_agent",
// "http.request_content_length", "user_agent.original".
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.
var h string
if req.URL != nil {
Expand All @@ -234,14 +254,10 @@
if req.ContentLength > 0 {
n++
}
userID, _, hasUserID := req.BasicAuth()
if hasUserID {
n++
}

attrs := make([]attribute.KeyValue, 0, n)

attrs = append(attrs, c.method(req.Method))
attrs = append(attrs, c.flavor(req.Proto))

var u string
if req.URL != nil {
Expand All @@ -260,17 +276,13 @@
}

if useragent != "" {
attrs = append(attrs, c.HTTPUserAgentKey.String(useragent))
attrs = append(attrs, c.UserAgentOriginalKey.String(useragent))
}

if l := req.ContentLength; l > 0 {
attrs = append(attrs, c.HTTPRequestContentLengthKey.Int64(l))
}

if hasUserID {
attrs = append(attrs, c.EnduserIDKey.String(userID))
}

return attrs
}

Expand All @@ -291,18 +303,35 @@
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
// "http.target", "net.host.name". The following attributes are returned if they
// related values are defined in req: "net.host.port", "net.sock.peer.addr",
// "net.sock.peer.port", "user_agent.original", "http.client_ip",
// "net.protocol.name", "net.protocol.version".
func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.KeyValue {
// TODO: This currently does not add the specification required
// `http.target` attribute. It has too high of a cardinality to safely be
// added. An alternate should be added, or this comment removed, when it is
// addressed by the specification. If it is ultimately decided to continue
// not including the attribute, the HTTPTargetKey field of the httpConv
// should be removed as well.

/* The following semantic conventions are returned if present:
http.method string
http.scheme string
net.host.name string
net.host.port int
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.
var host string
var p int
Expand Down Expand Up @@ -330,19 +359,31 @@
if useragent != "" {
n++
}
userID, _, hasUserID := req.BasicAuth()
if hasUserID {
n++
}

clientIP := serverClientIP(req.Header.Get("X-Forwarded-For"))
if clientIP != "" {
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++
}

Check warning on line 378 in instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconvutil/httpconv.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconvutil/httpconv.go#L377-L378

Added lines #L377 - L378 were not covered by tests
if protoVersion != "" {
n++
}

attrs := make([]attribute.KeyValue, 0, n)

attrs = append(attrs, c.method(req.Method))
attrs = append(attrs, c.scheme(req.TLS != nil))
attrs = append(attrs, c.flavor(req.Proto))
attrs = append(attrs, c.NetConv.HostName(host))

if hostPort > 0 {
Expand All @@ -359,17 +400,24 @@
}

if useragent != "" {
attrs = append(attrs, c.HTTPUserAgentKey.String(useragent))
}

if hasUserID {
attrs = append(attrs, c.EnduserIDKey.String(userID))
attrs = append(attrs, c.UserAgentOriginalKey.String(useragent))
}

if 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))
}

Check warning on line 416 in instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconvutil/httpconv.go

View check run for this annotation

Codecov / codecov/patch

instrumentation/github.com/emicklei/go-restful/otelrestful/internal/semconvutil/httpconv.go#L415-L416

Added lines #L415 - L416 were not covered by tests
if protoVersion != "" {
attrs = append(attrs, c.NetConv.NetProtocolVersion.String(protoVersion))
}

return attrs
}

Expand All @@ -394,14 +442,18 @@
// "http.flavor", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port".
func (c *httpConv) ServerRequestMetrics(server string, req *http.Request) []attribute.KeyValue {
// TODO: This currently does not add the specification required
// `http.target` attribute. It has too high of a cardinality to safely be
// added. An alternate should be added, or this comment removed, when it is
// addressed by the specification. If it is ultimately decided to continue
// not including the attribute, the HTTPTargetKey field of the httpConv
// should be removed as well.

n := 4 // Method, scheme, proto, and host name.
/* The following semantic conventions are returned if present:
http.scheme string
http.route string
http.method string
http.status_code int
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 := 3 // Method, scheme, and host name.
var host string
var p int
if server == "" {
Expand All @@ -417,16 +469,29 @@
if hostPort > 0 {
n++
}
protoName, protoVersion := netProtocol(req.Proto)
if protoName != "" {
n++
}
if protoVersion != "" {
n++
}

attrs := make([]attribute.KeyValue, 0, n)

attrs = append(attrs, c.methodMetric(req.Method))
attrs = append(attrs, c.scheme(req.TLS != nil))
attrs = append(attrs, c.flavor(req.Proto))
attrs = append(attrs, c.NetConv.HostName(host))

if hostPort > 0 {
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
}
Expand Down Expand Up @@ -455,21 +520,6 @@
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 {
if idx := strings.Index(xForwardedFor, ","); idx >= 0 {
xForwardedFor = xForwardedFor[:idx]
Expand Down