Skip to content

Commit 9999ab2

Browse files
committed
feat: Add client_capability_enabled_total counter in ClientCapability middleware
1 parent 5b02fdd commit 9999ab2

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

pkg/featureflags/client_capability.go

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,29 @@ import (
99
"connectrpc.com/connect"
1010
"github.com/go-kit/log/level"
1111
"github.com/grafana/dskit/middleware"
12+
"github.com/grafana/pyroscope/pkg/tenant"
1213
"github.com/grafana/pyroscope/pkg/util"
14+
"github.com/prometheus/client_golang/prometheus"
1315
"google.golang.org/grpc"
1416
"google.golang.org/grpc/metadata"
1517
)
1618

1719
const (
18-
// Capability names - update parseClientCapabilities below when new capabilities added
20+
// Capability names - update parseClientCapabilities and trackEnabledCapabilities
21+
// below when new capabilities added
1922
allowUtf8LabelNamesCapabilityName string = "allow-utf8-labelnames"
2023
)
2124

25+
var (
26+
usage = prometheus.NewCounterVec(
27+
prometheus.CounterOpts{
28+
Name: "client_capability_enabled_total",
29+
Help: "Total number of requests with client capabilities enabled",
30+
},
31+
[]string{"tenant", "capability_name"},
32+
)
33+
)
34+
2235
// Define a custom context key type to avoid collisions
2336
type contextKey struct{}
2437

@@ -35,7 +48,35 @@ func GetClientCapabilities(ctx context.Context) (ClientCapabilities, bool) {
3548
return value, ok
3649
}
3750

38-
func ClientCapabilitiesGRPCMiddleware() grpc.UnaryServerInterceptor {
51+
type ClientCapabilityMiddleware struct {
52+
usage *prometheus.CounterVec
53+
}
54+
55+
func NewClientCapabilityMiddleware(reg prometheus.Registerer) *ClientCapabilityMiddleware {
56+
usage = util.RegisterOrGet(reg, usage)
57+
58+
return &ClientCapabilityMiddleware{
59+
usage: usage,
60+
}
61+
}
62+
63+
// trackEnabledCapabilities records metrics for each enabled capability
64+
func (m *ClientCapabilityMiddleware) trackEnabledCapabilities(ctx context.Context, capabilities ClientCapabilities) {
65+
tenantID, err := tenant.ExtractTenantIDFromContext(ctx)
66+
if err != nil {
67+
// Fall back if tenant cannot be extracted
68+
tenantID = tenant.DefaultTenantID
69+
}
70+
71+
// Track each enabled capability
72+
if capabilities.AllowUtf8LabelNames {
73+
m.usage.WithLabelValues(tenantID, allowUtf8LabelNamesCapabilityName).Inc()
74+
}
75+
}
76+
77+
// CreateGRPC creates gRPC middleware that extracts and parses the
78+
// `Accept` header for capabilities the client supports
79+
func (m *ClientCapabilityMiddleware) CreateGRPC() grpc.UnaryServerInterceptor {
3980
return func(
4081
ctx context.Context,
4182
req interface{},
@@ -62,13 +103,17 @@ func ClientCapabilitiesGRPCMiddleware() grpc.UnaryServerInterceptor {
62103
}
63104

64105
enhancedCtx := WithClientCapabilities(ctx, clientCapabilities)
106+
107+
// Track enabled capabilities for metrics
108+
m.trackEnabledCapabilities(enhancedCtx, clientCapabilities)
109+
65110
return handler(enhancedCtx, req)
66111
}
67112
}
68113

69-
// ClientCapabilitiesHttpMiddleware creates middleware that extracts and parses the
114+
// CreateHttp creates HTTP middleware that extracts and parses the
70115
// `Accept` header for capabilities the client supports
71-
func ClientCapabilitiesHttpMiddleware() middleware.Interface {
116+
func (m *ClientCapabilityMiddleware) CreateHttp() middleware.Interface {
72117
return middleware.Func(func(next http.Handler) http.Handler {
73118
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
74119
clientCapabilities, err := parseClientCapabilities(r.Header)
@@ -78,6 +123,10 @@ func ClientCapabilitiesHttpMiddleware() middleware.Interface {
78123
}
79124

80125
ctx := WithClientCapabilities(r.Context(), clientCapabilities)
126+
127+
// Track enabled capabilities for metrics
128+
m.trackEnabledCapabilities(ctx, clientCapabilities)
129+
81130
next.ServeHTTP(w, r.WithContext(ctx))
82131
})
83132
})

pkg/pyroscope/modules.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,9 +465,11 @@ func (f *Pyroscope) initServer() (services.Service, error) {
465465
// see https://github.com/grafana/pyroscope/issues/231
466466
f.Cfg.Server.DoNotAddDefaultHTTPMiddleware = true
467467
f.Cfg.Server.ExcludeRequestInLog = true // gRPC-specific.
468+
469+
clientCapabilitiesMiddleware := featureflags.NewClientCapabilityMiddleware(f.reg)
468470
f.Cfg.Server.GRPCMiddleware = append(f.Cfg.Server.GRPCMiddleware,
469471
util.RecoveryInterceptorGRPC,
470-
featureflags.ClientCapabilitiesGRPCMiddleware(),
472+
clientCapabilitiesMiddleware.CreateGRPC(),
471473
)
472474

473475
if f.Cfg.V2 {
@@ -526,7 +528,7 @@ func (f *Pyroscope) initServer() (services.Service, error) {
526528
httpMetric,
527529
objstoreTracerMiddleware,
528530
httputil.K6Middleware(),
529-
featureflags.ClientCapabilitiesHttpMiddleware(),
531+
clientCapabilitiesMiddleware.CreateHttp(),
530532
}
531533
if f.Cfg.SelfProfiling.UseK6Middleware {
532534
defaultHTTPMiddleware = append(defaultHTTPMiddleware, httputil.K6Middleware())

0 commit comments

Comments
 (0)