mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 00:22:14 +01:00
309 lines
7.7 KiB
Go
309 lines
7.7 KiB
Go
// Code generated by gotmpl. DO NOT MODIFY.
|
|
// source: internal/shared/semconv/client.go.tmpl
|
|
|
|
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package semconv provides OpenTelemetry semantic convention types and
|
|
// functionality.
|
|
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/codes"
|
|
"go.opentelemetry.io/otel/metric"
|
|
"go.opentelemetry.io/otel/semconv/v1.39.0"
|
|
"go.opentelemetry.io/otel/semconv/v1.39.0/httpconv"
|
|
)
|
|
|
|
type HTTPClient struct {
|
|
requestBodySize httpconv.ClientRequestBodySize
|
|
requestDuration httpconv.ClientRequestDuration
|
|
}
|
|
|
|
func NewHTTPClient(meter metric.Meter) HTTPClient {
|
|
client := HTTPClient{}
|
|
|
|
var err error
|
|
client.requestBodySize, err = httpconv.NewClientRequestBodySize(meter)
|
|
handleErr(err)
|
|
|
|
client.requestDuration, err = httpconv.NewClientRequestDuration(
|
|
meter,
|
|
metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10),
|
|
)
|
|
handleErr(err)
|
|
|
|
return client
|
|
}
|
|
|
|
func (n HTTPClient) Status(code int) (codes.Code, string) {
|
|
if code == 0 {
|
|
return codes.Error, "No HTTP status code"
|
|
}
|
|
if code < 100 || code >= 600 {
|
|
return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code)
|
|
}
|
|
if code >= 400 {
|
|
return codes.Error, http.StatusText(code)
|
|
}
|
|
return codes.Ok, ""
|
|
}
|
|
|
|
// RequestTraceAttrs returns trace attributes for an HTTP request made by a client.
|
|
func (n HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue {
|
|
/*
|
|
below attributes are returned:
|
|
- http.request.method
|
|
- http.request.method.original
|
|
- url.full
|
|
- server.address
|
|
- server.port
|
|
- network.protocol.name
|
|
- network.protocol.version
|
|
*/
|
|
numOfAttributes := 3 // URL, server address, proto, and method.
|
|
|
|
var urlHost string
|
|
if req.URL != nil {
|
|
urlHost = req.URL.Host
|
|
}
|
|
var requestHost string
|
|
var requestPort int
|
|
for _, hostport := range []string{urlHost, req.Header.Get("Host")} {
|
|
requestHost, requestPort = SplitHostPort(hostport)
|
|
if requestHost != "" || requestPort > 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
eligiblePort := requiredHTTPPort(req.URL != nil && req.URL.Scheme == "https", requestPort)
|
|
if eligiblePort > 0 {
|
|
numOfAttributes++
|
|
}
|
|
useragent := req.UserAgent()
|
|
if useragent != "" {
|
|
numOfAttributes++
|
|
}
|
|
|
|
protoName, protoVersion := netProtocol(req.Proto)
|
|
if protoName != "" && protoName != "http" {
|
|
numOfAttributes++
|
|
}
|
|
if protoVersion != "" {
|
|
numOfAttributes++
|
|
}
|
|
|
|
method, originalMethod := n.method(req.Method)
|
|
if originalMethod != (attribute.KeyValue{}) {
|
|
numOfAttributes++
|
|
}
|
|
|
|
attrs := make([]attribute.KeyValue, 0, numOfAttributes)
|
|
|
|
attrs = append(attrs, method)
|
|
if originalMethod != (attribute.KeyValue{}) {
|
|
attrs = append(attrs, originalMethod)
|
|
}
|
|
|
|
var u string
|
|
if req.URL != nil {
|
|
// Remove any username/password info that may be in the URL.
|
|
userinfo := req.URL.User
|
|
req.URL.User = nil
|
|
u = req.URL.String()
|
|
// Restore any username/password info that was removed.
|
|
req.URL.User = userinfo
|
|
}
|
|
attrs = append(attrs, semconv.URLFull(u))
|
|
|
|
attrs = append(attrs, semconv.ServerAddress(requestHost))
|
|
if eligiblePort > 0 {
|
|
attrs = append(attrs, semconv.ServerPort(eligiblePort))
|
|
}
|
|
|
|
if protoName != "" && protoName != "http" {
|
|
attrs = append(attrs, semconv.NetworkProtocolName(protoName))
|
|
}
|
|
if protoVersion != "" {
|
|
attrs = append(attrs, semconv.NetworkProtocolVersion(protoVersion))
|
|
}
|
|
|
|
return attrs
|
|
}
|
|
|
|
// ResponseTraceAttrs returns trace attributes for an HTTP response made by a client.
|
|
func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue {
|
|
/*
|
|
below attributes are returned:
|
|
- http.response.status_code
|
|
- error.type
|
|
*/
|
|
var count int
|
|
if resp.StatusCode > 0 {
|
|
count++
|
|
}
|
|
|
|
if isErrorStatusCode(resp.StatusCode) {
|
|
count++
|
|
}
|
|
|
|
attrs := make([]attribute.KeyValue, 0, count)
|
|
if resp.StatusCode > 0 {
|
|
attrs = append(attrs, semconv.HTTPResponseStatusCode(resp.StatusCode))
|
|
}
|
|
|
|
if isErrorStatusCode(resp.StatusCode) {
|
|
errorType := strconv.Itoa(resp.StatusCode)
|
|
attrs = append(attrs, semconv.ErrorTypeKey.String(errorType))
|
|
}
|
|
return attrs
|
|
}
|
|
|
|
func (n HTTPClient) ErrorType(err error) attribute.KeyValue {
|
|
t := reflect.TypeOf(err)
|
|
var value string
|
|
if t.PkgPath() == "" && t.Name() == "" {
|
|
// Likely a builtin type.
|
|
value = t.String()
|
|
} else {
|
|
value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
|
|
}
|
|
|
|
if value == "" {
|
|
return semconv.ErrorTypeOther
|
|
}
|
|
|
|
return semconv.ErrorTypeKey.String(value)
|
|
}
|
|
|
|
func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) {
|
|
if method == "" {
|
|
return semconv.HTTPRequestMethodGet, attribute.KeyValue{}
|
|
}
|
|
if attr, ok := methodLookup[method]; ok {
|
|
return attr, attribute.KeyValue{}
|
|
}
|
|
|
|
orig := semconv.HTTPRequestMethodOriginal(method)
|
|
if attr, ok := methodLookup[strings.ToUpper(method)]; ok {
|
|
return attr, orig
|
|
}
|
|
return semconv.HTTPRequestMethodGet, orig
|
|
}
|
|
|
|
func (n HTTPClient) MetricAttributes(req *http.Request, statusCode int, additionalAttributes []attribute.KeyValue) []attribute.KeyValue {
|
|
num := len(additionalAttributes) + 2
|
|
var h string
|
|
if req.URL != nil {
|
|
h = req.URL.Host
|
|
}
|
|
var requestHost string
|
|
var requestPort int
|
|
for _, hostport := range []string{h, req.Header.Get("Host")} {
|
|
requestHost, requestPort = SplitHostPort(hostport)
|
|
if requestHost != "" || requestPort > 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
port := requiredHTTPPort(req.URL != nil && req.URL.Scheme == "https", requestPort)
|
|
if port > 0 {
|
|
num++
|
|
}
|
|
|
|
protoName, protoVersion := netProtocol(req.Proto)
|
|
if protoName != "" {
|
|
num++
|
|
}
|
|
if protoVersion != "" {
|
|
num++
|
|
}
|
|
|
|
if statusCode > 0 {
|
|
num++
|
|
}
|
|
|
|
attributes := slices.Grow(additionalAttributes, num)
|
|
attributes = append(attributes,
|
|
semconv.HTTPRequestMethodKey.String(standardizeHTTPMethod(req.Method)),
|
|
semconv.ServerAddress(requestHost),
|
|
n.scheme(req),
|
|
)
|
|
|
|
if port > 0 {
|
|
attributes = append(attributes, semconv.ServerPort(port))
|
|
}
|
|
if protoName != "" {
|
|
attributes = append(attributes, semconv.NetworkProtocolName(protoName))
|
|
}
|
|
if protoVersion != "" {
|
|
attributes = append(attributes, semconv.NetworkProtocolVersion(protoVersion))
|
|
}
|
|
|
|
if statusCode > 0 {
|
|
attributes = append(attributes, semconv.HTTPResponseStatusCode(statusCode))
|
|
}
|
|
return attributes
|
|
}
|
|
|
|
type MetricOpts struct {
|
|
measurement metric.MeasurementOption
|
|
addOptions metric.AddOption
|
|
}
|
|
|
|
func (o MetricOpts) MeasurementOption() metric.MeasurementOption {
|
|
return o.measurement
|
|
}
|
|
|
|
func (o MetricOpts) AddOptions() metric.AddOption {
|
|
return o.addOptions
|
|
}
|
|
|
|
func (n HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts {
|
|
opts := map[string]MetricOpts{}
|
|
|
|
attributes := n.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes)
|
|
set := metric.WithAttributeSet(attribute.NewSet(attributes...))
|
|
opts["new"] = MetricOpts{
|
|
measurement: set,
|
|
addOptions: set,
|
|
}
|
|
|
|
return opts
|
|
}
|
|
|
|
func (n HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts map[string]MetricOpts) {
|
|
n.requestBodySize.Inst().Record(ctx, md.RequestSize, opts["new"].MeasurementOption())
|
|
n.requestDuration.Inst().Record(ctx, md.ElapsedTime/1000, opts["new"].MeasurementOption())
|
|
}
|
|
|
|
// TraceAttributes returns attributes for httptrace.
|
|
func (n HTTPClient) TraceAttributes(host string) []attribute.KeyValue {
|
|
return []attribute.KeyValue{
|
|
semconv.ServerAddress(host),
|
|
}
|
|
}
|
|
|
|
func (n HTTPClient) scheme(req *http.Request) attribute.KeyValue {
|
|
if req.URL != nil && req.URL.Scheme != "" {
|
|
return semconv.URLScheme(req.URL.Scheme)
|
|
}
|
|
if req.TLS != nil {
|
|
return semconv.URLScheme("https")
|
|
}
|
|
return semconv.URLScheme("http")
|
|
}
|
|
|
|
func isErrorStatusCode(code int) bool {
|
|
return code >= 400 || code < 100
|
|
}
|