Skip to content

Commit d287787

Browse files
authored
feat: move prometheus middleware early in the chain (#1584)
Signed-off-by: Miguel Martinez <[email protected]>
1 parent 697e45c commit d287787

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

app/controlplane/internal/server/grpc.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@ func NewGRPCServer(opts *Opts) (*grpc.Server, error) {
9595
// Opt-in histogram metrics for the interceptor
9696
grpc_prometheus.EnableHandlingTimeHistogram()
9797

98+
// NOTE: kratos middlewares will always be run before plain grpc unary interceptors
99+
// If you want to change the behavior, please refer to wrappers.go and the Prometheus wrapper as example
98100
var serverOpts = []grpc.ServerOption{
99101
grpc.Middleware(craftMiddleware(opts)...),
100102
grpc.UnaryInterceptor(
101-
grpc_prometheus.UnaryServerInterceptor,
102103
protovalidateMiddleware.UnaryServerInterceptor(opts.Validator),
103104
),
104105
}
@@ -170,6 +171,7 @@ func craftMiddleware(opts *Opts) []middleware.Middleware {
170171

171172
// User authentication
172173
middlewares = append(middlewares,
174+
usercontext.Prometheus(),
173175
// If we require a logged in user we
174176
selector.Server(
175177
// 1 - Extract the currentUser/API token from the JWT
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// Copyright 2024 The Chainloop Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package usercontext
17+
18+
import (
19+
"context"
20+
21+
"github.com/go-kratos/kratos/v2/middleware"
22+
"github.com/go-kratos/kratos/v2/transport"
23+
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
24+
25+
"google.golang.org/grpc"
26+
)
27+
28+
// This package contains a set of wrappers that take grpc.UnaryInterceptors and translate them into Kratos middlewares.
29+
// The reason for having these kind of wrappers is so we can sort them in the context of the rest of middlewares.
30+
// Otherwise, plain grpc interceptors will be added after the chain of middlewares
31+
// https://github.com/go-kratos/kratos/blob/f8b97f675b32dfad02edae12d83053c720720b5b/transport/grpc/server.go#L166
32+
func Prometheus() middleware.Middleware {
33+
var interceptor = grpc_prometheus.UnaryServerInterceptor
34+
return func(handler middleware.Handler) middleware.Handler {
35+
return func(ctx context.Context, req interface{}) (interface{}, error) {
36+
// Extract gRPC metadata from the context
37+
info, ok := transport.FromServerContext(ctx)
38+
if !ok {
39+
// If gRPC metadata is not available, fallback to default handler
40+
return handler(ctx, req)
41+
}
42+
43+
// Wrap the handler into a gRPC UnaryHandler
44+
grpcHandler := func(ctx context.Context, req interface{}) (interface{}, error) {
45+
return handler(ctx, req)
46+
}
47+
48+
// Call the interceptor
49+
return interceptor(ctx, req, &grpc.UnaryServerInfo{
50+
Server: nil, // Kratos doesn't provide the server instance directly
51+
FullMethod: info.Operation(),
52+
}, grpcHandler)
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)