mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
Merge pull request #11573 from owncloud/otelhttp_for_tracing
Otelhttp for tracing
This commit is contained in:
1
go.mod
1
go.mod
@@ -71,7 +71,6 @@ require (
|
||||
github.com/pkg/xattr v0.4.12
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/r3labs/sse/v2 v2.10.0
|
||||
github.com/riandyrn/otelchi v0.12.1
|
||||
github.com/rogpeppe/go-internal v1.14.1
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/rs/zerolog v1.34.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -775,8 +775,6 @@ github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
|
||||
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/riandyrn/otelchi v0.12.1 h1:FdRKK3/RgZ/T+d+qTH5Uw3MFx0KwRF38SkdfTMMq/m8=
|
||||
github.com/riandyrn/otelchi v0.12.1/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
|
||||
@@ -3,18 +3,78 @@ package middleware
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
var propagator = propagation.NewCompositeTextMapPropagator(
|
||||
propagation.Baggage{},
|
||||
propagation.TraceContext{},
|
||||
)
|
||||
// GetOtelhttpMiddleware gets a new tracing middleware based on otelhttp
|
||||
// to trace the requests.
|
||||
// This middleware will use the otelhttp middleware and then store the
|
||||
// incoming data into the go-micro's metadata so it can be propagated through
|
||||
// go-micro.
|
||||
func GetOtelhttpMiddleware(service string, tp trace.TracerProvider) func(http.Handler) http.Handler {
|
||||
otelMid := otelhttp.NewMiddleware(
|
||||
service,
|
||||
otelhttp.WithTracerProvider(tp),
|
||||
otelhttp.WithPropagators(tracing.GetPropagator()),
|
||||
otelhttp.WithSpanOptions(trace.WithSpanKind(trace.SpanKindServer)),
|
||||
otelhttp.WithSpanNameFormatter(func(name string, r *http.Request) string {
|
||||
return r.Method + " " + r.URL.Path
|
||||
}),
|
||||
)
|
||||
|
||||
// TraceContext unpacks the request context looking for an existing trace id.
|
||||
func TraceContext(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
httpToMicroMid := otelhttpToGoMicroGrpc()
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return otelMid(httpToMicroMid(next))
|
||||
}
|
||||
}
|
||||
|
||||
func otelhttpToGoMicroGrpc() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
propagator := tracing.GetPropagator()
|
||||
|
||||
// based on go-micro plugin for opentelemetry
|
||||
// inject telemetry data into go-micro's metadata
|
||||
// in order to propagate the info to go-micro's calls
|
||||
md := make(metadata.Metadata)
|
||||
carrier := make(propagation.MapCarrier)
|
||||
propagator.Inject(ctx, carrier)
|
||||
for k, v := range carrier {
|
||||
md.Set(k, v)
|
||||
}
|
||||
mdCtx := metadata.NewContext(ctx, md)
|
||||
r = r.WithContext(mdCtx)
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GetOtelhttpClient will get a new HTTP client that will use telemetry and
|
||||
// automatically set the telemetry headers. It will wrap the default transport
|
||||
// in order to use telemetry.
|
||||
func GetOtelhttpClient(tp trace.TracerProvider) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: GetOtelhttpClientTransport(http.DefaultTransport, tp),
|
||||
}
|
||||
}
|
||||
|
||||
// GetOtelhttpClientTransport will get a new wrapped transport that will
|
||||
// include telemetry automatically. You can use the http.DefaultTransport
|
||||
// as base transport
|
||||
func GetOtelhttpClientTransport(baseTransport http.RoundTripper, tp trace.TracerProvider) http.RoundTripper {
|
||||
return otelhttp.NewTransport(
|
||||
baseTransport,
|
||||
otelhttp.WithTracerProvider(tp),
|
||||
otelhttp.WithPropagators(tracing.GetPropagator()),
|
||||
otelhttp.WithSpanNameFormatter(func(name string, r *http.Request) string {
|
||||
return r.Method + " " + r.URL.Path
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@ import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
rtrace "github.com/owncloud/reva/v2/pkg/trace"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/jaeger"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
@@ -60,6 +62,20 @@ func GetPropagator() propagation.TextMapPropagator {
|
||||
)
|
||||
}
|
||||
|
||||
// propagatorOnceFn is needed to ensure we set the global propagator only once
|
||||
var propagatorOnceFn sync.Once
|
||||
|
||||
// setGlobalPropagatorOnce set the global propagator only once. This is needed
|
||||
// because go-micro uses the global propagator to extract and inject data and
|
||||
// we want to use the same.
|
||||
// Note: in case of services running in different hosts, this needs to be run
|
||||
// in all of them.
|
||||
func setGlobalPropagatorOnce() {
|
||||
propagatorOnceFn.Do(func() {
|
||||
otel.SetTextMapPropagator(GetPropagator())
|
||||
})
|
||||
}
|
||||
|
||||
// GetTraceProvider returns a configured open-telemetry trace provider.
|
||||
func GetTraceProvider(endpoint, collector, serviceName, traceType string) (*sdktrace.TracerProvider, error) {
|
||||
switch t := traceType; t {
|
||||
@@ -141,6 +157,7 @@ func GetTraceProvider(endpoint, collector, serviceName, traceType string) (*sdkt
|
||||
sdktrace.WithResource(resources),
|
||||
)
|
||||
rtrace.SetDefaultTracerProvider(tp)
|
||||
setGlobalPropagatorOnce()
|
||||
return tp, nil
|
||||
case "agent":
|
||||
fallthrough
|
||||
|
||||
@@ -11,10 +11,8 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
svc "github.com/owncloud/ocis/v2/services/activitylog/pkg/service"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -44,6 +42,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
@@ -68,15 +67,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
mux := chi.NewMux()
|
||||
mux.Use(middlewares...)
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
"actitivylog",
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
handle, err := svc.New(
|
||||
svc.Logger(options.Logger),
|
||||
svc.Stream(options.Stream),
|
||||
|
||||
@@ -11,10 +11,8 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
svc "github.com/owncloud/ocis/v2/services/auth-app/pkg/service"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -44,6 +42,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TracerProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
@@ -68,15 +67,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
mux := chi.NewMux()
|
||||
mux.Use(middlewares...)
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
"auth-app",
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TracerProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
handle, err := svc.NewAuthAppService(
|
||||
svc.Logger(options.Logger),
|
||||
svc.Mux(mux),
|
||||
|
||||
@@ -10,10 +10,8 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
colabmiddleware "github.com/owncloud/ocis/v2/services/collaboration/pkg/middleware"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -39,6 +37,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name+"."+options.Config.App.Name, options.TracerProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name+"."+options.Config.App.Name,
|
||||
@@ -67,16 +66,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
mux := chi.NewMux()
|
||||
mux.Use(middlewares...)
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
options.Config.Service.Name+"."+options.Config.App.Name,
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TracerProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
otelchi.WithRequestMethodInSpanName(true),
|
||||
),
|
||||
)
|
||||
|
||||
prepareRoutes(mux, options)
|
||||
|
||||
// in debug mode print out the actual routes
|
||||
|
||||
@@ -65,7 +65,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.TraceContext,
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
|
||||
@@ -57,9 +57,9 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RealIP,
|
||||
chimiddleware.RequestID,
|
||||
middleware.TraceContext,
|
||||
middleware.NoCache,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
|
||||
@@ -20,12 +20,10 @@ import (
|
||||
"github.com/libregraph/lico/server"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/ldap"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/services/idp/pkg/assets"
|
||||
cs3BackendSupport "github.com/owncloud/ocis/v2/services/idp/pkg/backends/cs3/bootstrap"
|
||||
"github.com/owncloud/ocis/v2/services/idp/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/idp/pkg/middleware"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"gopkg.in/yaml.v2"
|
||||
"stash.kopano.io/kgol/rndm"
|
||||
@@ -125,7 +123,7 @@ func NewService(opts ...Option) Service {
|
||||
routes := []server.WithRoutes{managers.Must("identity").(server.WithRoutes)}
|
||||
handlers := managers.Must("handler").(http.Handler)
|
||||
|
||||
svc := IDP{
|
||||
svc := &IDP{
|
||||
logger: options.Logger,
|
||||
config: options.Config,
|
||||
assets: assetVFS,
|
||||
@@ -282,15 +280,6 @@ func (idp *IDP) initMux(ctx context.Context, r []server.WithRoutes, h http.Handl
|
||||
idp.tp,
|
||||
))
|
||||
|
||||
idp.mux.Use(
|
||||
otelchi.Middleware(
|
||||
"idp",
|
||||
otelchi.WithChiRoutes(idp.mux),
|
||||
otelchi.WithTracerProvider(idp.tp),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
// handle / | index.html with a template that needs to have the BASE_PREFIX replaced
|
||||
idp.mux.Get("/signin/v1/identifier", idp.Index())
|
||||
idp.mux.Get("/signin/v1/identifier/", idp.Index())
|
||||
@@ -305,12 +294,12 @@ func (idp *IDP) initMux(ctx context.Context, r []server.WithRoutes, h http.Handl
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (idp IDP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
func (idp *IDP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
idp.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Index renders the static html with templated variables.
|
||||
func (idp IDP) Index() http.HandlerFunc {
|
||||
func (idp *IDP) Index() http.HandlerFunc {
|
||||
f, err := idp.assets.Open("/identifier/index.html")
|
||||
if err != nil {
|
||||
idp.logger.Fatal().Err(err).Msg("Could not open index template")
|
||||
|
||||
@@ -66,6 +66,7 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
http.Context(ctx),
|
||||
http.Config(cfg),
|
||||
http.Service(svc),
|
||||
http.TraceProvider(traceProvider),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Info().
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/owncloud/ocis/v2/services/invitations/pkg/config"
|
||||
svc "github.com/owncloud/ocis/v2/services/invitations/pkg/service/v0"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -14,13 +15,14 @@ type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
Flags []cli.Flag
|
||||
Service svc.Service
|
||||
Name string
|
||||
Namespace string
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
Flags []cli.Flag
|
||||
Service svc.Service
|
||||
TraceProvider trace.TracerProvider
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -82,3 +84,10 @@ func Service(val svc.Service) Option {
|
||||
o.Service = val
|
||||
}
|
||||
}
|
||||
|
||||
// TraceProvider provides a function to set the trace provider
|
||||
func TraceProvider(tp trace.TracerProvider) Option {
|
||||
return func(o *Options) {
|
||||
o.TraceProvider = tp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ func Server(opts ...Option) (ohttp.Service, error) {
|
||||
|
||||
mux := chi.NewMux()
|
||||
|
||||
mux.Use(middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider))
|
||||
mux.Use(chimiddleware.RealIP)
|
||||
mux.Use(chimiddleware.RequestID)
|
||||
mux.Use(middleware.TraceContext)
|
||||
mux.Use(middleware.NoCache)
|
||||
mux.Use(
|
||||
middleware.Cors(
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/owncloud/reva/v2/pkg/store"
|
||||
"go-micro.dev/v4"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
// Server initializes the http service and server.
|
||||
@@ -50,6 +49,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RealIP,
|
||||
chimiddleware.RequestID,
|
||||
middleware.NoCache,
|
||||
@@ -65,8 +65,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
version.GetString(),
|
||||
),
|
||||
middleware.Logger(options.Logger),
|
||||
middleware.TraceContext,
|
||||
otelhttp.NewMiddleware(options.Config.Service.Name, otelhttp.WithTracerProvider(options.TraceProvider)),
|
||||
),
|
||||
svc.Store(signingKeyStore),
|
||||
)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
)
|
||||
|
||||
// NewTracing returns a service that instruments traces.
|
||||
func NewTracing(next Service) Service {
|
||||
return tracing{
|
||||
next: next,
|
||||
}
|
||||
}
|
||||
|
||||
type tracing struct {
|
||||
next Service
|
||||
}
|
||||
|
||||
// ServeHTTP implements the Service interface.
|
||||
func (t tracing) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.TraceContext(t.next).ServeHTTP(w, r)
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"go-micro.dev/v4/selector"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
@@ -122,6 +121,7 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
rp, err := proxy.NewMultiHostReverseProxy(
|
||||
proxy.Logger(logger),
|
||||
proxy.Config(cfg),
|
||||
proxy.TraceProvider(traceProvider),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize reverse proxy: %w", err)
|
||||
@@ -327,14 +327,7 @@ func loadMiddlewares(logger log.Logger, cfg *config.Config,
|
||||
|
||||
return alice.New(
|
||||
// first make sure we log all requests and redirect to https if necessary
|
||||
otelhttp.NewMiddleware("proxy",
|
||||
otelhttp.WithTracerProvider(traceProvider),
|
||||
otelhttp.WithSpanNameFormatter(func(name string, r *http.Request) string {
|
||||
return fmt.Sprintf("%s %s", r.Method, r.URL.Path)
|
||||
}),
|
||||
),
|
||||
middleware.Tracer(traceProvider),
|
||||
pkgmiddleware.TraceContext,
|
||||
pkgmiddleware.GetOtelhttpMiddleware(cfg.Service.Name, traceProvider),
|
||||
middleware.Instrumenter(metrics),
|
||||
chimiddleware.RealIP,
|
||||
chimiddleware.RequestID,
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/router"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/webdav"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
@@ -52,17 +51,10 @@ type Authenticator interface {
|
||||
func Authentication(auths []Authenticator, opts ...Option) func(next http.Handler) http.Handler {
|
||||
options := newOptions(opts...)
|
||||
configureSupportedChallenges(options)
|
||||
tracer := getTraceProvider(options).Tracer("proxy")
|
||||
|
||||
spanOpts := []trace.SpanStartOption{
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := tracer.Start(r.Context(), fmt.Sprintf("%s %v", r.Method, r.URL.Path), spanOpts...)
|
||||
defer span.End()
|
||||
r = r.WithContext(ctx)
|
||||
ctx := r.Context()
|
||||
|
||||
ri := router.ContextRoutingInfo(ctx)
|
||||
if isOIDCTokenAuth(r) || ri.IsRouteUnprotected() || r.Method == http.MethodOptions {
|
||||
@@ -202,10 +194,3 @@ func evalRequestURI(l userAgentLocker, r regexp.Regexp) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTraceProvider(o Options) trace.TracerProvider {
|
||||
if o.TraceProvider != nil {
|
||||
return o.TraceProvider
|
||||
}
|
||||
return trace.NewNoopTracerProvider()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package proxy
|
||||
import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -10,8 +11,9 @@ type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
Logger log.Logger
|
||||
Config *config.Config
|
||||
TraceProvider trace.TracerProvider
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -38,3 +40,10 @@ func Config(val *config.Config) Option {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
|
||||
// TraceProvider provides a function to set the trace provider
|
||||
func TraceProvider(tp trace.TracerProvider) Option {
|
||||
return func(o *Options) {
|
||||
o.TraceProvider = tp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/proxy/policy"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/router"
|
||||
@@ -72,7 +73,7 @@ func NewMultiHostReverseProxy(opts ...Option) (*MultiHostReverseProxy, error) {
|
||||
tlsConf.RootCAs = certs
|
||||
}
|
||||
// equals http.DefaultTransport except TLSClientConfig
|
||||
rp.Transport = &http.Transport{
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
@@ -86,6 +87,7 @@ func NewMultiHostReverseProxy(opts ...Option) (*MultiHostReverseProxy, error) {
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
TLSClientConfig: tlsConf,
|
||||
}
|
||||
rp.Transport = middleware.GetOtelhttpClientTransport(transport, options.TraceProvider)
|
||||
return rp, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/errorcode"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
|
||||
utils "github.com/owncloud/reva/v2/pkg/utils"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
type cs3backend struct {
|
||||
@@ -123,14 +125,14 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string) (
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, "", fmt.Errorf("could not get user by claim %v with value %v: %w", claim, value, err)
|
||||
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
|
||||
if res.Status.Code == rpcv1beta1.Code_CODE_NOT_FOUND {
|
||||
case res.GetStatus().GetCode() != rpcv1beta1.Code_CODE_OK:
|
||||
if res.GetStatus().GetCode() == rpcv1beta1.Code_CODE_NOT_FOUND {
|
||||
return nil, "", ErrAccountNotFound
|
||||
}
|
||||
return nil, "", fmt.Errorf("could not get user by claim %v with value %v : %s ", claim, value, res.GetStatus().GetMessage())
|
||||
}
|
||||
|
||||
user := res.User
|
||||
user := res.GetUser()
|
||||
|
||||
return user, res.GetToken(), nil
|
||||
}
|
||||
@@ -150,11 +152,11 @@ func (c *cs3backend) Authenticate(ctx context.Context, username string, password
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, %w", username, err)
|
||||
case res.Status.Code != rpcv1beta1.Code_CODE_OK:
|
||||
case res.GetStatus().GetCode() != rpcv1beta1.Code_CODE_OK:
|
||||
return nil, "", fmt.Errorf("could not authenticate with username and password user: %s, got code: %d", username, res.GetStatus().GetCode())
|
||||
}
|
||||
|
||||
return res.User, res.Token, nil
|
||||
return res.GetUser(), res.GetToken(), nil
|
||||
}
|
||||
|
||||
// CreateUserFromClaims creates a new user via libregraph users API, taking the
|
||||
@@ -233,7 +235,7 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
|
||||
return &cs3UserCreated, nil
|
||||
}
|
||||
|
||||
func (c cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
|
||||
func (c *cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
|
||||
newUser, err := c.libregraphUserFromClaims(claims)
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Interface("claims", claims).Msg("Error converting claims to user")
|
||||
@@ -258,7 +260,7 @@ func (c cs3backend) UpdateUserIfNeeded(ctx context.Context, user *cs3.User, clai
|
||||
}
|
||||
|
||||
// SyncGroupMemberships maintains a users group memberships based on an OIDC claim
|
||||
func (c cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
|
||||
func (c *cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, claims map[string]interface{}) error {
|
||||
gatewayClient, err := c.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("could not select next gateway client")
|
||||
@@ -376,7 +378,7 @@ func (c cs3backend) SyncGroupMemberships(ctx context.Context, user *cs3.User, cl
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cs3backend) getLibregraphGroup(ctx context.Context, client *libregraph.APIClient, group string) (*libregraph.Group, error) {
|
||||
func (c *cs3backend) getLibregraphGroup(ctx context.Context, client *libregraph.APIClient, group string) (*libregraph.Group, error) {
|
||||
lgGroup, resp, err := client.GroupApi.GetGroup(ctx, group).Execute()
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
@@ -394,7 +396,7 @@ func (c cs3backend) getLibregraphGroup(ctx context.Context, client *libregraph.A
|
||||
return lgGroup, nil
|
||||
}
|
||||
|
||||
func (c cs3backend) updateLibregraphUser(userid string, user libregraph.UserUpdate) error {
|
||||
func (c *cs3backend) updateLibregraphUser(userid string, user libregraph.UserUpdate) error {
|
||||
gatewayClient, err := c.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("could not select next gateway client")
|
||||
@@ -425,7 +427,7 @@ func (c cs3backend) updateLibregraphUser(userid string, user libregraph.UserUpda
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cs3backend) setupLibregraphClient(_ context.Context, cs3token string) (*libregraph.APIClient, error) {
|
||||
func (c *cs3backend) setupLibregraphClient(ctx context.Context, cs3token string) (*libregraph.APIClient, error) {
|
||||
// Use micro registry to resolve next graph service endpoint
|
||||
next, err := c.graphSelector.Select("com.owncloud.web.graph")
|
||||
if err != nil {
|
||||
@@ -445,10 +447,14 @@ func (c cs3backend) setupLibregraphClient(_ context.Context, cs3token string) (*
|
||||
}
|
||||
|
||||
lgconf.DefaultHeader = map[string]string{revactx.TokenHeader: cs3token}
|
||||
|
||||
// TODO: Need to improve the setup of the HTTP client for libregraph
|
||||
span := trace.SpanFromContext(ctx)
|
||||
lgconf.HTTPClient = middleware.GetOtelhttpClient(span.TracerProvider())
|
||||
return libregraph.NewAPIClient(lgconf), nil
|
||||
}
|
||||
|
||||
func (c cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
|
||||
func (c *cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
|
||||
oDataErr := libregraph.NewOdataErrorWithDefaults()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@@ -469,7 +475,7 @@ func (c cs3backend) isAlreadyExists(resp *http.Response) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c cs3backend) libregraphUserFromClaims(claims map[string]interface{}) (libregraph.User, error) {
|
||||
func (c *cs3backend) libregraphUserFromClaims(claims map[string]interface{}) (libregraph.User, error) {
|
||||
user := libregraph.User{}
|
||||
if dn, ok := claims[c.autoProvisionClaims.DisplayName].(string); ok {
|
||||
user.SetDisplayName(dn)
|
||||
@@ -499,7 +505,7 @@ func (c cs3backend) libregraphUserFromClaims(claims map[string]interface{}) (lib
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (c cs3backend) cs3UserFromLibregraph(_ context.Context, lu *libregraph.User) cs3.User {
|
||||
func (c *cs3backend) cs3UserFromLibregraph(_ context.Context, lu *libregraph.User) cs3.User {
|
||||
cs3id := cs3.UserId{
|
||||
Type: cs3.UserType_USER_TYPE_PRIMARY,
|
||||
Idp: c.oidcISS,
|
||||
|
||||
@@ -10,10 +10,8 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
ohttp "github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -42,6 +40,7 @@ func Server(opts ...Option) (ohttp.Service, error) {
|
||||
|
||||
mux := chi.NewMux()
|
||||
|
||||
mux.Use(middleware.GetOtelhttpMiddleware(options.Name, options.TraceProvider))
|
||||
mux.Use(chimiddleware.RealIP)
|
||||
mux.Use(chimiddleware.RequestID)
|
||||
mux.Use(middleware.NoCache)
|
||||
@@ -66,15 +65,6 @@ func Server(opts ...Option) (ohttp.Service, error) {
|
||||
options.Logger,
|
||||
))
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
options.Name,
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
mux.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
settingssvc.RegisterBundleServiceWeb(r, handle)
|
||||
settingssvc.RegisterValueServiceWeb(r, handle)
|
||||
|
||||
@@ -12,11 +12,9 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
svc "github.com/owncloud/ocis/v2/services/sse/pkg/service"
|
||||
"github.com/owncloud/reva/v2/pkg/events"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -45,6 +43,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TracerProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
@@ -69,15 +68,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
mux := chi.NewMux()
|
||||
mux.Use(middlewares...)
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
"sse",
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TracerProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
ch, err := events.Consume(options.Consumer, "sse-"+uuid.New().String(), options.RegisteredEvents...)
|
||||
if err != nil {
|
||||
return http.Service{}, err
|
||||
|
||||
@@ -38,6 +38,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(
|
||||
ocismiddleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
middleware.RealIP,
|
||||
middleware.RequestID,
|
||||
ocismiddleware.Cors(
|
||||
|
||||
@@ -8,10 +8,8 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/riandyrn/otelchi"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
|
||||
tjwt "github.com/owncloud/ocis/v2/services/thumbnails/pkg/service/jwt"
|
||||
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/thumbnail"
|
||||
@@ -36,15 +34,6 @@ func NewService(opts ...Option) Service {
|
||||
m := chi.NewMux()
|
||||
m.Use(options.Middleware...)
|
||||
|
||||
m.Use(
|
||||
otelchi.Middleware(
|
||||
"thumbnails",
|
||||
otelchi.WithChiRoutes(m),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
logger := options.Logger
|
||||
resolutions, err := thumbnail.ParseResolutions(options.Config.Thumbnail.Resolutions)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,10 +11,8 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
svc "github.com/owncloud/ocis/v2/services/userlog/pkg/service"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -44,6 +42,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
}
|
||||
|
||||
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TracerProvider),
|
||||
chimiddleware.RequestID,
|
||||
middleware.Version(
|
||||
options.Config.Service.Name,
|
||||
@@ -68,15 +67,6 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
mux := chi.NewMux()
|
||||
mux.Use(middlewares...)
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
"userlog",
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TracerProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
handle, err := svc.NewUserlogService(
|
||||
svc.Logger(options.Logger),
|
||||
svc.Stream(options.Stream),
|
||||
|
||||
@@ -57,14 +57,15 @@ func (ul *UserlogService) HandleGetEvents(w http.ResponseWriter, r *http.Request
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ctx, err = utils.GetServiceUserContext(ul.cfg.ServiceAccount.ServiceAccountID, gwc, ul.cfg.ServiceAccount.ServiceAccountSecret)
|
||||
// convCtx is a new context for the NewConverter
|
||||
convCtx, err := utils.GetServiceUserContext(ul.cfg.ServiceAccount.ServiceAccountID, gwc, ul.cfg.ServiceAccount.ServiceAccountSecret)
|
||||
if err != nil {
|
||||
ul.log.Error().Err(err).Msg("cant get service account")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
conv := NewConverter(ctx, r.Header.Get(HeaderAcceptLanguage), ul.gatewaySelector, ul.cfg.Service.Name, ul.cfg.TranslationPath, ul.cfg.DefaultLanguage)
|
||||
conv := NewConverter(convCtx, r.Header.Get(HeaderAcceptLanguage), ul.gatewaySelector, ul.cfg.Service.Name, ul.cfg.TranslationPath, ul.cfg.DefaultLanguage)
|
||||
|
||||
var outdatedEvents []string
|
||||
resp := GetEventResponseOC10{}
|
||||
@@ -254,7 +255,7 @@ func RequireAdminOrSecret(rm *roles.Manager, secret string) func(http.HandlerFun
|
||||
return func(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// allow bypassing admin requirement by sending the correct secret
|
||||
if secret != "" && r.Header.Get("secret") == secret {
|
||||
if secret != "" && r.Header.Get("Secret") == secret {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
http.TLSConfig(options.Config.HTTP.TLS),
|
||||
http.Logger(options.Logger),
|
||||
http.Namespace(options.Namespace),
|
||||
http.Name("web"),
|
||||
http.Name(options.Config.Service.Name),
|
||||
http.Version(version.GetString()),
|
||||
http.Address(options.Config.HTTP.Addr),
|
||||
http.Context(options.Context),
|
||||
@@ -96,6 +96,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.Config(options.Config),
|
||||
svc.GatewaySelector(gatewaySelector),
|
||||
svc.Middleware(
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RealIP,
|
||||
chimiddleware.RequestID,
|
||||
chimiddleware.Compress(5),
|
||||
|
||||
@@ -13,12 +13,10 @@ import (
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/riandyrn/otelchi"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/account"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/x/io/fsx"
|
||||
"github.com/owncloud/ocis/v2/services/web/pkg/assets"
|
||||
"github.com/owncloud/ocis/v2/services/web/pkg/config"
|
||||
@@ -41,15 +39,6 @@ func NewService(opts ...Option) (Service, error) {
|
||||
m := chi.NewMux()
|
||||
m.Use(options.Middleware...)
|
||||
|
||||
m.Use(
|
||||
otelchi.Middleware(
|
||||
"web",
|
||||
otelchi.WithChiRoutes(m),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
svc := Web{
|
||||
logger: options.Logger,
|
||||
config: options.Config,
|
||||
|
||||
@@ -38,6 +38,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
svc.Logger(options.Logger),
|
||||
svc.Config(options.Config),
|
||||
svc.Middleware(
|
||||
middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider),
|
||||
chimiddleware.RealIP,
|
||||
chimiddleware.RequestID,
|
||||
middleware.NoCache,
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
revactx "github.com/owncloud/reva/v2/pkg/ctx"
|
||||
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/owncloud/reva/v2/pkg/storage/utils/templates"
|
||||
"github.com/riandyrn/otelchi"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
grpcmetadata "google.golang.org/grpc/metadata"
|
||||
|
||||
@@ -56,14 +55,6 @@ func NewService(opts ...Option) (Service, error) {
|
||||
conf := options.Config
|
||||
|
||||
m := chi.NewMux()
|
||||
m.Use(
|
||||
otelchi.Middleware(
|
||||
conf.Service.Name,
|
||||
otelchi.WithChiRoutes(m),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
tm, err := pool.StringToTLSMode(conf.GRPCClientTLS.Mode)
|
||||
if err != nil {
|
||||
@@ -95,6 +86,7 @@ func NewService(opts ...Option) (Service, error) {
|
||||
// register method with chi before any routing is set up
|
||||
chi.RegisterMethod("REPORT")
|
||||
|
||||
m.Use(options.Middleware...)
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
|
||||
if !svc.config.DisablePreviews {
|
||||
|
||||
@@ -12,12 +12,10 @@ import (
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/cors"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
ohttp "github.com/owncloud/ocis/v2/ocis-pkg/service/http"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
serviceErrors "github.com/owncloud/ocis/v2/services/webfinger/pkg/service/v0"
|
||||
svc "github.com/owncloud/ocis/v2/services/webfinger/pkg/service/v0"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/riandyrn/otelchi"
|
||||
"go-micro.dev/v4"
|
||||
)
|
||||
|
||||
@@ -45,9 +43,9 @@ func Server(opts ...Option) (ohttp.Service, error) {
|
||||
|
||||
mux := chi.NewMux()
|
||||
|
||||
mux.Use(middleware.GetOtelhttpMiddleware(options.Config.Service.Name, options.TraceProvider))
|
||||
mux.Use(chimiddleware.RealIP)
|
||||
mux.Use(chimiddleware.RequestID)
|
||||
mux.Use(middleware.TraceContext)
|
||||
mux.Use(middleware.NoCache)
|
||||
mux.Use(
|
||||
middleware.Cors(
|
||||
@@ -63,15 +61,6 @@ func Server(opts ...Option) (ohttp.Service, error) {
|
||||
version.String,
|
||||
))
|
||||
|
||||
mux.Use(
|
||||
otelchi.Middleware(
|
||||
options.Name,
|
||||
otelchi.WithChiRoutes(mux),
|
||||
otelchi.WithTracerProvider(options.TraceProvider),
|
||||
otelchi.WithPropagators(tracing.GetPropagator()),
|
||||
),
|
||||
)
|
||||
|
||||
var oidcHTTPClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
|
||||
280
vendor/github.com/riandyrn/otelchi/CHANGELOG.md
generated
vendored
280
vendor/github.com/riandyrn/otelchi/CHANGELOG.md
generated
vendored
@@ -1,280 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.12.1] - 2025-02-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix superfluous header writer ([#89])
|
||||
|
||||
## [0.12.0] - 2025-01-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade `go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/sdk`, & `go.opentelemetry.io/otel/trace` to `v1.34.0`. ([#87])
|
||||
- Upgrade `go.opentelemetry.io/otel/metric` to `v1.34.0`. ([#87])
|
||||
- Set the metric version to be the same as middleware version which is `v0.12.0` to make it easy for maintainer of this repo to maintain the versioning. ([#88])
|
||||
|
||||
## [0.11.0] - 2024-11-27
|
||||
|
||||
### Added
|
||||
|
||||
- Add metric package as middleware `go-chi/chi`, support `request_duration_millis`, `requests_inflight`, and `response_size_bytes` metric. Using `go.opentelemetry.io/otel/metric` which the version is `v1.32.0`. ([#69])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade `go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/sdk`, & `go.opentelemetry.io/otel/trace` to `v1.32.0`. ([#74])
|
||||
|
||||
## [0.10.1] - 2024-10-27
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade `go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/sdk`, & `go.opentelemetry.io/otel/trace` to `v1.31.0`. ([#70])
|
||||
|
||||
### Fixed
|
||||
|
||||
- Span for websocket connection now won't be marked as error span. ([#67])
|
||||
|
||||
## [0.10.0] - 2024-09-17
|
||||
|
||||
### Added
|
||||
|
||||
- Add `WithTraceResponseHeaders` option to include trace information in response headers, this option replaces the deprecated `WithTraceIDResponseHeader` option. ([#62])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade `go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/sdk`, & `go.opentelemetry.io/otel/trace` to `v1.30.0`. ([#64])
|
||||
- Set the go versions for testing in both `Makefile` & `compatibility-test.yml` to `1.22` & `1.23`. ([#64])
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Gobrew installation in CI pipeline. ([#63])
|
||||
|
||||
### Removed
|
||||
|
||||
- Drop support for Go 1.21. ([#64])
|
||||
- Deprecated `WithTraceIDResponseHeader` option, use `WithTraceResponseHeaders` instead. ([#62])
|
||||
|
||||
## [0.9.0] - 2024-07-06
|
||||
|
||||
### Changed
|
||||
|
||||
- `WithFilter` option now support multiple filter functions, just like in [otelmux](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/v1.24.0/instrumentation/github.com/gorilla/mux/otelmux/config.go#L106-L110). ([#47])
|
||||
- Upgrade `go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/sdk`, & `go.opentelemetry.io/otel/trace` to `v1.28.0`. ([#49])
|
||||
- Upgrade `github.com/go-chi/chi/v5` to `v5.1.0`. ([#49])
|
||||
- Set the go versions for testing in both `Makefile` & `compatibility-test.yml` to `1.21` & `1.22`. ([#49])
|
||||
|
||||
### Removed
|
||||
|
||||
- Drop support for Go `<1.21`. ([#49])
|
||||
|
||||
## [0.8.0] - 2024-04-29
|
||||
|
||||
### ⚠️ Notice ⚠️
|
||||
|
||||
This release is the last to support Go `1.19`. The next release will require at least Go `1.21`.
|
||||
|
||||
### Added
|
||||
|
||||
- Add `WithPublicEndpoint` & `WithPublicEndpointFn` options. ([#43])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to `v1.24.0` of `go.opentelemetry.io/otel`. ([#41])
|
||||
- Upgrade to `v1.20.0` of `go.opentelemetry.io/otel/semconv`. ([#41])
|
||||
- Adjust Go version for both `examples/basic` & `examples/multi-services` to `1.19` & `go.opentelemetry.io/otel` to `v1.24.0`. ([#41])
|
||||
- Update otelhttp version to `0.49.0` since it is the version that uses otel `1.24.0` internally, check [here](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/v1.24.0/instrumentation/net/http/otelhttp/go.mod#L8) for details. ([#42])
|
||||
- Set the go versions in compatibility-test.yml to 1.19, 1.20, & 1.21. ([#42])
|
||||
- Set the sampling strategy to always sample in test cases to avoid random error. ([#42])
|
||||
- Use `otlptrace` exporter instead of `jaeger` exporter in `examples/multi-services`. ([#42])
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove the deprecated `jaeger` exporter from `examples/multi-services` & use `otlptrace` exporter instead. ([#42])
|
||||
- Drop support for Go `<1.19`. ([#41])
|
||||
|
||||
## [0.7.0] - 2024-04-22
|
||||
|
||||
### ⚠️ Notice ⚠️
|
||||
|
||||
This release is the last to support Go `1.18`. The next release will require at least Go `1.19`.
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to `v1.14.0` of `go.opentelemetry.io/otel`. ([#38])
|
||||
- Upgrade to `v1.17.0` of `go.opentelemetry.io/otel/semconv`. ([#38])
|
||||
- Adjust Go version for both `examples/basic` & `examples/multi-services` to `1.18` & `go.opentelemetry.io/otel` to `v1.14.0`. ([#38])
|
||||
- Change `http.server_name` attributes to `net.host.name`, this is because semconv is removing this attribute for http. ([#38])
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove `http.target` attribute on implementation & tests based on [this comment](https://github.com/open-telemetry/opentelemetry-go/blob/v1.17.0/semconv/internal/v2/http.go#L160-L165). ([#39])
|
||||
- Drop support for Go `<1.18`. ([#38])
|
||||
|
||||
## [0.6.0] - 2024-04-02
|
||||
|
||||
### ⚠️ Notice ⚠️
|
||||
|
||||
This release is the last to support Go `1.15`. The next release will require at least Go `1.18`.
|
||||
|
||||
### Added
|
||||
|
||||
- Add `WithTraceIDResponseHeader` option to enable adding trace id into response header. ([#36])
|
||||
- Add multiple go versions test scripts for local and CI pipeline. ([#29])
|
||||
- Add compatibility testing for `ubuntu`, `macos` and `windows`. ([#32])
|
||||
- Add repo essentials docs. ([#33])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to `v5.0.12` of `go-chi/chi`. ([#29])
|
||||
- Upgrade to `v1.10.0` of `go.opentelemetry.io/otel`. ([#29])
|
||||
- Upgrade to `v1.12.0` of `go.opentelemetry.io/otel/semconv`. ([#29])
|
||||
- Set the required go version for both `examples/basic` & `examples/multi-services` to `1.15`, `go-chi/chi` to `v5.0.12`, & `go.opentelemetry.io/otel` to `v1.10.0` ([#35])
|
||||
|
||||
## [0.5.2] - 2024-03-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix empty status code. ([#30])
|
||||
|
||||
### Changed
|
||||
|
||||
- Return `http.StatusOK` (200) as a default `http.status_code` span attribute. ([#30])
|
||||
|
||||
## [0.5.1] - 2023-02-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix broken empty routes. ([#18])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to `v5.0.8` of `go-chi/chi`.
|
||||
|
||||
## [0.5.0] - 2022-10-02
|
||||
|
||||
### Added
|
||||
|
||||
- Add multi services example. ([#9])
|
||||
- Add `WithFilter()` option to ignore tracing in certain endpoints. ([#11])
|
||||
|
||||
## [0.4.0] - 2022-02-22
|
||||
|
||||
### Added
|
||||
|
||||
- Add Option `WithRequestMethodInSpanName()` to handle vendor that do not include HTTP request method as mentioned in [#6]. ([#7])
|
||||
- Refine description for `WithChiRoutes()` option to announce it is possible to override the span name in underlying handler with this option.
|
||||
|
||||
### Changed
|
||||
|
||||
## [0.3.0] - 2022-01-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix both `docker-compose.yml` & `Dockerfile` in the example. ([#5])
|
||||
|
||||
### Added
|
||||
|
||||
- Add `WithChiRoutes()` option to make the middleware able to determine full route pattern on span creation. ([#5])
|
||||
- Set all known span attributes on span creation rather than set them after request is being executed. ([#5])
|
||||
|
||||
## [0.2.1] - 2022-01-08
|
||||
|
||||
### Added
|
||||
|
||||
- Add build example to CI pipeline. ([#2])
|
||||
|
||||
### Changed
|
||||
|
||||
- Use `ctx.RoutePattern()` to get span name, this is to strip out noisy wildcard pattern. ([#1])
|
||||
|
||||
## [0.2.0] - 2021-10-18
|
||||
|
||||
### Added
|
||||
|
||||
- Set service name on tracer provider from code example.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update dependencies in go.mod
|
||||
- Upgrade to `v1.0.1` of `go.opentelemetry.io/otel`.
|
||||
- Upgrade to `v5.0.4` of `go-chi/chi`.
|
||||
- Update latest test to use `otelmux` format.
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove `HTTPResponseContentLengthKey`
|
||||
- Remove `HTTPTargetKey`, since automatically set in `HTTPServerAttributesFromHTTPRequest`
|
||||
|
||||
## [0.1.0] - 2021-08-11
|
||||
|
||||
This is the first release of otelchi.
|
||||
It contains instrumentation for trace and depends on:
|
||||
|
||||
- otel => `v1.0.0-RC2`
|
||||
- go-chi/chi => `v5.0.3`
|
||||
|
||||
### Added
|
||||
|
||||
- Instrumentation for trace.
|
||||
- CI files.
|
||||
- Example code for a basic usage.
|
||||
- Apache-2.0 license.
|
||||
|
||||
[#89]: https://github.com/riandyrn/otelchi/pull/89
|
||||
[#88]: https://github.com/riandyrn/otelchi/pull/88
|
||||
[#87]: https://github.com/riandyrn/otelchi/pull/87
|
||||
[#74]: https://github.com/riandyrn/otelchi/pull/74
|
||||
[#70]: https://github.com/riandyrn/otelchi/pull/70
|
||||
[#69]: https://github.com/riandyrn/otelchi/pull/69
|
||||
[#67]: https://github.com/riandyrn/otelchi/pull/67
|
||||
[#64]: https://github.com/riandyrn/otelchi/pull/64
|
||||
[#63]: https://github.com/riandyrn/otelchi/pull/63
|
||||
[#62]: https://github.com/riandyrn/otelchi/pull/62
|
||||
[#49]: https://github.com/riandyrn/otelchi/pull/49
|
||||
[#47]: https://github.com/riandyrn/otelchi/pull/47
|
||||
[#43]: https://github.com/riandyrn/otelchi/pull/43
|
||||
[#42]: https://github.com/riandyrn/otelchi/pull/42
|
||||
[#41]: https://github.com/riandyrn/otelchi/pull/41
|
||||
[#39]: https://github.com/riandyrn/otelchi/pull/39
|
||||
[#38]: https://github.com/riandyrn/otelchi/pull/38
|
||||
[#36]: https://github.com/riandyrn/otelchi/pull/36
|
||||
[#35]: https://github.com/riandyrn/otelchi/pull/35
|
||||
[#33]: https://github.com/riandyrn/otelchi/pull/33
|
||||
[#32]: https://github.com/riandyrn/otelchi/pull/32
|
||||
[#30]: https://github.com/riandyrn/otelchi/pull/30
|
||||
[#29]: https://github.com/riandyrn/otelchi/pull/29
|
||||
[#18]: https://github.com/riandyrn/otelchi/pull/18
|
||||
[#11]: https://github.com/riandyrn/otelchi/pull/11
|
||||
[#9]: https://github.com/riandyrn/otelchi/pull/9
|
||||
[#7]: https://github.com/riandyrn/otelchi/pull/7
|
||||
[#6]: https://github.com/riandyrn/otelchi/pull/6
|
||||
[#5]: https://github.com/riandyrn/otelchi/pull/5
|
||||
[#2]: https://github.com/riandyrn/otelchi/pull/2
|
||||
[#1]: https://github.com/riandyrn/otelchi/pull/1
|
||||
|
||||
[Unreleased]: https://github.com/riandyrn/otelchi/compare/v0.12.1...HEAD
|
||||
[0.12.1]: https://github.com/riandyrn/otelchi/releases/tag/v0.12.1
|
||||
[0.12.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.12.0
|
||||
[0.11.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.11.0
|
||||
[0.10.1]: https://github.com/riandyrn/otelchi/releases/tag/v0.10.1
|
||||
[0.10.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.10.0
|
||||
[0.9.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.9.0
|
||||
[0.8.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.8.0
|
||||
[0.7.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.7.0
|
||||
[0.6.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.6.0
|
||||
[0.5.2]: https://github.com/riandyrn/otelchi/releases/tag/v0.5.2
|
||||
[0.5.1]: https://github.com/riandyrn/otelchi/releases/tag/v0.5.1
|
||||
[0.5.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.5.0
|
||||
[0.4.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.4.0
|
||||
[0.3.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.3.0
|
||||
[0.2.1]: https://github.com/riandyrn/otelchi/releases/tag/v0.2.1
|
||||
[0.2.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.2.0
|
||||
[0.1.0]: https://github.com/riandyrn/otelchi/releases/tag/v0.1.0
|
||||
1
vendor/github.com/riandyrn/otelchi/CODEOWNERS
generated
vendored
1
vendor/github.com/riandyrn/otelchi/CODEOWNERS
generated
vendored
@@ -1 +0,0 @@
|
||||
* @riandyrn @ilhamsyahids
|
||||
201
vendor/github.com/riandyrn/otelchi/LICENSE
generated
vendored
201
vendor/github.com/riandyrn/otelchi/LICENSE
generated
vendored
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2021] [Riandy Rahman Nugraha]
|
||||
|
||||
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.
|
||||
29
vendor/github.com/riandyrn/otelchi/Makefile
generated
vendored
29
vendor/github.com/riandyrn/otelchi/Makefile
generated
vendored
@@ -1,29 +0,0 @@
|
||||
.PHONY: *
|
||||
|
||||
GO_VERSIONS="1.22 1.23"
|
||||
|
||||
# This is the command that will be used to run the tests
|
||||
go-test:
|
||||
go build .
|
||||
go test ./...
|
||||
|
||||
# This is the command that will be used to run the tests in a Docker container, useful when executing the test locally
|
||||
test:
|
||||
docker build \
|
||||
-t go-test \
|
||||
--build-arg GO_VERSIONS=${GO_VERSIONS} \
|
||||
-f ./test/infras/Dockerfile . && \
|
||||
docker run --rm go-test
|
||||
|
||||
make test-build-examples
|
||||
|
||||
test-build-examples:
|
||||
make test-build-basic-example
|
||||
make test-build-multi-services-example
|
||||
|
||||
test-build-basic-example:
|
||||
docker build -f ./examples/basic/Dockerfile .
|
||||
|
||||
test-build-multi-services-example:
|
||||
docker build -f ./examples/multi-services/back-svc/Dockerfile .
|
||||
docker build -f ./examples/multi-services/front-svc/Dockerfile .
|
||||
27
vendor/github.com/riandyrn/otelchi/README.md
generated
vendored
27
vendor/github.com/riandyrn/otelchi/README.md
generated
vendored
@@ -1,27 +0,0 @@
|
||||
# otelchi
|
||||
|
||||
[](https://github.com/riandyrn/otelchi/actions/workflows/compatibility-test.yaml)
|
||||
[](https://goreportcard.com/report/github.com/riandyrn/otelchi)
|
||||
[](https://pkg.go.dev/mod/github.com/riandyrn/otelchi)
|
||||
|
||||
OpenTelemetry instrumentation for [go-chi/chi](https://github.com/go-chi/chi).
|
||||
|
||||
Essentially this is an adaptation from [otelmux](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/gorilla/mux/otelmux) but instead of using `gorilla/mux`, we use `go-chi/chi`.
|
||||
|
||||
Currently, this library can only instrument traces and metrics.
|
||||
|
||||
Contributions are welcomed!
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
$ go get github.com/riandyrn/otelchi
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See [examples](./examples) for details.
|
||||
|
||||
## Why Port This?
|
||||
|
||||
I was planning to make this project as part of the Open Telemetry Go instrumentation project. However, based on [this comment](https://github.com/open-telemetry/opentelemetry-go-contrib/pull/986#issuecomment-941280855) they no longer accept new instrumentation. This is why I maintain this project here.
|
||||
48
vendor/github.com/riandyrn/otelchi/RELEASING.md
generated
vendored
48
vendor/github.com/riandyrn/otelchi/RELEASING.md
generated
vendored
@@ -1,48 +0,0 @@
|
||||
# Release Process
|
||||
|
||||
This document explains how to create releases in this project in each release scenario.
|
||||
|
||||
Currently there are 2 release procedures for this project:
|
||||
|
||||
- [Latest Release](#latest-release)
|
||||
- [Non-Latest Release](#non-latest-release)
|
||||
|
||||
## Latest Release
|
||||
|
||||
This procedure is used when we want to create new release from the latest development edge (latest commit in the `master` branch).
|
||||
|
||||
The steps for this procedure are the following:
|
||||
|
||||
1. Create a new branch from the `master` branch with the following name format: `pre_release/v{MAJOR}.{MINOR}.{BUILD}`. For example, if we want to release for version `0.6.0`, we will first create a new branch from the `master` called `pre_release/v0.6.0`.
|
||||
2. Update method `version.Version()` to return the target version.
|
||||
3. Update the `CHANGELOG.md` to include all the notable changes.
|
||||
4. Create a new PR from this branch to `master` with the title: `Release v{MAJOR}.{MINOR}.{BUILD}` (e.g `Release v0.6.0`).
|
||||
5. At least one maintainer should approve the PR. However if the PR is created by the repo owner, it doesn't need to get approval from other maintainers.
|
||||
6. Upon approval, the PR will be merged to `master` and the branch will be deleted.
|
||||
7. Create new release from the `master` branch.
|
||||
8. Set the title to `Release v{MAJOR}.{MINOR}.{BUILD}` (e.g `Release v0.6.0`).
|
||||
9. Set the newly release tag using this format: `v{MAJOR}.{MINOR}.{BUILD}` (e.g `v0.6.0`).
|
||||
10. Set the description of the release to match with the content inside `CHANGELOG.md`.
|
||||
11. Set the release as the latest release.
|
||||
12. Publish the release.
|
||||
13. Done.
|
||||
|
||||
## Non-Latest Release
|
||||
|
||||
This procedure is used when we need to create fix or patch for the older releases. Consider the following scenario:
|
||||
|
||||
1. For example our latest release is version `0.7.1` which has the minimum go version `1.18`.
|
||||
2. Let say our user got a critical bug in version `0.6.0` which has the minimum go version `1.15`.
|
||||
3. Due to some constraints, this user cannot upgrade his/her minimum go version.
|
||||
4. We decided to create fix for this version by releasing `0.6.1`.
|
||||
|
||||
In this scenario, the procedure is the following:
|
||||
|
||||
1. Create a new branch from the version that we want to patch.
|
||||
2. We name the new branch with the increment in the build value. So for example if we want to create patch for `0.6.0`, then we should create new branch with name: `patch_release/v0.6.1`.
|
||||
3. We create again new branch that will use `patch_release/v0.6.1` as base. Let say `fix/handle-cve-233`.
|
||||
4. We will push any necessary changes to `fix/handle-cve-233`.
|
||||
5. Create a new PR that target `patch_release/v0.6.1`.
|
||||
6. Follow step `2-10` as described in the [Latest Release](#latest-release).
|
||||
7. Publish the release without setting the release as the latest release.
|
||||
8. Done.
|
||||
179
vendor/github.com/riandyrn/otelchi/config.go
generated
vendored
179
vendor/github.com/riandyrn/otelchi/config.go
generated
vendored
@@ -1,179 +0,0 @@
|
||||
package otelchi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// These defaults are used in `TraceHeaderConfig`.
|
||||
const (
|
||||
DefaultTraceIDResponseHeaderKey = "X-Trace-Id"
|
||||
DefaultTraceSampledResponseHeaderKey = "X-Trace-Sampled"
|
||||
)
|
||||
|
||||
// config is used to configure the mux middleware.
|
||||
type config struct {
|
||||
tracerProvider oteltrace.TracerProvider
|
||||
propagators propagation.TextMapPropagator
|
||||
chiRoutes chi.Routes
|
||||
requestMethodInSpanName bool
|
||||
filters []Filter
|
||||
traceIDResponseHeaderKey string
|
||||
traceSampledResponseHeaderKey string
|
||||
publicEndpointFn func(r *http.Request) bool
|
||||
}
|
||||
|
||||
// Option specifies instrumentation configuration options.
|
||||
type Option interface {
|
||||
apply(*config)
|
||||
}
|
||||
|
||||
type optionFunc func(*config)
|
||||
|
||||
func (o optionFunc) apply(c *config) {
|
||||
o(c)
|
||||
}
|
||||
|
||||
// Filter is a predicate used to determine whether a given http.Request should
|
||||
// be traced. A Filter must return true if the request should be traced.
|
||||
type Filter func(*http.Request) bool
|
||||
|
||||
// WithPropagators specifies propagators to use for extracting
|
||||
// information from the HTTP requests. If none are specified, global
|
||||
// ones will be used.
|
||||
func WithPropagators(propagators propagation.TextMapPropagator) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.propagators = propagators
|
||||
})
|
||||
}
|
||||
|
||||
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
|
||||
// If none is specified, the global provider is used.
|
||||
func WithTracerProvider(provider oteltrace.TracerProvider) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.tracerProvider = provider
|
||||
})
|
||||
}
|
||||
|
||||
// WithChiRoutes specified the routes that being used by application. Its main
|
||||
// purpose is to provide route pattern as span name during span creation. If this
|
||||
// option is not set, by default the span will be given name at the end of span
|
||||
// execution. For some people, this behavior is not desirable since they want
|
||||
// to override the span name on underlying handler. By setting this option, it
|
||||
// is possible for them to override the span name.
|
||||
func WithChiRoutes(routes chi.Routes) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.chiRoutes = routes
|
||||
})
|
||||
}
|
||||
|
||||
// WithRequestMethodInSpanName is used for adding http request method to span name.
|
||||
// While this is not necessary for vendors that properly implemented the tracing
|
||||
// specs (e.g Jaeger, AWS X-Ray, etc...), but for other vendors such as Elastic
|
||||
// and New Relic this might be helpful.
|
||||
//
|
||||
// See following threads for details:
|
||||
//
|
||||
// - https://github.com/riandyrn/otelchi/pull/3#issuecomment-1005883910
|
||||
// - https://github.com/riandyrn/otelchi/issues/6#issuecomment-1034461912
|
||||
func WithRequestMethodInSpanName(isActive bool) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.requestMethodInSpanName = isActive
|
||||
})
|
||||
}
|
||||
|
||||
// WithFilter adds a filter to the list of filters used by the handler.
|
||||
// If any filter indicates to exclude a request then the request will not be
|
||||
// traced. All filters must allow a request to be traced for a Span to be created.
|
||||
// If no filters are provided then all requests are traced.
|
||||
// Filters will be invoked for each processed request, it is advised to make them
|
||||
// simple and fast.
|
||||
func WithFilter(filter Filter) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.filters = append(cfg.filters, filter)
|
||||
})
|
||||
}
|
||||
|
||||
// WithTraceIDResponseHeader enables adding trace id into response header.
|
||||
// It accepts a function that generates the header key name. If this parameter
|
||||
// function set to `nil` the default header key which is `X-Trace-Id` will be used.
|
||||
//
|
||||
// Deprecated: use `WithTraceResponseHeaders` instead.
|
||||
func WithTraceIDResponseHeader(headerKeyFunc func() string) Option {
|
||||
cfg := TraceHeaderConfig{
|
||||
TraceIDHeader: "",
|
||||
TraceSampledHeader: "",
|
||||
}
|
||||
if headerKeyFunc != nil {
|
||||
cfg.TraceIDHeader = headerKeyFunc()
|
||||
}
|
||||
return WithTraceResponseHeaders(cfg)
|
||||
}
|
||||
|
||||
// TraceHeaderConfig is configuration for trace headers in the response.
|
||||
type TraceHeaderConfig struct {
|
||||
TraceIDHeader string // if non-empty overrides the default of X-Trace-ID
|
||||
TraceSampledHeader string // if non-empty overrides the default of X-Trace-Sampled
|
||||
}
|
||||
|
||||
// WithTraceResponseHeaders configures the response headers for trace information.
|
||||
// It accepts a TraceHeaderConfig struct that contains the keys for the Trace ID
|
||||
// and Trace Sampled headers. If the provided keys are empty, default values will
|
||||
// be used for the respective headers.
|
||||
func WithTraceResponseHeaders(cfg TraceHeaderConfig) Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.traceIDResponseHeaderKey = cfg.TraceIDHeader
|
||||
if c.traceIDResponseHeaderKey == "" {
|
||||
c.traceIDResponseHeaderKey = DefaultTraceIDResponseHeaderKey
|
||||
}
|
||||
|
||||
c.traceSampledResponseHeaderKey = cfg.TraceSampledHeader
|
||||
if c.traceSampledResponseHeaderKey == "" {
|
||||
c.traceSampledResponseHeaderKey = DefaultTraceSampledResponseHeaderKey
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithPublicEndpoint is used for marking every endpoint as public endpoint.
|
||||
// This means if the incoming request has span context, it won't be used as
|
||||
// parent span by the span generated by this middleware, instead the generated
|
||||
// span will be the root span (new trace) and then linked to the span from the
|
||||
// incoming request.
|
||||
//
|
||||
// Let say we have the following scenario:
|
||||
//
|
||||
// 1. We have 2 systems: `SysA` & `SysB`.
|
||||
// 2. `SysA` has the following services: `SvcA.1` & `SvcA.2`.
|
||||
// 3. `SysB` has the following services: `SvcB.1` & `SvcB.2`.
|
||||
// 4. `SvcA.2` is used internally only by `SvcA.1`.
|
||||
// 5. `SvcB.2` is used internally only by `SvcB.1`.
|
||||
// 6. All of these services already instrumented otelchi & using the same collector (e.g Jaeger).
|
||||
// 7. In `SvcA.1` we should set `WithPublicEndpoint()` since it is the entry point (a.k.a "public endpoint") for entering `SysA`.
|
||||
// 8. In `SvcA.2` we should not set `WithPublicEndpoint()` since it is only used internally by `SvcA.1` inside `SysA`.
|
||||
// 9. Point 7 & 8 also applies to both services in `SysB`.
|
||||
//
|
||||
// Now, whenever `SvcA.1` calls `SvcA.2` there will be only a single trace generated. This trace will contain 2 spans: root span from `SvcA.1` & child span from `SvcA.2`.
|
||||
//
|
||||
// But if let say `SvcA.2` calls `SvcB.1`, then there will be 2 traces generated: trace from `SysA` & trace from `SysB`. But in trace generated in `SysB` there will be like a marking that this trace is actually related to trace in `SysA` (a.k.a linked with the trace from `SysA`).
|
||||
func WithPublicEndpoint() Option {
|
||||
return WithPublicEndpointFn(func(r *http.Request) bool { return true })
|
||||
}
|
||||
|
||||
// WithPublicEndpointFn runs with every request, and allows conditionally
|
||||
// configuring the Handler to link the generated span with an incoming span
|
||||
// context.
|
||||
//
|
||||
// If the function return `true` the generated span will be linked with the
|
||||
// incoming span context. Otherwise, the generated span will be set as the
|
||||
// child span of the incoming span context.
|
||||
//
|
||||
// Essentially it has the same functionality as `WithPublicEndpoint` but with
|
||||
// more flexibility.
|
||||
func WithPublicEndpointFn(fn func(r *http.Request) bool) Option {
|
||||
return optionFunc(func(cfg *config) {
|
||||
cfg.publicEndpointFn = fn
|
||||
})
|
||||
}
|
||||
236
vendor/github.com/riandyrn/otelchi/middleware.go
generated
vendored
236
vendor/github.com/riandyrn/otelchi/middleware.go
generated
vendored
@@ -1,236 +0,0 @@
|
||||
package otelchi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/felixge/httpsnoop"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/riandyrn/otelchi/version"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.20.0/httpconv"
|
||||
oteltrace "go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
tracerName = "github.com/riandyrn/otelchi"
|
||||
)
|
||||
|
||||
// Middleware sets up a handler to start tracing the incoming
|
||||
// requests. The serverName parameter should describe the name of the
|
||||
// (virtual) server handling the request.
|
||||
func Middleware(serverName string, opts ...Option) func(next http.Handler) http.Handler {
|
||||
cfg := config{}
|
||||
for _, opt := range opts {
|
||||
opt.apply(&cfg)
|
||||
}
|
||||
if cfg.tracerProvider == nil {
|
||||
cfg.tracerProvider = otel.GetTracerProvider()
|
||||
}
|
||||
tracer := cfg.tracerProvider.Tracer(
|
||||
tracerName,
|
||||
oteltrace.WithInstrumentationVersion(version.Version()),
|
||||
)
|
||||
if cfg.propagators == nil {
|
||||
cfg.propagators = otel.GetTextMapPropagator()
|
||||
}
|
||||
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return traceware{
|
||||
config: cfg,
|
||||
serverName: serverName,
|
||||
tracer: tracer,
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type traceware struct {
|
||||
config
|
||||
serverName string
|
||||
tracer oteltrace.Tracer
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
type recordingResponseWriter struct {
|
||||
writer http.ResponseWriter
|
||||
written bool
|
||||
status int
|
||||
}
|
||||
|
||||
var rrwPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &recordingResponseWriter{}
|
||||
},
|
||||
}
|
||||
|
||||
func getRRW(writer http.ResponseWriter) *recordingResponseWriter {
|
||||
rrw := rrwPool.Get().(*recordingResponseWriter)
|
||||
rrw.written = false
|
||||
rrw.status = http.StatusOK
|
||||
rrw.writer = httpsnoop.Wrap(writer, httpsnoop.Hooks{
|
||||
Write: func(next httpsnoop.WriteFunc) httpsnoop.WriteFunc {
|
||||
return func(b []byte) (int, error) {
|
||||
if !rrw.written {
|
||||
rrw.written = true
|
||||
}
|
||||
return next(b)
|
||||
}
|
||||
},
|
||||
WriteHeader: func(next httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc {
|
||||
return func(statusCode int) {
|
||||
if !rrw.written {
|
||||
rrw.written = true
|
||||
rrw.status = statusCode
|
||||
// only call next WriteHeader when header is not written yet
|
||||
// this is to prevent superfluous WriteHeader call
|
||||
next(statusCode)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
return rrw
|
||||
}
|
||||
|
||||
func putRRW(rrw *recordingResponseWriter) {
|
||||
rrw.writer = nil
|
||||
rrwPool.Put(rrw)
|
||||
}
|
||||
|
||||
// ServeHTTP implements the http.Handler interface. It does the actual
|
||||
// tracing of the request.
|
||||
func (tw traceware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// go through all filters if any
|
||||
for _, filter := range tw.filters {
|
||||
// if there is a filter that returns false, we skip tracing
|
||||
// and execute next handler
|
||||
if !filter(r) {
|
||||
tw.handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// extract tracing header using propagator
|
||||
ctx := tw.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
// create span, based on specification, we need to set already known attributes
|
||||
// when creating the span, the only thing missing here is HTTP route pattern since
|
||||
// in go-chi/chi route pattern could only be extracted once the request is executed
|
||||
// check here for details:
|
||||
//
|
||||
// https://github.com/go-chi/chi/issues/150#issuecomment-278850733
|
||||
//
|
||||
// if we have access to chi routes, we could extract the route pattern beforehand.
|
||||
spanName := ""
|
||||
routePattern := ""
|
||||
spanAttributes := httpconv.ServerRequest(tw.serverName, r)
|
||||
|
||||
if tw.chiRoutes != nil {
|
||||
rctx := chi.NewRouteContext()
|
||||
if tw.chiRoutes.Match(rctx, r.Method, r.URL.Path) {
|
||||
routePattern = rctx.RoutePattern()
|
||||
spanName = addPrefixToSpanName(tw.requestMethodInSpanName, r.Method, routePattern)
|
||||
spanAttributes = append(spanAttributes, semconv.HTTPRoute(routePattern))
|
||||
}
|
||||
}
|
||||
|
||||
// define span start options
|
||||
spanOpts := []oteltrace.SpanStartOption{
|
||||
oteltrace.WithAttributes(spanAttributes...),
|
||||
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
|
||||
}
|
||||
|
||||
if tw.publicEndpointFn != nil && tw.publicEndpointFn(r) {
|
||||
// mark span as the root span
|
||||
spanOpts = append(spanOpts, oteltrace.WithNewRoot())
|
||||
|
||||
// linking incoming span context to the root span, we need to
|
||||
// ensure if the incoming span context is valid (because it is
|
||||
// possible for us to receive invalid span context due to various
|
||||
// reason such as bug or context propagation error) and it is
|
||||
// coming from another service (remote) before linking it to the
|
||||
// root span
|
||||
spanCtx := oteltrace.SpanContextFromContext(ctx)
|
||||
if spanCtx.IsValid() && spanCtx.IsRemote() {
|
||||
spanOpts = append(
|
||||
spanOpts,
|
||||
oteltrace.WithLinks(oteltrace.Link{
|
||||
SpanContext: spanCtx,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// start span
|
||||
ctx, span := tw.tracer.Start(ctx, spanName, spanOpts...)
|
||||
defer span.End()
|
||||
|
||||
// put trace_id to response header only when `WithTraceIDResponseHeader` is used
|
||||
if len(tw.traceIDResponseHeaderKey) > 0 && span.SpanContext().HasTraceID() {
|
||||
w.Header().Add(tw.traceIDResponseHeaderKey, span.SpanContext().TraceID().String())
|
||||
w.Header().Add(tw.traceSampledResponseHeaderKey, strconv.FormatBool(span.SpanContext().IsSampled()))
|
||||
}
|
||||
|
||||
// get recording response writer
|
||||
rrw := getRRW(w)
|
||||
defer putRRW(rrw)
|
||||
|
||||
// execute next http handler
|
||||
r = r.WithContext(ctx)
|
||||
tw.handler.ServeHTTP(rrw.writer, r)
|
||||
|
||||
// set span name & http route attribute if route pattern cannot be determined
|
||||
// during span creation
|
||||
if len(routePattern) == 0 {
|
||||
routePattern = chi.RouteContext(r.Context()).RoutePattern()
|
||||
span.SetAttributes(semconv.HTTPRoute(routePattern))
|
||||
|
||||
spanName = addPrefixToSpanName(tw.requestMethodInSpanName, r.Method, routePattern)
|
||||
span.SetName(spanName)
|
||||
}
|
||||
|
||||
// check if the request is a WebSocket upgrade request
|
||||
if isWebSocketRequest(r) {
|
||||
span.SetStatus(codes.Unset, "WebSocket upgrade request")
|
||||
return
|
||||
}
|
||||
|
||||
// set status code attribute
|
||||
span.SetAttributes(semconv.HTTPStatusCode(rrw.status))
|
||||
|
||||
// set span status
|
||||
span.SetStatus(httpconv.ServerStatus(rrw.status))
|
||||
}
|
||||
|
||||
func addPrefixToSpanName(shouldAdd bool, prefix, spanName string) string {
|
||||
// in chi v5.0.8, the root route will be returned has an empty string
|
||||
// (see https://github.com/go-chi/chi/blob/v5.0.8/context.go#L126)
|
||||
if spanName == "" {
|
||||
spanName = "/"
|
||||
}
|
||||
|
||||
if shouldAdd && len(spanName) > 0 {
|
||||
spanName = prefix + " " + spanName
|
||||
}
|
||||
return spanName
|
||||
}
|
||||
|
||||
// isWebSocketRequest checks if an HTTP request is a WebSocket upgrade request
|
||||
// Fix: https://github.com/riandyrn/otelchi/issues/66
|
||||
func isWebSocketRequest(r *http.Request) bool {
|
||||
// Check if the Connection header contains "Upgrade"
|
||||
connectionHeader := r.Header.Get("Connection")
|
||||
if !strings.Contains(strings.ToLower(connectionHeader), "upgrade") {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the Upgrade header is "websocket"
|
||||
upgradeHeader := r.Header.Get("Upgrade")
|
||||
return strings.ToLower(upgradeHeader) == "websocket"
|
||||
}
|
||||
6
vendor/github.com/riandyrn/otelchi/version/version.go
generated
vendored
6
vendor/github.com/riandyrn/otelchi/version/version.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
package version
|
||||
|
||||
// Version is the current release version of otelchi in use.
|
||||
func Version() string {
|
||||
return "0.12.1"
|
||||
}
|
||||
395
vendor/go.opentelemetry.io/otel/semconv/internal/v4/http.go
generated
vendored
395
vendor/go.opentelemetry.io/otel/semconv/internal/v4/http.go
generated
vendored
@@ -1,395 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package internal provides common semconv functionality.
|
||||
package internal // import "go.opentelemetry.io/otel/semconv/internal/v4"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
)
|
||||
|
||||
// HTTPConv are the HTTP semantic convention attributes defined for a version
|
||||
// of the OpenTelemetry specification.
|
||||
type HTTPConv struct {
|
||||
NetConv *NetConv
|
||||
|
||||
EnduserIDKey attribute.Key
|
||||
HTTPClientIPKey attribute.Key
|
||||
NetProtocolNameKey attribute.Key
|
||||
NetProtocolVersionKey attribute.Key
|
||||
HTTPMethodKey attribute.Key
|
||||
HTTPRequestContentLengthKey attribute.Key
|
||||
HTTPResponseContentLengthKey attribute.Key
|
||||
HTTPRouteKey attribute.Key
|
||||
HTTPSchemeHTTP attribute.KeyValue
|
||||
HTTPSchemeHTTPS attribute.KeyValue
|
||||
HTTPStatusCodeKey attribute.Key
|
||||
HTTPTargetKey attribute.Key
|
||||
HTTPURLKey attribute.Key
|
||||
UserAgentOriginalKey attribute.Key
|
||||
}
|
||||
|
||||
// ClientResponse returns attributes for an HTTP response received by a client
|
||||
// from a server. The following attributes are returned if the related values
|
||||
// are defined in resp: "http.status.code", "http.response_content_length".
|
||||
//
|
||||
// This does not add all OpenTelemetry required attributes for an HTTP event,
|
||||
// it assumes ClientRequest was used to create the span with a complete set of
|
||||
// attributes. If a complete set of attributes can be generated using the
|
||||
// request contained in resp. For example:
|
||||
//
|
||||
// append(ClientResponse(resp), ClientRequest(resp.Request)...)
|
||||
func (c *HTTPConv) ClientResponse(resp *http.Response) []attribute.KeyValue {
|
||||
var n int
|
||||
if resp.StatusCode > 0 {
|
||||
n++
|
||||
}
|
||||
if resp.ContentLength > 0 {
|
||||
n++
|
||||
}
|
||||
|
||||
attrs := make([]attribute.KeyValue, 0, n)
|
||||
if resp.StatusCode > 0 {
|
||||
attrs = append(attrs, c.HTTPStatusCodeKey.Int(resp.StatusCode))
|
||||
}
|
||||
if resp.ContentLength > 0 {
|
||||
attrs = append(attrs, c.HTTPResponseContentLengthKey.Int(int(resp.ContentLength)))
|
||||
}
|
||||
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".
|
||||
func (c *HTTPConv) ClientRequest(req *http.Request) []attribute.KeyValue {
|
||||
n := 3 // URL, peer name, proto, and method.
|
||||
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++
|
||||
}
|
||||
useragent := req.UserAgent()
|
||||
if useragent != "" {
|
||||
n++
|
||||
}
|
||||
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.proto(req.Proto))
|
||||
|
||||
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, c.HTTPURLKey.String(u))
|
||||
|
||||
attrs = append(attrs, c.NetConv.PeerName(peer))
|
||||
if port > 0 {
|
||||
attrs = append(attrs, c.NetConv.PeerPort(port))
|
||||
}
|
||||
|
||||
if 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
|
||||
}
|
||||
|
||||
// ServerRequest returns 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.
|
||||
//
|
||||
// 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".
|
||||
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.
|
||||
|
||||
n := 4 // Method, scheme, proto, and host name.
|
||||
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 {
|
||||
n++
|
||||
}
|
||||
peer, peerPort := splitHostPort(req.RemoteAddr)
|
||||
if peer != "" {
|
||||
n++
|
||||
if peerPort > 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
useragent := req.UserAgent()
|
||||
if useragent != "" {
|
||||
n++
|
||||
}
|
||||
userID, _, hasUserID := req.BasicAuth()
|
||||
if hasUserID {
|
||||
n++
|
||||
}
|
||||
clientIP := serverClientIP(req.Header.Get("X-Forwarded-For"))
|
||||
if clientIP != "" {
|
||||
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.proto(req.Proto))
|
||||
attrs = append(attrs, c.NetConv.HostName(host))
|
||||
|
||||
if hostPort > 0 {
|
||||
attrs = append(attrs, c.NetConv.HostPort(hostPort))
|
||||
}
|
||||
|
||||
if 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, c.NetConv.SockPeerAddr(peer))
|
||||
if peerPort > 0 {
|
||||
attrs = append(attrs, c.NetConv.SockPeerPort(peerPort))
|
||||
}
|
||||
}
|
||||
|
||||
if useragent != "" {
|
||||
attrs = append(attrs, c.UserAgentOriginalKey.String(useragent))
|
||||
}
|
||||
|
||||
if hasUserID {
|
||||
attrs = append(attrs, c.EnduserIDKey.String(userID))
|
||||
}
|
||||
|
||||
if clientIP != "" {
|
||||
attrs = append(attrs, c.HTTPClientIPKey.String(clientIP))
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
||||
|
||||
func (c *HTTPConv) method(method string) attribute.KeyValue {
|
||||
if method == "" {
|
||||
return c.HTTPMethodKey.String(http.MethodGet)
|
||||
}
|
||||
return c.HTTPMethodKey.String(method)
|
||||
}
|
||||
|
||||
func (c *HTTPConv) scheme(https bool) attribute.KeyValue { // nolint:revive
|
||||
if https {
|
||||
return c.HTTPSchemeHTTPS
|
||||
}
|
||||
return c.HTTPSchemeHTTP
|
||||
}
|
||||
|
||||
func (c *HTTPConv) proto(proto string) attribute.KeyValue {
|
||||
switch proto {
|
||||
case "HTTP/1.0":
|
||||
return c.NetProtocolVersionKey.String("1.0")
|
||||
case "HTTP/1.1":
|
||||
return c.NetProtocolVersionKey.String("1.1")
|
||||
case "HTTP/2":
|
||||
return c.NetProtocolVersionKey.String("2.0")
|
||||
case "HTTP/3":
|
||||
return c.NetProtocolVersionKey.String("3.0")
|
||||
default:
|
||||
return c.NetProtocolNameKey.String(proto)
|
||||
}
|
||||
}
|
||||
|
||||
func serverClientIP(xForwardedFor string) string {
|
||||
if idx := strings.Index(xForwardedFor, ","); idx >= 0 {
|
||||
xForwardedFor = xForwardedFor[:idx]
|
||||
}
|
||||
return xForwardedFor
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Return the request host and port from the first non-empty source.
|
||||
func firstHostPort(source ...string) (host string, port int) {
|
||||
for _, hostport := range source {
|
||||
host, port = splitHostPort(hostport)
|
||||
if host != "" || port > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
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
|
||||
// value received by a client.
|
||||
func (c *HTTPConv) ClientStatus(code int) (codes.Code, string) {
|
||||
stat, valid := validateHTTPStatusCode(code)
|
||||
if !valid {
|
||||
return stat, fmt.Sprintf("Invalid HTTP status code %d", code)
|
||||
}
|
||||
return stat, ""
|
||||
}
|
||||
|
||||
// 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 (c *HTTPConv) ServerStatus(code int) (codes.Code, string) {
|
||||
stat, valid := validateHTTPStatusCode(code)
|
||||
if !valid {
|
||||
return stat, fmt.Sprintf("Invalid HTTP status code %d", code)
|
||||
}
|
||||
|
||||
if code/100 == 4 {
|
||||
return codes.Unset, ""
|
||||
}
|
||||
return stat, ""
|
||||
}
|
||||
|
||||
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},
|
||||
},
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
313
vendor/go.opentelemetry.io/otel/semconv/internal/v4/net.go
generated
vendored
313
vendor/go.opentelemetry.io/otel/semconv/internal/v4/net.go
generated
vendored
@@ -1,313 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package internal // import "go.opentelemetry.io/otel/semconv/internal/v4"
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// NetConv are the network semantic convention attributes defined for a version
|
||||
// of the OpenTelemetry specification.
|
||||
type NetConv struct {
|
||||
NetHostNameKey attribute.Key
|
||||
NetHostPortKey attribute.Key
|
||||
NetPeerNameKey attribute.Key
|
||||
NetPeerPortKey attribute.Key
|
||||
NetSockFamilyKey attribute.Key
|
||||
NetSockPeerAddrKey attribute.Key
|
||||
NetSockPeerPortKey attribute.Key
|
||||
NetSockHostAddrKey attribute.Key
|
||||
NetSockHostPortKey attribute.Key
|
||||
NetTransportOther attribute.KeyValue
|
||||
NetTransportTCP attribute.KeyValue
|
||||
NetTransportUDP attribute.KeyValue
|
||||
NetTransportInProc attribute.KeyValue
|
||||
}
|
||||
|
||||
func (c *NetConv) Transport(network string) attribute.KeyValue {
|
||||
switch network {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
return c.NetTransportTCP
|
||||
case "udp", "udp4", "udp6":
|
||||
return c.NetTransportUDP
|
||||
case "unix", "unixgram", "unixpacket":
|
||||
return c.NetTransportInProc
|
||||
default:
|
||||
// "ip:*", "ip4:*", and "ip6:*" all are considered other.
|
||||
return c.NetTransportOther
|
||||
}
|
||||
}
|
||||
|
||||
// Host returns attributes for a network host address.
|
||||
func (c *NetConv) Host(address string) []attribute.KeyValue {
|
||||
h, p := splitHostPort(address)
|
||||
var n int
|
||||
if h != "" {
|
||||
n++
|
||||
if p > 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
attrs := make([]attribute.KeyValue, 0, n)
|
||||
attrs = append(attrs, c.HostName(h))
|
||||
if p > 0 {
|
||||
attrs = append(attrs, c.HostPort(p))
|
||||
}
|
||||
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 {
|
||||
return c.NetHostNameKey.String(name)
|
||||
}
|
||||
|
||||
func (c *NetConv) HostPort(port int) attribute.KeyValue {
|
||||
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 {
|
||||
switch network {
|
||||
case "unix", "unixgram", "unixpacket":
|
||||
return "unix"
|
||||
default:
|
||||
if ip := net.ParseIP(address); ip != nil {
|
||||
if ip.To4() == nil {
|
||||
return "inet6"
|
||||
}
|
||||
return "inet"
|
||||
}
|
||||
}
|
||||
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.
|
||||
func (c *NetConv) Peer(address string) []attribute.KeyValue {
|
||||
h, p := splitHostPort(address)
|
||||
var n int
|
||||
if h != "" {
|
||||
n++
|
||||
if p > 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
attrs := make([]attribute.KeyValue, 0, n)
|
||||
attrs = append(attrs, c.PeerName(h))
|
||||
if p > 0 {
|
||||
attrs = append(attrs, c.PeerPort(p))
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func (c *NetConv) PeerName(name string) attribute.KeyValue {
|
||||
return c.NetPeerNameKey.String(name)
|
||||
}
|
||||
|
||||
func (c *NetConv) PeerPort(port int) attribute.KeyValue {
|
||||
return c.NetPeerPortKey.Int(port)
|
||||
}
|
||||
|
||||
func (c *NetConv) SockPeerAddr(addr string) attribute.KeyValue {
|
||||
return c.NetSockPeerAddrKey.String(addr)
|
||||
}
|
||||
|
||||
func (c *NetConv) SockPeerPort(port int) attribute.KeyValue {
|
||||
return c.NetSockPeerPortKey.Int(port)
|
||||
}
|
||||
|
||||
// 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) // nolint: gosec // Bit size of 16 checked above.
|
||||
}
|
||||
3
vendor/go.opentelemetry.io/otel/semconv/v1.20.0/httpconv/README.md
generated
vendored
3
vendor/go.opentelemetry.io/otel/semconv/v1.20.0/httpconv/README.md
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Semconv v1.20.0 HTTP conv
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.20.0/httpconv)
|
||||
143
vendor/go.opentelemetry.io/otel/semconv/v1.20.0/httpconv/http.go
generated
vendored
143
vendor/go.opentelemetry.io/otel/semconv/v1.20.0/httpconv/http.go
generated
vendored
@@ -1,143 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package httpconv provides OpenTelemetry HTTP semantic conventions for
|
||||
// tracing telemetry.
|
||||
package httpconv // import "go.opentelemetry.io/otel/semconv/v1.20.0/httpconv"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/semconv/internal/v4"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
)
|
||||
|
||||
var (
|
||||
nc = &internal.NetConv{
|
||||
NetHostNameKey: semconv.NetHostNameKey,
|
||||
NetHostPortKey: semconv.NetHostPortKey,
|
||||
NetPeerNameKey: semconv.NetPeerNameKey,
|
||||
NetPeerPortKey: semconv.NetPeerPortKey,
|
||||
NetSockPeerAddrKey: semconv.NetSockPeerAddrKey,
|
||||
NetSockPeerPortKey: semconv.NetSockPeerPortKey,
|
||||
NetTransportOther: semconv.NetTransportOther,
|
||||
NetTransportTCP: semconv.NetTransportTCP,
|
||||
NetTransportUDP: semconv.NetTransportUDP,
|
||||
NetTransportInProc: semconv.NetTransportInProc,
|
||||
}
|
||||
|
||||
hc = &internal.HTTPConv{
|
||||
NetConv: nc,
|
||||
|
||||
EnduserIDKey: semconv.EnduserIDKey,
|
||||
HTTPClientIPKey: semconv.HTTPClientIPKey,
|
||||
NetProtocolNameKey: semconv.NetProtocolNameKey,
|
||||
NetProtocolVersionKey: semconv.NetProtocolVersionKey,
|
||||
HTTPMethodKey: semconv.HTTPMethodKey,
|
||||
HTTPRequestContentLengthKey: semconv.HTTPRequestContentLengthKey,
|
||||
HTTPResponseContentLengthKey: semconv.HTTPResponseContentLengthKey,
|
||||
HTTPRouteKey: semconv.HTTPRouteKey,
|
||||
HTTPSchemeHTTP: semconv.HTTPSchemeHTTP,
|
||||
HTTPSchemeHTTPS: semconv.HTTPSchemeHTTPS,
|
||||
HTTPStatusCodeKey: semconv.HTTPStatusCodeKey,
|
||||
HTTPTargetKey: semconv.HTTPTargetKey,
|
||||
HTTPURLKey: semconv.HTTPURLKey,
|
||||
UserAgentOriginalKey: semconv.UserAgentOriginalKey,
|
||||
}
|
||||
)
|
||||
|
||||
// ClientResponse returns trace attributes for an HTTP response received by a
|
||||
// client from a server. It will return the following attributes if the related
|
||||
// values are defined in resp: "http.status.code",
|
||||
// "http.response_content_length".
|
||||
//
|
||||
// This does not add all OpenTelemetry required attributes for an HTTP event,
|
||||
// it assumes ClientRequest was used to create the span with a complete set of
|
||||
// attributes. If a complete set of attributes can be generated using the
|
||||
// request contained in resp. For example:
|
||||
//
|
||||
// append(ClientResponse(resp), ClientRequest(resp.Request)...)
|
||||
func ClientResponse(resp *http.Response) []attribute.KeyValue {
|
||||
return hc.ClientResponse(resp)
|
||||
}
|
||||
|
||||
// ClientRequest returns trace attributes for an HTTP request made by a client.
|
||||
// The following attributes are always returned: "http.url",
|
||||
// "net.protocol.(name|version)", "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".
|
||||
func ClientRequest(req *http.Request) []attribute.KeyValue {
|
||||
return hc.ClientRequest(req)
|
||||
}
|
||||
|
||||
// ClientStatus returns a span status code and message for an HTTP status code
|
||||
// value received by a client.
|
||||
func ClientStatus(code int) (codes.Code, string) {
|
||||
return hc.ClientStatus(code)
|
||||
}
|
||||
|
||||
// ServerRequest 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.
|
||||
//
|
||||
// The following attributes are always returned: "http.method", "http.scheme",
|
||||
// ""net.protocol.(name|version)", "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", "enduser.id", "http.client_ip".
|
||||
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
|
||||
return hc.ServerRequest(server, req)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return hc.ServerStatus(code)
|
||||
}
|
||||
|
||||
// RequestHeader 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 user_agent.original 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 RequestHeader(h http.Header) []attribute.KeyValue {
|
||||
return hc.RequestHeader(h)
|
||||
}
|
||||
|
||||
// ResponseHeader 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 user_agent.original 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 ResponseHeader(h http.Header) []attribute.KeyValue {
|
||||
return hc.ResponseHeader(h)
|
||||
}
|
||||
6
vendor/modules.txt
vendored
6
vendor/modules.txt
vendored
@@ -1674,10 +1674,6 @@ github.com/r3labs/sse/v2
|
||||
# github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9
|
||||
## explicit
|
||||
github.com/rcrowley/go-metrics
|
||||
# github.com/riandyrn/otelchi v0.12.1
|
||||
## explicit; go 1.22.0
|
||||
github.com/riandyrn/otelchi
|
||||
github.com/riandyrn/otelchi/version
|
||||
# github.com/rivo/uniseg v0.4.7
|
||||
## explicit; go 1.18
|
||||
github.com/rivo/uniseg
|
||||
@@ -2045,10 +2041,8 @@ go.opentelemetry.io/otel/internal/baggage
|
||||
go.opentelemetry.io/otel/internal/global
|
||||
go.opentelemetry.io/otel/propagation
|
||||
go.opentelemetry.io/otel/semconv/internal
|
||||
go.opentelemetry.io/otel/semconv/internal/v4
|
||||
go.opentelemetry.io/otel/semconv/v1.10.0
|
||||
go.opentelemetry.io/otel/semconv/v1.20.0
|
||||
go.opentelemetry.io/otel/semconv/v1.20.0/httpconv
|
||||
go.opentelemetry.io/otel/semconv/v1.21.0
|
||||
go.opentelemetry.io/otel/semconv/v1.26.0
|
||||
go.opentelemetry.io/otel/semconv/v1.34.0
|
||||
|
||||
Reference in New Issue
Block a user