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 @@ -35,6 +35,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 This requires the response.
http.response_content_length his requires the response.
*/
var n int
if resp.StatusCode > 0 {
n++
Expand All @@ -211,12 +211,30 @@
return attrs
}

// 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".
// TraceClientRequest returns attributes for an HTTP request made by a client. The
MrAlias marked this conversation as resolved.
Show resolved Hide resolved
// 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 Required
user_agent.original string Recommended
http.url string Required
net.peer.name string Required
net.peer.port int Conditionally Required: [5]
http.request_content_length int Recommended
*/

/* The following semantic conventions are not returned:
http.status_code This requires the response. See ClientResponse.
http.response_content_length his 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.
*/
n := 3 // URL, peer name, proto, and method.
var h string
if req.URL != nil {
Expand All @@ -234,14 +252,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 +274,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 +301,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
net.protocol.version string
http.target string Note: doesn't include the querry 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 +357,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 376 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#L375-L376

Added lines #L375 - L376 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 +398,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 414 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#L413-L414

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

return attrs
}

Expand All @@ -394,14 +440,22 @@
// "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 Required
http.route string Conditionally Required: If and only if it’s available
http.method string Required - Note: Only known good headers and _OTHER
http.status_code int Conditionally Required: If and only if one was received/sent.
net.host.name string Required
net.host.port int Conditionally Required: [4]
net.protocol.name string Recommended
net.protocol.version string Recommended
*/

/* The following semantic conventions are not returned:

*/

n := 3 // Method, scheme, and host name.
var host string
var p int
if server == "" {
Expand All @@ -417,16 +471,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 +522,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