Zanzana: Add server side metrics (#109923)
* Zanzana: Add metrics to server side * Zanzana: Collect check duration * add metrics for other methods
This commit is contained in:
@@ -189,7 +189,7 @@ func (s *ModuleServer) Run() error {
|
||||
})
|
||||
|
||||
m.RegisterModule(modules.ZanzanaServer, func() (services.Service, error) {
|
||||
return authz.ProvideZanzanaService(s.cfg, s.features)
|
||||
return authz.ProvideZanzanaService(s.cfg, s.features, s.registerer)
|
||||
})
|
||||
|
||||
m.RegisterModule(modules.FrontendServer, func() (services.Service, error) {
|
||||
|
||||
@@ -88,7 +88,7 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, tracer tracing.Tracer, features
|
||||
return nil, fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
srv, err := zanzana.NewServer(cfg.ZanzanaServer, openfga, logger, tracer)
|
||||
srv, err := zanzana.NewServer(cfg.ZanzanaServer, openfga, logger, tracer, reg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
@@ -127,11 +127,12 @@ type ZanzanaService interface {
|
||||
var _ ZanzanaService = (*Zanzana)(nil)
|
||||
|
||||
// ProvideZanzanaService is used to register zanzana as a module so we can run it seperatly from grafana.
|
||||
func ProvideZanzanaService(cfg *setting.Cfg, features featuremgmt.FeatureToggles) (*Zanzana, error) {
|
||||
func ProvideZanzanaService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, reg prometheus.Registerer) (*Zanzana, error) {
|
||||
s := &Zanzana{
|
||||
cfg: cfg,
|
||||
features: features,
|
||||
logger: log.New("zanzana.server"),
|
||||
reg: reg,
|
||||
}
|
||||
|
||||
s.BasicService = services.NewBasicService(s.start, s.running, s.stopping).WithName("zanzana")
|
||||
@@ -147,6 +148,7 @@ type Zanzana struct {
|
||||
logger log.Logger
|
||||
handle grpcserver.Provider
|
||||
features featuremgmt.FeatureToggles
|
||||
reg prometheus.Registerer
|
||||
}
|
||||
|
||||
func (z *Zanzana) start(ctx context.Context) error {
|
||||
@@ -172,7 +174,7 @@ func (z *Zanzana) start(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
zanzanaServer, err := zanzana.NewServer(z.cfg.ZanzanaServer, openfgaServer, z.logger, tracer)
|
||||
zanzanaServer, err := zanzana.NewServer(z.cfg.ZanzanaServer, openfgaServer, z.logger, tracer, z.reg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
openfgaserver "github.com/openfga/openfga/pkg/server"
|
||||
openfgastorage "github.com/openfga/openfga/pkg/storage"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@@ -13,8 +14,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga server.OpenFGAServer, logger log.Logger, tracer tracing.Tracer) (*server.Server, error) {
|
||||
return server.NewServer(cfg, openfga, logger, tracer)
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga server.OpenFGAServer, logger log.Logger, tracer tracing.Tracer, reg prometheus.Registerer) (*server.Server, error) {
|
||||
return server.NewServer(cfg, openfga, logger, tracer, reg)
|
||||
}
|
||||
|
||||
func NewHealthServer(target server.DiagnosticServer) *server.HealthServer {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
const (
|
||||
metricsNamespace = "iam"
|
||||
metricsSubSystem = "authz_zanzana_server"
|
||||
)
|
||||
|
||||
type metrics struct {
|
||||
// requestDurationSeconds is a summary for zanzana server request duration
|
||||
requestDurationSeconds *prometheus.HistogramVec
|
||||
}
|
||||
|
||||
func newZanzanaServerMetrics(reg prometheus.Registerer) *metrics {
|
||||
return &metrics{
|
||||
requestDurationSeconds: promauto.With(reg).NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "request_duration_seconds",
|
||||
Help: "Histogram for zanzana server request duration",
|
||||
Namespace: metricsNamespace,
|
||||
Subsystem: metricsSubSystem,
|
||||
Buckets: prometheus.ExponentialBuckets(0.00001, 4, 10),
|
||||
},
|
||||
[]string{"method", "namespace"},
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/fullstorydev/grpchan/inprocgrpc"
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
dashboardV2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
|
||||
@@ -43,8 +44,9 @@ type Server struct {
|
||||
storesMU *sync.Mutex
|
||||
cache *localcache.CacheService
|
||||
|
||||
logger log.Logger
|
||||
tracer tracing.Tracer
|
||||
logger log.Logger
|
||||
tracer tracing.Tracer
|
||||
metrics *metrics
|
||||
}
|
||||
|
||||
type storeInfo struct {
|
||||
@@ -52,7 +54,7 @@ type storeInfo struct {
|
||||
ModelID string
|
||||
}
|
||||
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga OpenFGAServer, logger log.Logger, tracer tracing.Tracer) (*Server, error) {
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga OpenFGAServer, logger log.Logger, tracer tracing.Tracer, reg prometheus.Registerer) (*Server, error) {
|
||||
channel := &inprocgrpc.Channel{}
|
||||
openfgav1.RegisterOpenFGAServiceServer(channel, openfga)
|
||||
openFGAClient := openfgav1.NewOpenFGAServiceClient(channel)
|
||||
@@ -66,6 +68,7 @@ func NewServer(cfg setting.ZanzanaServerSettings, openfga OpenFGAServer, logger
|
||||
cache: localcache.New(cfg.CacheSettings.CheckQueryCacheTTL, cacheCleanInterval),
|
||||
logger: logger,
|
||||
tracer: tracer,
|
||||
metrics: newZanzanaServerMetrics(reg),
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
@@ -16,9 +17,11 @@ import (
|
||||
func (s *Server) Check(ctx context.Context, r *authzv1.CheckRequest) (*authzv1.CheckResponse, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "server.Check")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
attribute.String("namespace", r.GetNamespace()),
|
||||
)
|
||||
span.SetAttributes(attribute.String("namespace", r.GetNamespace()))
|
||||
|
||||
defer func(t time.Time) {
|
||||
s.metrics.requestDurationSeconds.WithLabelValues("server.Check", r.GetNamespace()).Observe(time.Since(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
res, err := s.check(ctx, r)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
@@ -19,9 +20,11 @@ import (
|
||||
func (s *Server) List(ctx context.Context, r *authzv1.ListRequest) (*authzv1.ListResponse, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "server.List")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
attribute.String("namespace", r.GetNamespace()),
|
||||
)
|
||||
span.SetAttributes(attribute.String("namespace", r.GetNamespace()))
|
||||
|
||||
defer func(t time.Time) {
|
||||
s.metrics.requestDurationSeconds.WithLabelValues("server.List", r.GetNamespace()).Observe(time.Since(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
res, err := s.list(ctx, r)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
|
||||
@@ -15,6 +16,10 @@ func (s *Server) Read(ctx context.Context, req *authzextv1.ReadRequest) (*authze
|
||||
ctx, span := s.tracer.Start(ctx, "server.Read")
|
||||
defer span.End()
|
||||
|
||||
defer func(t time.Time) {
|
||||
s.metrics.requestDurationSeconds.WithLabelValues("server.Read", req.GetNamespace()).Observe(time.Since(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
res, err := s.read(ctx, req)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to perform read request", "error", err, "namespace", req.GetNamespace())
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
authnlib "github.com/grafana/authlib/authn"
|
||||
@@ -92,7 +93,7 @@ func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server {
|
||||
openfga, err := NewOpenFGAServer(cfg.ZanzanaServer, store)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv, err := NewServer(cfg.ZanzanaServer, openfga, log.NewNopLogger(), tracing.NewNoopTracerService())
|
||||
srv, err := NewServer(cfg.ZanzanaServer, openfga, log.NewNopLogger(), tracing.NewNoopTracerService(), prometheus.NewRegistry())
|
||||
require.NoError(t, err)
|
||||
|
||||
storeInf, err := srv.getStoreInfo(context.Background(), namespace)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
|
||||
@@ -15,6 +16,10 @@ func (s *Server) Write(ctx context.Context, req *authzextv1.WriteRequest) (*auth
|
||||
ctx, span := s.tracer.Start(ctx, "server.Write")
|
||||
defer span.End()
|
||||
|
||||
defer func(t time.Time) {
|
||||
s.metrics.requestDurationSeconds.WithLabelValues("server.Write", req.GetNamespace()).Observe(time.Since(t).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
res, err := s.write(ctx, req)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to perform write request", "error", err, "namespace", req.GetNamespace())
|
||||
|
||||
Reference in New Issue
Block a user