mirror of
https://github.com/zitadel/zitadel.git
synced 2025-06-07 20:58:33 +00:00

# Which Problems Are Solved The service name is hardcoded in the metrics code. Making the service name to be configurable helps when running multiple instances of Zitadel. The defaults remain unchanged, the service name will be defaulted to ZITADEL. # How the Problems Are Solved Add a config option to override the name in defaults.yaml and pass it down to the corresponding metrics or tracing module (google or otel) # Additional Changes NA # Additional Context NA (cherry picked from commit dc64e35128108d70471c7a5b9ad1dfc2c7c4c654)
128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package otel
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/exporters/prometheus"
|
|
"go.opentelemetry.io/otel/metric"
|
|
"go.opentelemetry.io/otel/sdk/instrumentation"
|
|
sdk_metric "go.opentelemetry.io/otel/sdk/metric"
|
|
|
|
"github.com/zitadel/zitadel/internal/telemetry/metrics"
|
|
otel_resource "github.com/zitadel/zitadel/internal/telemetry/otel"
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
type Metrics struct {
|
|
Provider metric.MeterProvider
|
|
Meter metric.Meter
|
|
Counters sync.Map
|
|
UpDownSumObserver sync.Map
|
|
ValueObservers sync.Map
|
|
}
|
|
|
|
func NewMetrics(meterName string) (metrics.Metrics, error) {
|
|
resource, err := otel_resource.ResourceWithService("ZITADEL")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
exporter, err := prometheus.New()
|
|
if err != nil {
|
|
return &Metrics{}, err
|
|
}
|
|
// create a view to filter out unwanted attributes
|
|
view := sdk_metric.NewView(
|
|
sdk_metric.Instrument{
|
|
Scope: instrumentation.Scope{Name: otelhttp.ScopeName},
|
|
},
|
|
sdk_metric.Stream{
|
|
AttributeFilter: attribute.NewAllowKeysFilter("http.method", "http.status_code", "http.target"),
|
|
},
|
|
)
|
|
meterProvider := sdk_metric.NewMeterProvider(
|
|
sdk_metric.WithReader(exporter),
|
|
sdk_metric.WithResource(resource),
|
|
sdk_metric.WithView(view),
|
|
)
|
|
return &Metrics{
|
|
Provider: meterProvider,
|
|
Meter: meterProvider.Meter(meterName),
|
|
}, nil
|
|
}
|
|
|
|
func (m *Metrics) GetExporter() http.Handler {
|
|
return promhttp.Handler()
|
|
}
|
|
|
|
func (m *Metrics) GetMetricsProvider() metric.MeterProvider {
|
|
return m.Provider
|
|
}
|
|
|
|
func (m *Metrics) RegisterCounter(name, description string) error {
|
|
if _, exists := m.Counters.Load(name); exists {
|
|
return nil
|
|
}
|
|
counter, err := m.Meter.Int64Counter(name, metric.WithDescription(description))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.Counters.Store(name, counter)
|
|
return nil
|
|
}
|
|
|
|
func (m *Metrics) AddCount(ctx context.Context, name string, value int64, labels map[string]attribute.Value) error {
|
|
counter, exists := m.Counters.Load(name)
|
|
if !exists {
|
|
return zerrors.ThrowNotFound(nil, "METER-4u8fs", "Errors.Metrics.Counter.NotFound")
|
|
}
|
|
counter.(metric.Int64Counter).Add(ctx, value, MapToAddOption(labels)...)
|
|
return nil
|
|
}
|
|
|
|
func (m *Metrics) RegisterUpDownSumObserver(name, description string, callbackFunc metric.Int64Callback) error {
|
|
if _, exists := m.UpDownSumObserver.Load(name); exists {
|
|
return nil
|
|
}
|
|
|
|
counter, err := m.Meter.Int64ObservableUpDownCounter(name, metric.WithInt64Callback(callbackFunc), metric.WithDescription(description))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m.UpDownSumObserver.Store(name, counter)
|
|
return nil
|
|
}
|
|
|
|
func (m *Metrics) RegisterValueObserver(name, description string, callbackFunc metric.Int64Callback) error {
|
|
if _, exists := m.UpDownSumObserver.Load(name); exists {
|
|
return nil
|
|
}
|
|
|
|
gauge, err := m.Meter.Int64ObservableGauge(name, metric.WithInt64Callback(callbackFunc), metric.WithDescription(description))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m.UpDownSumObserver.Store(name, gauge)
|
|
return nil
|
|
}
|
|
|
|
func MapToAddOption(labels map[string]attribute.Value) []metric.AddOption {
|
|
if labels == nil {
|
|
return nil
|
|
}
|
|
keyValues := make([]attribute.KeyValue, 0, len(labels))
|
|
for key, value := range labels {
|
|
keyValues = append(keyValues, attribute.KeyValue{
|
|
Key: attribute.Key(key),
|
|
Value: value,
|
|
})
|
|
}
|
|
return []metric.AddOption{metric.WithAttributes(keyValues...)}
|
|
}
|