mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-03-09 17:09:29 +00:00
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
328 lines
11 KiB
Go
328 lines
11 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package internal // import "go.opentelemetry.io/otel/semconv/internal"
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/codes"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
// SemanticConventions are the semantic convention values defined for a
|
|
// version of the OpenTelemetry specification.
|
|
type SemanticConventions struct {
|
|
EnduserIDKey attribute.Key
|
|
HTTPClientIPKey attribute.Key
|
|
HTTPFlavorKey attribute.Key
|
|
HTTPHostKey attribute.Key
|
|
HTTPMethodKey attribute.Key
|
|
HTTPRequestContentLengthKey attribute.Key
|
|
HTTPRouteKey attribute.Key
|
|
HTTPSchemeHTTP attribute.KeyValue
|
|
HTTPSchemeHTTPS attribute.KeyValue
|
|
HTTPServerNameKey attribute.Key
|
|
HTTPStatusCodeKey attribute.Key
|
|
HTTPTargetKey attribute.Key
|
|
HTTPURLKey attribute.Key
|
|
HTTPUserAgentKey attribute.Key
|
|
NetHostIPKey attribute.Key
|
|
NetHostNameKey attribute.Key
|
|
NetHostPortKey attribute.Key
|
|
NetPeerIPKey attribute.Key
|
|
NetPeerNameKey attribute.Key
|
|
NetPeerPortKey attribute.Key
|
|
NetTransportIP attribute.KeyValue
|
|
NetTransportOther attribute.KeyValue
|
|
NetTransportTCP attribute.KeyValue
|
|
NetTransportUDP attribute.KeyValue
|
|
NetTransportUnix attribute.KeyValue
|
|
}
|
|
|
|
// NetAttributesFromHTTPRequest generates attributes of the net
|
|
// namespace as specified by the OpenTelemetry specification for a
|
|
// span. The network parameter is a string that net.Dial function
|
|
// from standard library can understand.
|
|
func (sc *SemanticConventions) NetAttributesFromHTTPRequest(network string, request *http.Request) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{}
|
|
|
|
switch network {
|
|
case "tcp", "tcp4", "tcp6":
|
|
attrs = append(attrs, sc.NetTransportTCP)
|
|
case "udp", "udp4", "udp6":
|
|
attrs = append(attrs, sc.NetTransportUDP)
|
|
case "ip", "ip4", "ip6":
|
|
attrs = append(attrs, sc.NetTransportIP)
|
|
case "unix", "unixgram", "unixpacket":
|
|
attrs = append(attrs, sc.NetTransportUnix)
|
|
default:
|
|
attrs = append(attrs, sc.NetTransportOther)
|
|
}
|
|
|
|
peerIP, peerName, peerPort := hostIPNamePort(request.RemoteAddr)
|
|
if peerIP != "" {
|
|
attrs = append(attrs, sc.NetPeerIPKey.String(peerIP))
|
|
}
|
|
if peerName != "" {
|
|
attrs = append(attrs, sc.NetPeerNameKey.String(peerName))
|
|
}
|
|
if peerPort != 0 {
|
|
attrs = append(attrs, sc.NetPeerPortKey.Int(peerPort))
|
|
}
|
|
|
|
hostIP, hostName, hostPort := "", "", 0
|
|
for _, someHost := range []string{request.Host, request.Header.Get("Host"), request.URL.Host} {
|
|
hostIP, hostName, hostPort = hostIPNamePort(someHost)
|
|
if hostIP != "" || hostName != "" || hostPort != 0 {
|
|
break
|
|
}
|
|
}
|
|
if hostIP != "" {
|
|
attrs = append(attrs, sc.NetHostIPKey.String(hostIP))
|
|
}
|
|
if hostName != "" {
|
|
attrs = append(attrs, sc.NetHostNameKey.String(hostName))
|
|
}
|
|
if hostPort != 0 {
|
|
attrs = append(attrs, sc.NetHostPortKey.Int(hostPort))
|
|
}
|
|
|
|
return attrs
|
|
}
|
|
|
|
// hostIPNamePort extracts the IP address, name and (optional) port from hostWithPort.
|
|
// It handles both IPv4 and IPv6 addresses. If the host portion is not recognized
|
|
// as a valid IPv4 or IPv6 address, the `ip` result will be empty and the
|
|
// host portion will instead be returned in `name`.
|
|
func hostIPNamePort(hostWithPort string) (ip string, name string, port int) {
|
|
var (
|
|
hostPart, portPart string
|
|
parsedPort uint64
|
|
err error
|
|
)
|
|
if hostPart, portPart, err = net.SplitHostPort(hostWithPort); err != nil {
|
|
hostPart, portPart = hostWithPort, ""
|
|
}
|
|
if parsedIP := net.ParseIP(hostPart); parsedIP != nil {
|
|
ip = parsedIP.String()
|
|
} else {
|
|
name = hostPart
|
|
}
|
|
if parsedPort, err = strconv.ParseUint(portPart, 10, 16); err == nil {
|
|
port = int(parsedPort) // nolint: gosec // Bit size of 16 checked above.
|
|
}
|
|
return
|
|
}
|
|
|
|
// EndUserAttributesFromHTTPRequest generates attributes of the
|
|
// enduser namespace as specified by the OpenTelemetry specification
|
|
// for a span.
|
|
func (sc *SemanticConventions) EndUserAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
|
if username, _, ok := request.BasicAuth(); ok {
|
|
return []attribute.KeyValue{sc.EnduserIDKey.String(username)}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HTTPClientAttributesFromHTTPRequest generates attributes of the
|
|
// http namespace as specified by the OpenTelemetry specification for
|
|
// a span on the client side.
|
|
func (sc *SemanticConventions) HTTPClientAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{}
|
|
|
|
// remove any username/password info that may be in the URL
|
|
// before adding it to the attributes
|
|
userinfo := request.URL.User
|
|
request.URL.User = nil
|
|
|
|
attrs = append(attrs, sc.HTTPURLKey.String(request.URL.String()))
|
|
|
|
// restore any username/password info that was removed
|
|
request.URL.User = userinfo
|
|
|
|
return append(attrs, sc.httpCommonAttributesFromHTTPRequest(request)...)
|
|
}
|
|
|
|
func (sc *SemanticConventions) httpCommonAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{}
|
|
if ua := request.UserAgent(); ua != "" {
|
|
attrs = append(attrs, sc.HTTPUserAgentKey.String(ua))
|
|
}
|
|
if request.ContentLength > 0 {
|
|
attrs = append(attrs, sc.HTTPRequestContentLengthKey.Int64(request.ContentLength))
|
|
}
|
|
|
|
return append(attrs, sc.httpBasicAttributesFromHTTPRequest(request)...)
|
|
}
|
|
|
|
func (sc *SemanticConventions) httpBasicAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
|
// as these attributes are used by HTTPServerMetricAttributesFromHTTPRequest, they should be low-cardinality
|
|
attrs := []attribute.KeyValue{}
|
|
|
|
if request.TLS != nil {
|
|
attrs = append(attrs, sc.HTTPSchemeHTTPS)
|
|
} else {
|
|
attrs = append(attrs, sc.HTTPSchemeHTTP)
|
|
}
|
|
|
|
if request.Host != "" {
|
|
attrs = append(attrs, sc.HTTPHostKey.String(request.Host))
|
|
} else if request.URL != nil && request.URL.Host != "" {
|
|
attrs = append(attrs, sc.HTTPHostKey.String(request.URL.Host))
|
|
}
|
|
|
|
flavor := ""
|
|
if request.ProtoMajor == 1 {
|
|
flavor = fmt.Sprintf("1.%d", request.ProtoMinor)
|
|
} else if request.ProtoMajor == 2 {
|
|
flavor = "2"
|
|
}
|
|
if flavor != "" {
|
|
attrs = append(attrs, sc.HTTPFlavorKey.String(flavor))
|
|
}
|
|
|
|
if request.Method != "" {
|
|
attrs = append(attrs, sc.HTTPMethodKey.String(request.Method))
|
|
} else {
|
|
attrs = append(attrs, sc.HTTPMethodKey.String(http.MethodGet))
|
|
}
|
|
|
|
return attrs
|
|
}
|
|
|
|
// HTTPServerMetricAttributesFromHTTPRequest generates low-cardinality attributes
|
|
// to be used with server-side HTTP metrics.
|
|
func (sc *SemanticConventions) HTTPServerMetricAttributesFromHTTPRequest(serverName string, request *http.Request) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{}
|
|
if serverName != "" {
|
|
attrs = append(attrs, sc.HTTPServerNameKey.String(serverName))
|
|
}
|
|
return append(attrs, sc.httpBasicAttributesFromHTTPRequest(request)...)
|
|
}
|
|
|
|
// HTTPServerAttributesFromHTTPRequest generates attributes of the
|
|
// http namespace as specified by the OpenTelemetry specification for
|
|
// a span on the server side. Currently, only basic authentication is
|
|
// supported.
|
|
func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(serverName, route string, request *http.Request) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{
|
|
sc.HTTPTargetKey.String(request.RequestURI),
|
|
}
|
|
|
|
if serverName != "" {
|
|
attrs = append(attrs, sc.HTTPServerNameKey.String(serverName))
|
|
}
|
|
if route != "" {
|
|
attrs = append(attrs, sc.HTTPRouteKey.String(route))
|
|
}
|
|
if values := request.Header["X-Forwarded-For"]; len(values) > 0 {
|
|
addr := values[0]
|
|
if i := strings.Index(addr, ","); i > 0 {
|
|
addr = addr[:i]
|
|
}
|
|
attrs = append(attrs, sc.HTTPClientIPKey.String(addr))
|
|
}
|
|
|
|
return append(attrs, sc.httpCommonAttributesFromHTTPRequest(request)...)
|
|
}
|
|
|
|
// HTTPAttributesFromHTTPStatusCode generates attributes of the http
|
|
// namespace as specified by the OpenTelemetry specification for a
|
|
// span.
|
|
func (sc *SemanticConventions) HTTPAttributesFromHTTPStatusCode(code int) []attribute.KeyValue {
|
|
attrs := []attribute.KeyValue{
|
|
sc.HTTPStatusCodeKey.Int(code),
|
|
}
|
|
return attrs
|
|
}
|
|
|
|
type codeRange struct {
|
|
fromInclusive int
|
|
toInclusive int
|
|
}
|
|
|
|
func (r codeRange) contains(code int) bool {
|
|
return r.fromInclusive <= code && code <= r.toInclusive
|
|
}
|
|
|
|
var validRangesPerCategory = map[int][]codeRange{
|
|
1: {
|
|
{http.StatusContinue, http.StatusEarlyHints},
|
|
},
|
|
2: {
|
|
{http.StatusOK, http.StatusAlreadyReported},
|
|
{http.StatusIMUsed, http.StatusIMUsed},
|
|
},
|
|
3: {
|
|
{http.StatusMultipleChoices, http.StatusUseProxy},
|
|
{http.StatusTemporaryRedirect, http.StatusPermanentRedirect},
|
|
},
|
|
4: {
|
|
{http.StatusBadRequest, http.StatusTeapot}, // yes, teapot is so useful…
|
|
{http.StatusMisdirectedRequest, http.StatusUpgradeRequired},
|
|
{http.StatusPreconditionRequired, http.StatusTooManyRequests},
|
|
{http.StatusRequestHeaderFieldsTooLarge, http.StatusRequestHeaderFieldsTooLarge},
|
|
{http.StatusUnavailableForLegalReasons, http.StatusUnavailableForLegalReasons},
|
|
},
|
|
5: {
|
|
{http.StatusInternalServerError, http.StatusLoopDetected},
|
|
{http.StatusNotExtended, http.StatusNetworkAuthenticationRequired},
|
|
},
|
|
}
|
|
|
|
// SpanStatusFromHTTPStatusCode generates a status code and a message
|
|
// as specified by the OpenTelemetry specification for a span.
|
|
func SpanStatusFromHTTPStatusCode(code int) (codes.Code, string) {
|
|
spanCode, valid := validateHTTPStatusCode(code)
|
|
if !valid {
|
|
return spanCode, fmt.Sprintf("Invalid HTTP status code %d", code)
|
|
}
|
|
return spanCode, ""
|
|
}
|
|
|
|
// SpanStatusFromHTTPStatusCodeAndSpanKind generates a status code and a message
|
|
// as specified by the OpenTelemetry specification for a span.
|
|
// Exclude 4xx for SERVER to set the appropriate status.
|
|
func SpanStatusFromHTTPStatusCodeAndSpanKind(code int, spanKind trace.SpanKind) (codes.Code, string) {
|
|
spanCode, valid := validateHTTPStatusCode(code)
|
|
if !valid {
|
|
return spanCode, fmt.Sprintf("Invalid HTTP status code %d", code)
|
|
}
|
|
category := code / 100
|
|
if spanKind == trace.SpanKindServer && category == 4 {
|
|
return codes.Unset, ""
|
|
}
|
|
return spanCode, ""
|
|
}
|
|
|
|
// validateHTTPStatusCode validates the HTTP status code and returns
|
|
// corresponding span status code. If the `code` is not a valid HTTP status
|
|
// code, returns span status Error and false.
|
|
func validateHTTPStatusCode(code int) (codes.Code, bool) {
|
|
category := code / 100
|
|
ranges, ok := validRangesPerCategory[category]
|
|
if !ok {
|
|
return codes.Error, false
|
|
}
|
|
ok = false
|
|
for _, crange := range ranges {
|
|
ok = crange.contains(code)
|
|
if ok {
|
|
break
|
|
}
|
|
}
|
|
if !ok {
|
|
return codes.Error, false
|
|
}
|
|
if category > 0 && category < 4 {
|
|
return codes.Unset, true
|
|
}
|
|
return codes.Error, true
|
|
}
|