Skip to content

Commit

Permalink
turns gRPC latency histogram into a toggleable option
Browse files Browse the repository at this point in the history
so that custom builds of SpiceDB can decide to enable or disable it,
as with the new version of the grpc-ecosystem prometheus middleware
does not provide enough granularity.
  • Loading branch information
vroldanbet committed Mar 15, 2024
1 parent d66d50e commit 9333f75
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 22 deletions.
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/devtools.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
30 changes: 17 additions & 13 deletions pkg/cmd/server/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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).
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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")),
Expand Down Expand Up @@ -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() {
Expand Down
8 changes: 6 additions & 2 deletions pkg/cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ type Config struct {
// Logs
EnableRequestLogs bool `debugmap:"visible"`
EnableResponseLogs bool `debugmap:"visible"`

// Metrics
DisableGRPCLatencyHistogram bool `debugmap:"visible"`
}

type closeableStack struct {
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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)

Expand Down
9 changes: 9 additions & 0 deletions pkg/cmd/server/zz_generated.options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9333f75

Please sign in to comment.