Merge pull request #11989 from containerd/dependabot/go_modules/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus-1.1.0

build(deps): bump github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus from 1.0.1 to 1.1.0
This commit is contained in:
Phil Estes
2025-06-20 18:19:33 +00:00
committed by GitHub
7 changed files with 127 additions and 31 deletions

2
go.mod
View File

@@ -40,7 +40,7 @@ require (
github.com/fsnotify/fsnotify v1.9.0
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0
github.com/intel/goresctrl v0.8.0
github.com/klauspost/compress v1.18.0
github.com/mdlayher/vsock v1.2.1

4
go.sum
View File

@@ -170,8 +170,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=

View File

@@ -46,6 +46,13 @@ func WithSubsystem(subsystem string) CounterOption {
}
}
// WithNamespace allows you to add a Namespace to Counter metrics.
func WithNamespace(namespace string) CounterOption {
return func(o *prometheus.CounterOpts) {
o.Namespace = namespace
}
}
// A HistogramOption lets you add options to Histogram metrics using With*
// funcs.
type HistogramOption func(*prometheus.HistogramOpts)
@@ -68,7 +75,7 @@ func WithHistogramBuckets(buckets []float64) HistogramOption {
// This function is helpful when specifying more than just the buckets, like using NativeHistograms.
func WithHistogramOpts(opts *prometheus.HistogramOpts) HistogramOption {
// TODO: This isn't ideal either if new fields are added to prometheus.HistogramOpts.
// Maybe we can change the interface to accept abitrary HistogramOpts and
// Maybe we can change the interface to accept arbitrary HistogramOpts and
// only make sure to overwrite the necessary fields (name, labels).
return func(o *prometheus.HistogramOpts) {
o.Buckets = opts.Buckets
@@ -95,6 +102,13 @@ func WithHistogramSubsystem(subsystem string) HistogramOption {
}
}
// WithHistogramNamespace allows you to add a Namespace to histograms metrics.
func WithHistogramNamespace(namespace string) HistogramOption {
return func(o *prometheus.HistogramOpts) {
o.Namespace = namespace
}
}
func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType {
if !mInfo.IsClientStream && !mInfo.IsServerStream {
return Unary
@@ -113,6 +127,7 @@ type Option func(*config)
type config struct {
exemplarFn exemplarFromCtxFn
labelsFn labelsFromCtxFn
}
func (c *config) apply(opts []Option) {
@@ -127,3 +142,11 @@ func WithExemplarFromContext(exemplarFn exemplarFromCtxFn) Option {
o.exemplarFn = exemplarFn
}
}
// WithLabelsFromContext sets function that will be used to extract labels from context for metrics.
// This should be used in conjunction with WithContextLabels to define which labels to extract.
func WithLabelsFromContext(labelsFn labelsFromCtxFn) Option {
return func(o *config) {
o.labelsFn = labelsFn
}
}

View File

@@ -18,6 +18,7 @@ type reporter struct {
service, method string
kind Kind
exemplar prometheus.Labels
contextLabels []string
}
func (r *reporter) PostCall(err error, rpcDuration time.Duration) {
@@ -28,9 +29,13 @@ func (r *reporter) PostCall(err error, rpcDuration time.Duration) {
// perform handling of metrics from code
switch r.kind {
case KindServer:
r.incrementWithExemplar(r.serverMetrics.serverHandledCounter, string(r.typ), r.service, r.method, code.String())
baseLabels := []string{string(r.typ), r.service, r.method, code.String()}
allLabels := append(baseLabels, r.contextLabels...)
r.incrementWithExemplar(r.serverMetrics.serverHandledCounter, allLabels...)
if r.serverMetrics.serverHandledHistogram != nil {
r.observeWithExemplar(r.serverMetrics.serverHandledHistogram, rpcDuration.Seconds(), string(r.typ), r.service, r.method)
histLabels := []string{string(r.typ), r.service, r.method}
allHistLabels := append(histLabels, r.contextLabels...)
r.observeWithExemplar(r.serverMetrics.serverHandledHistogram, rpcDuration.Seconds(), allHistLabels...)
}
case KindClient:
@@ -44,7 +49,9 @@ func (r *reporter) PostCall(err error, rpcDuration time.Duration) {
func (r *reporter) PostMsgSend(_ any, _ error, sendDuration time.Duration) {
switch r.kind {
case KindServer:
r.incrementWithExemplar(r.serverMetrics.serverStreamMsgSent, string(r.typ), r.service, r.method)
baseLabels := []string{string(r.typ), r.service, r.method}
allLabels := append(baseLabels, r.contextLabels...)
r.incrementWithExemplar(r.serverMetrics.serverStreamMsgSent, allLabels...)
case KindClient:
r.incrementWithExemplar(r.clientMetrics.clientStreamMsgSent, string(r.typ), r.service, r.method)
if r.clientMetrics.clientStreamSendHistogram != nil {
@@ -56,7 +63,9 @@ func (r *reporter) PostMsgSend(_ any, _ error, sendDuration time.Duration) {
func (r *reporter) PostMsgReceive(_ any, _ error, recvDuration time.Duration) {
switch r.kind {
case KindServer:
r.incrementWithExemplar(r.serverMetrics.serverStreamMsgReceived, string(r.typ), r.service, r.method)
baseLabels := []string{string(r.typ), r.service, r.method}
allLabels := append(baseLabels, r.contextLabels...)
r.incrementWithExemplar(r.serverMetrics.serverStreamMsgReceived, allLabels...)
case KindClient:
r.incrementWithExemplar(r.clientMetrics.clientStreamMsgReceived, string(r.typ), r.service, r.method)
if r.clientMetrics.clientStreamRecvHistogram != nil {
@@ -95,11 +104,28 @@ func (rep *reportable) reporter(ctx context.Context, sm *ServerMetrics, cm *Clie
r.exemplar = c.exemplarFn(ctx)
}
// Extract context labels if labelsFn is configured and we're on server side
if c.labelsFn != nil && kind == KindServer && sm != nil {
contextLabelMap := c.labelsFn(ctx)
// Extract context label values in the order defined by the server metrics
r.contextLabels = make([]string, len(sm.contextLabelNames))
for i, labelName := range sm.contextLabelNames {
if value, exists := contextLabelMap[labelName]; exists {
r.contextLabels[i] = value
} else {
// Use empty string if label not found in context
r.contextLabels[i] = ""
}
}
}
switch kind {
case KindClient:
r.incrementWithExemplar(r.clientMetrics.clientStartedCounter, string(r.typ), r.service, r.method)
case KindServer:
r.incrementWithExemplar(r.serverMetrics.serverStartedCounter, string(r.typ), r.service, r.method)
baseLabels := []string{string(r.typ), r.service, r.method}
allLabels := append(baseLabels, r.contextLabels...)
r.incrementWithExemplar(r.serverMetrics.serverStartedCounter, allLabels...)
}
return r, ctx
}

View File

@@ -19,6 +19,8 @@ type ServerMetrics struct {
serverStreamMsgSent *prometheus.CounterVec
// serverHandledHistogram can be nil.
serverHandledHistogram *prometheus.HistogramVec
// contextLabelNames stores the names of context labels
contextLabelNames []string
}
// NewServerMetrics returns a new ServerMetrics object that has server interceptor methods.
@@ -27,28 +29,52 @@ type ServerMetrics struct {
func NewServerMetrics(opts ...ServerMetricsOption) *ServerMetrics {
var config serverMetricsConfig
config.apply(opts)
// Build label names by combining default labels with context labels
defaultLabels := []string{"grpc_type", "grpc_service", "grpc_method"}
defaultLabelsWithCode := []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}
startedLabels := append(defaultLabels, config.contextLabels...)
handledLabels := append(defaultLabelsWithCode, config.contextLabels...)
streamLabels := append(defaultLabels, config.contextLabels...)
// Create histogram if enabled
var serverHandledHistogram *prometheus.HistogramVec
if config.enableHistogram {
histogramLabels := append(defaultLabels, config.contextLabels...)
serverHandledHistogram = prometheus.NewHistogramVec(
histogramOptions(config.histogramOpts).apply(prometheus.HistogramOpts{
Name: "grpc_server_handling_seconds",
Help: "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.",
Buckets: prometheus.DefBuckets,
}),
histogramLabels,
)
}
return &ServerMetrics{
serverStartedCounter: prometheus.NewCounterVec(
config.counterOpts.apply(prometheus.CounterOpts{
Name: "grpc_server_started_total",
Help: "Total number of RPCs started on the server.",
}), []string{"grpc_type", "grpc_service", "grpc_method"}),
}), startedLabels),
serverHandledCounter: prometheus.NewCounterVec(
config.counterOpts.apply(prometheus.CounterOpts{
Name: "grpc_server_handled_total",
Help: "Total number of RPCs completed on the server, regardless of success or failure.",
}), []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}),
}), handledLabels),
serverStreamMsgReceived: prometheus.NewCounterVec(
config.counterOpts.apply(prometheus.CounterOpts{
Name: "grpc_server_msg_received_total",
Help: "Total number of RPC stream messages received on the server.",
}), []string{"grpc_type", "grpc_service", "grpc_method"}),
}), streamLabels),
serverStreamMsgSent: prometheus.NewCounterVec(
config.counterOpts.apply(prometheus.CounterOpts{
Name: "grpc_server_msg_sent_total",
Help: "Total number of gRPC stream messages sent by the server.",
}), []string{"grpc_type", "grpc_service", "grpc_method"}),
serverHandledHistogram: config.serverHandledHistogram,
}), streamLabels),
serverHandledHistogram: serverHandledHistogram,
contextLabelNames: config.contextLabels,
}
}
@@ -95,15 +121,28 @@ func (m *ServerMetrics) InitializeMetrics(server reflection.ServiceInfoProvider)
func (m *ServerMetrics) preRegisterMethod(serviceName string, mInfo *grpc.MethodInfo) {
methodName := mInfo.Name
methodType := string(typeFromMethodInfo(mInfo))
// Create empty context label values for pre-registration
contextLabels := make([]string, len(m.contextLabelNames))
for i := range contextLabels {
contextLabels[i] = ""
}
// Build complete label value arrays
startedLabels := append([]string{methodType, serviceName, methodName}, contextLabels...)
handledLabels := append([]string{methodType, serviceName, methodName}, contextLabels...)
streamLabels := append([]string{methodType, serviceName, methodName}, contextLabels...)
// These are just references (no increments), as just referencing will create the labels but not set values.
_, _ = m.serverStartedCounter.GetMetricWithLabelValues(methodType, serviceName, methodName)
_, _ = m.serverStreamMsgReceived.GetMetricWithLabelValues(methodType, serviceName, methodName)
_, _ = m.serverStreamMsgSent.GetMetricWithLabelValues(methodType, serviceName, methodName)
_, _ = m.serverStartedCounter.GetMetricWithLabelValues(startedLabels...)
_, _ = m.serverStreamMsgReceived.GetMetricWithLabelValues(streamLabels...)
_, _ = m.serverStreamMsgSent.GetMetricWithLabelValues(streamLabels...)
if m.serverHandledHistogram != nil {
_, _ = m.serverHandledHistogram.GetMetricWithLabelValues(methodType, serviceName, methodName)
_, _ = m.serverHandledHistogram.GetMetricWithLabelValues(streamLabels...)
}
for _, code := range interceptors.AllCodes {
_, _ = m.serverHandledCounter.GetMetricWithLabelValues(methodType, serviceName, methodName, code.String())
handledLabelsWithCode := append(handledLabels, code.String())
_, _ = m.serverHandledCounter.GetMetricWithLabelValues(handledLabelsWithCode...)
}
}

View File

@@ -10,11 +10,16 @@ import (
)
type exemplarFromCtxFn func(ctx context.Context) prometheus.Labels
type labelsFromCtxFn func(metadata context.Context) prometheus.Labels
type serverMetricsConfig struct {
counterOpts counterOptions
// serverHandledHistogram can be nil.
serverHandledHistogram *prometheus.HistogramVec
// histogramOpts stores the options for creating the histogram with dynamic labels
histogramOpts histogramOptions
// enableHistogram indicates whether histogram should be created
enableHistogram bool
// contextLabels defines the names of dynamic labels to be extracted from context
contextLabels []string
}
type ServerMetricsOption func(*serverMetricsConfig)
@@ -36,13 +41,16 @@ func WithServerCounterOptions(opts ...CounterOption) ServerMetricsOption {
// Histogram metrics can be very expensive for Prometheus to retain and query.
func WithServerHandlingTimeHistogram(opts ...HistogramOption) ServerMetricsOption {
return func(o *serverMetricsConfig) {
o.serverHandledHistogram = prometheus.NewHistogramVec(
histogramOptions(opts).apply(prometheus.HistogramOpts{
Name: "grpc_server_handling_seconds",
Help: "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.",
Buckets: prometheus.DefBuckets,
}),
[]string{"grpc_type", "grpc_service", "grpc_method"},
)
o.histogramOpts = opts
o.enableHistogram = true
}
}
// WithContextLabels configures the server metrics to include dynamic labels extracted from context.
// The provided label names will be added to all server metrics as dynamic labels.
// Use WithLabelsFromContext in the interceptor options to specify how to extract these labels from context.
func WithContextLabels(labelNames ...string) ServerMetricsOption {
return func(o *serverMetricsConfig) {
o.contextLabels = labelNames
}
}

4
vendor/modules.txt vendored
View File

@@ -313,8 +313,8 @@ github.com/google/uuid
# github.com/gorilla/websocket v1.5.0
## explicit; go 1.12
github.com/gorilla/websocket
# github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
## explicit; go 1.19
# github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0
## explicit; go 1.21
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus
# github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
## explicit; go 1.19