mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved We run multiple deployments (regions) under a single GCP project. Within these deployments we scale containers. Currently all metrics target the same time series in GCP, regardless or region or container. All metics ended up in `generic_node` and Cloud Monitoring rejects the duplicate and out-of-order points. This can be fixed by setting vendor specific attributes such as `faas.name` (K_SERVICE), `faas.version` (K_REVISION), `faas.instance` (instance id from the metadata server), and `cloud.region` (metadata instance/region). # How the Problems Are Solved Use `go.opentelemetry.io/contrib/detectors/gcp` to auto-detect values as mentioned above. A new `Instrumentation.Detectors` config entry is added, which accepts and array of enum for detecotrs. At the moment only Google is accepted, other entries from [contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/detectors) can be added if deemed usefull. I've considered using `autodetect` contrib package, identifiers and constructor, but this pulls in the full AWS SDK, increasing zitadel's binary size by 50MiB. By default detection is switched off, as it relies on unauthenticated link-local calls that are insecure anywhere outside of the infrastructure it targets. It also prevents breaking existing deployments that rely on detection being off already. (May break existing trace and logging pipelines). # Additional Changes - none # Additional Context - (internal only): https://github.com/caos/infra/pull/1813 --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: Claude Opus 5 <[email protected]>
86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
// Package instrumentation initializes and configures telemetry and logging instrumentation.
|
|
// After [Start] is called, the instrumentation providers can be accessed using global getters.
|
|
package instrumentation
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
|
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/metric"
|
|
"go.opentelemetry.io/otel/sdk/log"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
const Name = "zitadel/backend/v3/instrumentation/tracing"
|
|
|
|
type Config struct {
|
|
ServiceName string
|
|
// Detectors enrich the resource of every exported signal with attributes
|
|
// describing the platform we run on. Empty by default.
|
|
Detectors []DetectorType
|
|
Trace TraceConfig
|
|
Metric MetricConfig
|
|
Log LogConfig
|
|
Profile ProfileConfig
|
|
}
|
|
|
|
type ShutdownFunc func(context.Context) error
|
|
|
|
var (
|
|
startOnce sync.Once
|
|
shutdown ShutdownFunc
|
|
errStart error
|
|
)
|
|
|
|
// Start initializes global instrumentation once, based on the provided configuration.
|
|
// It is safe to call multiple times; subsequent calls will return the same shutdown function and error as the first call.
|
|
func Start(ctx context.Context, cfg Config) (ShutdownFunc, error) {
|
|
startOnce.Do(func() {
|
|
errStart = startProfiler(cfg.Profile, cfg.ServiceName)
|
|
if errStart != nil {
|
|
return
|
|
}
|
|
var logProvider *log.LoggerProvider
|
|
logProvider, shutdown, errStart = setupOTelSDK(ctx, cfg)
|
|
if errStart != nil {
|
|
return
|
|
}
|
|
setLogger(logProvider, cfg.Log)
|
|
})
|
|
return shutdown, errStart
|
|
}
|
|
|
|
// NewTracer creates a new tracer from the global provider.
|
|
// See [trace.TracerProvider.Tracer] for details.
|
|
func NewTracer(name string, options ...trace.TracerOption) *Tracer {
|
|
provider := otel.GetTracerProvider()
|
|
return &Tracer{provider.Tracer(name, options...)}
|
|
}
|
|
|
|
// NewMeter creates a new meter from the global provider.
|
|
// See [metric.MeterProvider.Meter] for details.
|
|
func NewMeter(name string, options ...metric.MeterOption) *Meter {
|
|
provider := otel.GetMeterProvider()
|
|
return &Meter{
|
|
Meter: provider.Meter(name, options...),
|
|
}
|
|
}
|
|
|
|
// RequestFilter returns an [otelhttp.Filter] that excludes requests
|
|
// with paths starting with any of the specified prefixes.
|
|
func RequestFilter(ignoredPrefix ...string) otelhttp.Filter {
|
|
return func(r *http.Request) bool {
|
|
return !slices.ContainsFunc(
|
|
ignoredPrefix,
|
|
func(endpoint string) bool {
|
|
return strings.HasPrefix(r.URL.RequestURI(), endpoint)
|
|
},
|
|
)
|
|
}
|
|
}
|