Skip to content

Commit c422228

Browse files
committed
Add initial set of metrics for BBR
1 parent f769a23 commit c422228

File tree

4 files changed

+99
-8
lines changed

4 files changed

+99
-8
lines changed

Diff for: cmd/body-based-routing/main.go

+70
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,26 @@ package main
1818

1919
import (
2020
"flag"
21+
"net"
22+
"net/http"
2123
"os"
24+
"strconv"
2225

2326
"github.com/go-logr/logr"
27+
"github.com/prometheus/client_golang/prometheus/promhttp"
2428
uberzap "go.uber.org/zap"
2529
"go.uber.org/zap/zapcore"
2630
"google.golang.org/grpc"
2731
healthPb "google.golang.org/grpc/health/grpc_health_v1"
32+
"k8s.io/client-go/rest"
33+
"k8s.io/component-base/metrics/legacyregistry"
2834
ctrl "sigs.k8s.io/controller-runtime"
2935
"sigs.k8s.io/controller-runtime/pkg/log/zap"
3036
"sigs.k8s.io/controller-runtime/pkg/manager"
37+
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
3138
"sigs.k8s.io/gateway-api-inference-extension/internal/runnable"
3239
runserver "sigs.k8s.io/gateway-api-inference-extension/pkg/body-based-routing/server"
40+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/metrics"
3341
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging"
3442
)
3543

@@ -42,6 +50,8 @@ var (
4250
"grpcHealthPort",
4351
9003,
4452
"The port used for gRPC liveness and readiness probes")
53+
metricsPort = flag.Int(
54+
"metricsPort", 9090, "The metrics port")
4555
logVerbosity = flag.Int("v", logging.DEFAULT, "number for the log level verbosity")
4656

4757
setupLog = ctrl.Log.WithName("setup")
@@ -95,6 +105,11 @@ func run() error {
95105
return err
96106
}
97107

108+
// Register metrics handler.
109+
if err := registerMetricsHandler(mgr, *metricsPort, cfg); err != nil {
110+
return err
111+
}
112+
98113
// Start the manager. This blocks until a signal is received.
99114
setupLog.Info("Manager starting")
100115
if err := mgr.Start(ctx); err != nil {
@@ -135,3 +150,58 @@ func initLogging(opts *zap.Options) {
135150
logger := zap.New(zap.UseFlagOptions(opts), zap.RawZapOpts(uberzap.AddCaller()))
136151
ctrl.SetLogger(logger)
137152
}
153+
154+
const metricsEndpoint = "/metrics"
155+
156+
// registerMetricsHandler adds the metrics HTTP handler as a Runnable to the given manager.
157+
func registerMetricsHandler(mgr manager.Manager, port int, cfg *rest.Config) error {
158+
metrics.Register()
159+
160+
// Init HTTP server.
161+
h, err := metricsHandlerWithAuthenticationAndAuthorization(cfg)
162+
if err != nil {
163+
return err
164+
}
165+
166+
mux := http.NewServeMux()
167+
mux.Handle(metricsEndpoint, h)
168+
169+
srv := &http.Server{
170+
Addr: net.JoinHostPort("", strconv.Itoa(port)),
171+
Handler: mux,
172+
}
173+
174+
if err := mgr.Add(&manager.Server{
175+
Name: "metrics",
176+
Server: srv,
177+
}); err != nil {
178+
setupLog.Error(err, "Failed to register metrics HTTP handler")
179+
return err
180+
}
181+
return nil
182+
}
183+
184+
func metricsHandlerWithAuthenticationAndAuthorization(cfg *rest.Config) (http.Handler, error) {
185+
h := promhttp.HandlerFor(
186+
legacyregistry.DefaultGatherer,
187+
promhttp.HandlerOpts{},
188+
)
189+
httpClient, err := rest.HTTPClientFor(cfg)
190+
if err != nil {
191+
setupLog.Error(err, "Failed to create http client for metrics auth")
192+
return nil, err
193+
}
194+
195+
filter, err := filters.WithAuthenticationAndAuthorization(cfg, httpClient)
196+
if err != nil {
197+
setupLog.Error(err, "Failed to create metrics filter for auth")
198+
return nil, err
199+
}
200+
metricsLogger := ctrl.Log.WithName("metrics").WithValues("path", metricsEndpoint)
201+
metricsAuthHandler, err := filter(metricsLogger, h)
202+
if err != nil {
203+
setupLog.Error(err, "Failed to create metrics auth handler")
204+
return nil, err
205+
}
206+
return metricsAuthHandler, nil
207+
}

Diff for: pkg/body-based-routing/handlers/request.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (s *Server) HandleRequestBody(ctx context.Context, body *eppb.HttpBody) (*e
5050

5151
modelStr, ok := modelVal.(string)
5252
if !ok {
53-
metrics.RecordModelNotParseableCounter()
53+
metrics.RecordModelNotParsedCounter()
5454
logger.V(logutil.DEFAULT).Info("Model parameter value is not a string")
5555
return &eppb.ProcessingResponse{
5656
Response: &eppb.ProcessingResponse_RequestBody{

Diff for: pkg/body-based-routing/handlers/request_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ package handlers
1818

1919
import (
2020
"context"
21+
"strings"
2122
"testing"
2223

2324
basepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
2425
extProcPb "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"
2526
"github.com/google/go-cmp/cmp"
2627
"google.golang.org/protobuf/testing/protocmp"
28+
"k8s.io/component-base/metrics/legacyregistry"
29+
metricsutils "k8s.io/component-base/metrics/testutil"
30+
"sigs.k8s.io/gateway-api-inference-extension/pkg/body-based-routing/metrics"
2731
logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging"
2832
)
2933

@@ -48,6 +52,7 @@ const (
4852
)
4953

5054
func TestHandleRequestBody(t *testing.T) {
55+
metrics.Register()
5156
ctx := logutil.NewTestLoggerIntoContext(context.Background())
5257

5358
tests := []struct {
@@ -125,4 +130,20 @@ func TestHandleRequestBody(t *testing.T) {
125130
}
126131
})
127132
}
133+
134+
wantMetrics := `
135+
# HELP bbr_model_not_in_body_total [ALPHA] Count of times the model was not present in the request body.
136+
# TYPE bbr_model_not_in_body_total counter
137+
bbr_model_not_in_body_total{} 1
138+
# HELP bbr_model_not_parsed_total [ALPHA] Count of times the model was in the request body but we could not parse it.
139+
# TYPE bbr_model_not_parsed_total counter
140+
bbr_model_not_parsed_total{} 1
141+
# HELP bbr_success_total [ALPHA] Count of successes pulling model name from body and injecting it in the request headers.
142+
# TYPE bbr_success_total counter
143+
bbr_success_total{} 1
144+
`
145+
146+
if err := metricsutils.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(wantMetrics), "inference_model_request_total"); err != nil {
147+
t.Error(err)
148+
}
128149
}

Diff for: pkg/body-based-routing/metrics/metrics.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"k8s.io/component-base/metrics/legacyregistry"
2424
)
2525

26-
const component = "BodyBasedRouting"
26+
const component = "bbr"
2727

2828
var (
2929
successCounter = compbasemetrics.NewCounterVec(
@@ -44,10 +44,10 @@ var (
4444
},
4545
[]string{},
4646
)
47-
modelNotParseableCounter = compbasemetrics.NewCounterVec(
47+
modelNotParsedCounter = compbasemetrics.NewCounterVec(
4848
&compbasemetrics.CounterOpts{
4949
Subsystem: component,
50-
Name: "model_not_parseable_total",
50+
Name: "model_not_parsed_total",
5151
Help: "Count of times the model was in the request body but we could not parse it.",
5252
StabilityLevel: compbasemetrics.ALPHA,
5353
},
@@ -75,7 +75,7 @@ func Register() {
7575
registerMetrics.Do(func() {
7676
legacyregistry.MustRegister(successCounter)
7777
legacyregistry.MustRegister(modelNotInBodyCounter)
78-
legacyregistry.MustRegister(modelNotParseableCounter)
78+
legacyregistry.MustRegister(modelNotParsedCounter)
7979
// legacyregistry.MustRegister(modelAlreadyPresentInHeaderCounter)
8080
})
8181
}
@@ -90,9 +90,9 @@ func RecordModelNotInBodyCounter() {
9090
modelNotInBodyCounter.WithLabelValues().Inc()
9191
}
9292

93-
// RecordModelNotParseableCounter records the number of times the model was found in the body but it was not parseable.
94-
func RecordModelNotParseableCounter() {
95-
modelNotParseableCounter.WithLabelValues().Inc()
93+
// RecordModelNotParsedCounter records the number of times the model was found in the body but it could not be parsed.
94+
func RecordModelNotParsedCounter() {
95+
modelNotParsedCounter.WithLabelValues().Inc()
9696
}
9797

9898
/*

0 commit comments

Comments
 (0)