diff --git a/go.mod b/go.mod index 9fcda7d064..96630cdd53 100644 --- a/go.mod +++ b/go.mod @@ -130,7 +130,7 @@ require ( github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/bkielbasa/cyclop v1.2.1 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bombsimon/wsl/v3 v3.4.0 // indirect + github.com/bombsimon/wsl/v4 v4.2.1 // indirect github.com/breml/bidichk v0.2.7 // indirect github.com/breml/errchkjson v0.3.6 // indirect github.com/butuzov/ireturn v0.3.0 // indirect @@ -178,6 +178,7 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect + github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect @@ -219,6 +220,7 @@ require ( github.com/jgautheron/goconst v1.7.0 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/jjti/go-spancheck v0.5.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -318,6 +320,7 @@ require ( github.com/yeya24/promlinter v0.2.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // indirect gitlab.com/bosi/decorder v0.4.1 // indirect + go-simpler.org/musttag v0.8.0 // indirect go-simpler.org/sloglint v0.4.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect go.opentelemetry.io/contrib/propagators/ot v1.20.0 // indirect @@ -326,7 +329,6 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.tmz.dev/musttag v0.7.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.21.0 // indirect diff --git a/go.sum b/go.sum index 4e26345a9e..b9620353f1 100644 --- a/go.sum +++ b/go.sum @@ -137,7 +137,6 @@ github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJ github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= github.com/bombsimon/wsl/v4 v4.2.1 h1:Cxg6u+XDWff75SIFFmNsqnIOgob+Q9hG6y/ioKbRFiM= github.com/bombsimon/wsl/v4 v4.2.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= @@ -916,7 +915,6 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.tmz.dev/musttag v0.7.2/go.mod h1:m6q5NiiSKMnQYokefa2xGoyoXnrswCbJ0AWYzf4Zs28= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= diff --git a/pkg/cmd/devtools.go b/pkg/cmd/devtools.go index 898da1c54e..9dc8fec144 100644 --- a/pkg/cmd/devtools.go +++ b/pkg/cmd/devtools.go @@ -56,7 +56,7 @@ func NewDevtoolsCommand(programName string) *cobra.Command { } func runfunc(cmd *cobra.Command, _ []string) error { - grpcUnaryInterceptor, _ := server.GRPCMetrics() + grpcUnaryInterceptor, _ := server.GRPCMetrics(false) grpcBuilder := grpcServiceBuilder() grpcServer, err := grpcBuilder.ServerFromFlags(cmd, grpc.ChainUnaryInterceptor( diff --git a/pkg/cmd/server/defaults.go b/pkg/cmd/server/defaults.go index ac2428594b..12f63be134 100644 --- a/pkg/cmd/server/defaults.go +++ b/pkg/cmd/server/defaults.go @@ -163,6 +163,7 @@ type MiddlewareOption struct { ds datastore.Datastore enableRequestLog bool enableResponseLog bool + disableGRPCHistogram bool } // gRPCMetricsUnaryInterceptor creates the default prometheus metrics interceptor for unary gRPCs @@ -174,9 +175,9 @@ var gRPCMetricsStreamingInterceptor grpc.StreamServerInterceptor var serverMetricsOnce sync.Once // GRPCMetrics returns the interceptors used for the default gRPC metrics from grpc-ecosystem/go-grpc-middleware -func GRPCMetrics() (grpc.UnaryServerInterceptor, grpc.StreamServerInterceptor) { +func GRPCMetrics(disableLatencyHistogram bool) (grpc.UnaryServerInterceptor, grpc.StreamServerInterceptor) { serverMetricsOnce.Do(func() { - gRPCMetricsUnaryInterceptor, gRPCMetricsStreamingInterceptor = createServerMetrics() + gRPCMetricsUnaryInterceptor, gRPCMetricsStreamingInterceptor = createServerMetrics(disableLatencyHistogram) }) return gRPCMetricsUnaryInterceptor, gRPCMetricsStreamingInterceptor @@ -198,7 +199,7 @@ func doesNotMatchRoute(route string) func(_ context.Context, c interceptors.Call // DefaultUnaryMiddleware generates the default middleware chain used for the public SpiceDB Unary gRPC methods func DefaultUnaryMiddleware(opts MiddlewareOption) (*MiddlewareChain[grpc.UnaryServerInterceptor], error) { - grpcMetricsUnaryInterceptor, _ := GRPCMetrics() + grpcMetricsUnaryInterceptor, _ := GRPCMetrics(opts.disableGRPCHistogram) chain, err := NewMiddlewareChain([]ReferenceableMiddleware[grpc.UnaryServerInterceptor]{ NewUnaryMiddleware(). WithName(DefaultMiddlewareRequestID). @@ -276,7 +277,7 @@ func DefaultUnaryMiddleware(opts MiddlewareOption) (*MiddlewareChain[grpc.UnaryS // DefaultStreamingMiddleware generates the default middleware chain used for the public SpiceDB Streaming gRPC methods func DefaultStreamingMiddleware(opts MiddlewareOption) (*MiddlewareChain[grpc.StreamServerInterceptor], error) { - _, grpcMetricsStreamingInterceptor := GRPCMetrics() + _, grpcMetricsStreamingInterceptor := GRPCMetrics(opts.disableGRPCHistogram) chain, err := NewMiddlewareChain([]ReferenceableMiddleware[grpc.StreamServerInterceptor]{ NewStreamMiddleware(). WithName(DefaultMiddlewareRequestID). @@ -366,8 +367,10 @@ func determineEventsToLog(opts MiddlewareOption) grpclog.Option { } // DefaultDispatchMiddleware generates the default middleware chain used for the internal dispatch SpiceDB gRPC API -func DefaultDispatchMiddleware(logger zerolog.Logger, authFunc grpcauth.AuthFunc, ds datastore.Datastore) ([]grpc.UnaryServerInterceptor, []grpc.StreamServerInterceptor) { - grpcMetricsUnaryInterceptor, grpcMetricsStreamingInterceptor := GRPCMetrics() +func DefaultDispatchMiddleware(logger zerolog.Logger, authFunc grpcauth.AuthFunc, ds datastore.Datastore, + disableGRPCLatencyHistogram bool, +) ([]grpc.UnaryServerInterceptor, []grpc.StreamServerInterceptor) { + grpcMetricsUnaryInterceptor, grpcMetricsStreamingInterceptor := GRPCMetrics(disableGRPCLatencyHistogram) return []grpc.UnaryServerInterceptor{ requestid.UnaryServerInterceptor(requestid.GenerateIfMissing(true)), logmw.UnaryServerInterceptor(logmw.ExtractMetadataField("x-request-id", "requestID")), @@ -410,16 +413,17 @@ func InterceptorLogger(l zerolog.Logger) grpclog.Logger { } // initializes prometheus grpc interceptors with exemplar support enabled -func createServerMetrics() (grpc.UnaryServerInterceptor, grpc.StreamServerInterceptor) { - srvMetrics := grpcprom.NewServerMetrics( - grpcprom.WithServerHandlingTimeHistogram( +func createServerMetrics(disableHistogram bool) (grpc.UnaryServerInterceptor, grpc.StreamServerInterceptor) { + var opts []grpcprom.ServerMetricsOption + if !disableHistogram { + opts = append(opts, grpcprom.WithServerHandlingTimeHistogram( grpcprom.WithHistogramBuckets([]float64{.001, .003, .006, .010, .018, .024, .032, .042, .056, .075, .100, .178, .316, .562, 1, 5}), - ), - ) - + )) + } + srvMetrics := grpcprom.NewServerMetrics(opts...) // deliberately ignore if these metrics were already registered, so that // custom builds of SpiceDB can register these metrics with custom labels - _ = prometheus.DefaultRegisterer.Register(srvMetrics) + _ = prometheus.Register(srvMetrics) exemplarFromContext := func(ctx context.Context) prometheus.Labels { if span := trace.SpanContextFromContext(ctx); span.IsSampled() { diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index a3a90e45b1..0c4a7f1e03 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -131,6 +131,9 @@ type Config struct { // Logs EnableRequestLogs bool `debugmap:"visible"` EnableResponseLogs bool `debugmap:"visible"` + + // Metrics + DisableGRPCLatencyHistogram bool `debugmap:"visible"` } type closeableStack struct { @@ -289,9 +292,9 @@ func (c *Config) Complete(ctx context.Context) (RunnableServer, error) { if len(c.DispatchUnaryMiddleware) == 0 && len(c.DispatchStreamingMiddleware) == 0 { if c.GRPCAuthFunc == nil { - c.DispatchUnaryMiddleware, c.DispatchStreamingMiddleware = DefaultDispatchMiddleware(log.Logger, auth.MustRequirePresharedKey(c.PresharedSecureKey), ds) + c.DispatchUnaryMiddleware, c.DispatchStreamingMiddleware = DefaultDispatchMiddleware(log.Logger, auth.MustRequirePresharedKey(c.PresharedSecureKey), ds, c.DisableGRPCLatencyHistogram) } else { - c.DispatchUnaryMiddleware, c.DispatchStreamingMiddleware = DefaultDispatchMiddleware(log.Logger, c.GRPCAuthFunc, ds) + c.DispatchUnaryMiddleware, c.DispatchStreamingMiddleware = DefaultDispatchMiddleware(log.Logger, c.GRPCAuthFunc, ds, c.DisableGRPCLatencyHistogram) } } @@ -360,6 +363,7 @@ func (c *Config) Complete(ctx context.Context) (RunnableServer, error) { ds, c.EnableRequestLogs, c.EnableResponseLogs, + c.DisableGRPCLatencyHistogram, } defaultUnaryMiddlewareChain, err := DefaultUnaryMiddleware(opts) if err != nil { diff --git a/pkg/cmd/server/server_test.go b/pkg/cmd/server/server_test.go index f87f3f3847..9ae630b6ce 100644 --- a/pkg/cmd/server/server_test.go +++ b/pkg/cmd/server/server_test.go @@ -230,7 +230,7 @@ func TestModifyUnaryMiddleware(t *testing.T) { }, }} - opt := MiddlewareOption{logging.Logger, nil, false, nil, nil, false, false} + opt := MiddlewareOption{logging.Logger, nil, false, nil, nil, false, false, false} defaultMw, err := DefaultUnaryMiddleware(opt) require.NoError(t, err) @@ -256,7 +256,7 @@ func TestModifyStreamingMiddleware(t *testing.T) { }, }} - opt := MiddlewareOption{logging.Logger, nil, false, nil, nil, false, false} + opt := MiddlewareOption{logging.Logger, nil, false, nil, nil, false, false, false} defaultMw, err := DefaultStreamingMiddleware(opt) require.NoError(t, err) diff --git a/pkg/cmd/server/zz_generated.options.go b/pkg/cmd/server/zz_generated.options.go index 95b0d9f439..33572cb0b8 100644 --- a/pkg/cmd/server/zz_generated.options.go +++ b/pkg/cmd/server/zz_generated.options.go @@ -92,6 +92,7 @@ func (c *Config) ToOption() ConfigOption { to.TelemetryInterval = c.TelemetryInterval to.EnableRequestLogs = c.EnableRequestLogs to.EnableResponseLogs = c.EnableResponseLogs + to.DisableGRPCLatencyHistogram = c.DisableGRPCLatencyHistogram } } @@ -148,6 +149,7 @@ func (c Config) DebugMap() map[string]any { debugMap["TelemetryInterval"] = helpers.DebugValue(c.TelemetryInterval, false) debugMap["EnableRequestLogs"] = helpers.DebugValue(c.EnableRequestLogs, false) debugMap["EnableResponseLogs"] = helpers.DebugValue(c.EnableResponseLogs, false) + debugMap["DisableGRPCLatencyHistogram"] = helpers.DebugValue(c.DisableGRPCLatencyHistogram, false) return debugMap } @@ -600,3 +602,10 @@ func WithEnableResponseLogs(enableResponseLogs bool) ConfigOption { c.EnableResponseLogs = enableResponseLogs } } + +// WithDisableGRPCLatencyHistogram returns an option that can set DisableGRPCLatencyHistogram on a Config +func WithDisableGRPCLatencyHistogram(disableGRPCLatencyHistogram bool) ConfigOption { + return func(c *Config) { + c.DisableGRPCLatencyHistogram = disableGRPCLatencyHistogram + } +}