interceptors: migrate to otel and add logging interceptor

Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
2024-10-17 17:15:05 +02:00
parent 9591a64e09
commit 3a3d77169c
41 changed files with 2817 additions and 852 deletions

View File

@ -5,7 +5,7 @@ import (
"encoding/base64"
"strings"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"go.linka.cloud/grpc-toolkit/errors"
"go.linka.cloud/grpc-toolkit/interceptors"

View File

@ -4,7 +4,7 @@ import (
"context"
"crypto/subtle"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

View File

@ -4,7 +4,7 @@ import (
"context"
"testing"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
assert2 "github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"

View File

@ -1,7 +1,7 @@
package auth
import (
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
)
type Option func(o *options)

View File

@ -3,7 +3,7 @@ package auth
import (
"context"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"go.linka.cloud/grpc-toolkit/interceptors"
"go.linka.cloud/grpc-toolkit/interceptors/metadata"

View File

@ -3,7 +3,7 @@ package auth
import (
"context"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"

View File

@ -0,0 +1,77 @@
package logging
import (
"context"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"google.golang.org/grpc"
"go.linka.cloud/grpc-toolkit/interceptors"
"go.linka.cloud/grpc-toolkit/logger"
)
func New(ctx context.Context, opts ...logging.Option) interceptors.Interceptors {
log := logger.C(ctx)
return &interceptor{
log: logging.LoggerFunc(func(ctx context.Context, level logging.Level, msg string, fields ...any) {
switch level {
case logging.LevelDebug:
log.WithReportCaller(true, 2).WithFields(fields...).Debug(msg)
case logging.LevelInfo:
log.WithReportCaller(true, 2).WithFields(fields...).Info(msg)
case logging.LevelWarn:
log.WithReportCaller(true, 2).WithFields(fields...).Warn(msg)
case logging.LevelError:
log.WithReportCaller(true, 2).WithFields(fields...).Error(msg)
}
}),
opts: opts,
}
}
type interceptor struct {
log logging.Logger
opts []logging.Option
}
func (i *interceptor) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return grpc_middleware.ChainUnaryServer(
logging.UnaryServerInterceptor(i.log, i.opts...),
func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
log := logger.C(ctx)
return handler(logger.Set(ctx, log.WithFields(logging.ExtractFields(ctx)...)), req)
},
)
}
func (i *interceptor) StreamServerInterceptor() grpc.StreamServerInterceptor {
return grpc_middleware.ChainStreamServer(
logging.StreamServerInterceptor(i.log, i.opts...),
func(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
ctx := ss.Context()
log := logger.C(ctx)
return handler(srv, interceptors.NewContextServerStream(logger.Set(ctx, log.WithFields(logging.ExtractFields(ctx)...)), ss))
},
)
}
func (i *interceptor) UnaryClientInterceptor() grpc.UnaryClientInterceptor {
return grpc_middleware.ChainUnaryClient(
logging.UnaryClientInterceptor(i.log, i.opts...),
func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
log := logger.C(ctx)
return invoker(logger.Set(ctx, log.WithFields(logging.ExtractFields(ctx)...)), method, req, reply, cc, opts...)
},
)
}
func (i *interceptor) StreamClientInterceptor() grpc.StreamClientInterceptor {
return grpc_middleware.ChainStreamClient(
logging.StreamClientInterceptor(i.log, i.opts...),
func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
log := logger.C(ctx)
return streamer(logger.Set(ctx, log.WithFields(logging.ExtractFields(ctx)...)), desc, cc, method, opts...)
},
)
}

View File

@ -1,14 +1,24 @@
package metrics
import (
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"context"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
"github.com/prometheus/client_golang/prometheus"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"go.linka.cloud/grpc-toolkit/interceptors"
"go.linka.cloud/grpc-toolkit/service"
)
func DefaultExemplarFromCtx(ctx context.Context) prometheus.Labels {
if span := trace.SpanContextFromContext(ctx); span.IsSampled() {
return prometheus.Labels{"traceID": span.TraceID().String()}
}
return nil
}
type Registerer interface {
Register(svc service.Service)
}
@ -22,11 +32,6 @@ type ServerInterceptors interface {
Registerer
interceptors.ServerInterceptors
prometheus.Collector
EnableHandlingTimeHistogram(opts ...grpc_prometheus.HistogramOption)
EnableClientHandlingTimeHistogram(opts ...grpc_prometheus.HistogramOption)
EnableClientStreamReceiveTimeHistogram(opts ...grpc_prometheus.HistogramOption)
EnableClientStreamSendTimeHistogram(opts ...grpc_prometheus.HistogramOption)
}
type ClientInterceptors interface {
@ -36,46 +41,7 @@ type ClientInterceptors interface {
type metrics struct {
s *grpc_prometheus.ServerMetrics
c *grpc_prometheus.ClientMetrics
}
func (m *metrics) EnableHandlingTimeHistogram(opts ...grpc_prometheus.HistogramOption) {
if m.s != nil {
if m.s == grpc_prometheus.DefaultServerMetrics {
grpc_prometheus.EnableHandlingTimeHistogram(opts...)
} else {
m.s.EnableHandlingTimeHistogram(opts...)
}
}
}
func (m *metrics) EnableClientHandlingTimeHistogram(opts ...grpc_prometheus.HistogramOption) {
if m.c != nil {
if m.c == grpc_prometheus.DefaultClientMetrics {
grpc_prometheus.EnableClientHandlingTimeHistogram(opts...)
} else {
m.c.EnableClientHandlingTimeHistogram(opts...)
}
}
}
func (m *metrics) EnableClientStreamReceiveTimeHistogram(opts ...grpc_prometheus.HistogramOption) {
if m.c != nil {
if m.c == grpc_prometheus.DefaultClientMetrics {
grpc_prometheus.EnableClientStreamReceiveTimeHistogram(opts...)
} else {
m.c.EnableClientStreamReceiveTimeHistogram(opts...)
}
}
}
func (m *metrics) EnableClientStreamSendTimeHistogram(opts ...grpc_prometheus.HistogramOption) {
if m.c != nil {
if m.c == grpc_prometheus.DefaultClientMetrics {
grpc_prometheus.EnableClientStreamSendTimeHistogram(opts...)
} else {
m.c.EnableClientStreamSendTimeHistogram(opts...)
}
}
o *options
}
func (m *metrics) Describe(descs chan<- *prometheus.Desc) {
@ -96,36 +62,45 @@ func (m *metrics) Register(svc service.Service) {
}
}
func NewInterceptors(opts ...grpc_prometheus.CounterOption) Interceptors {
s := grpc_prometheus.NewServerMetrics(opts...)
c := grpc_prometheus.NewClientMetrics(opts...)
return &metrics{s: s, c: c}
func NewInterceptors(opts ...Option) Interceptors {
o := (&options{}).apply(opts...)
s := grpc_prometheus.NewServerMetrics(
grpc_prometheus.WithServerCounterOptions(o.copts...),
grpc_prometheus.WithServerHandlingTimeHistogram(o.hopts...),
)
c := grpc_prometheus.NewClientMetrics(
grpc_prometheus.WithClientCounterOptions(o.copts...),
grpc_prometheus.WithClientHandlingTimeHistogram(o.hopts...),
)
m := &metrics{s: s, c: c, o: o}
o.reg.MustRegister(m)
return m
}
func NewServerInterceptors(opts ...grpc_prometheus.CounterOption) ServerInterceptors {
s := grpc_prometheus.NewServerMetrics(opts...)
return &metrics{s: s}
func NewServerInterceptors(opts ...Option) ServerInterceptors {
o := (&options{}).apply(opts...)
s := grpc_prometheus.NewServerMetrics(
grpc_prometheus.WithServerCounterOptions(o.copts...),
grpc_prometheus.WithServerHandlingTimeHistogram(o.hopts...),
)
m := &metrics{s: s, o: o}
o.reg.MustRegister(m)
return m
}
func NewClientInterceptors(opts ...grpc_prometheus.CounterOption) ClientInterceptors {
c := grpc_prometheus.NewClientMetrics(opts...)
return &metrics{c: c}
}
func DefaultInterceptors() Interceptors {
return &metrics{s: grpc_prometheus.DefaultServerMetrics, c: grpc_prometheus.DefaultClientMetrics}
}
func DefaultServerInterceptors() ServerInterceptors {
return &metrics{s: grpc_prometheus.DefaultServerMetrics}
}
func DefaultClientInterceptors() ClientInterceptors {
return &metrics{c: grpc_prometheus.DefaultClientMetrics}
func NewClientInterceptors(opts ...Option) ClientInterceptors {
o := (&options{}).apply(opts...)
c := grpc_prometheus.NewClientMetrics(
grpc_prometheus.WithClientCounterOptions(o.copts...),
grpc_prometheus.WithClientHandlingTimeHistogram(o.hopts...),
)
m := &metrics{c: c, o: o}
o.reg.MustRegister(m)
return m
}
func (m *metrics) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return m.s.UnaryServerInterceptor()
return m.s.UnaryServerInterceptor(grpc_prometheus.WithExemplarFromContext(m.o.fn))
}
func (m *metrics) StreamServerInterceptor() grpc.StreamServerInterceptor {

View File

@ -0,0 +1,59 @@
package metrics
import (
"context"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
"github.com/prometheus/client_golang/prometheus"
)
type ExemplarFromCtxFunc func(ctx context.Context) prometheus.Labels
type Option func(*options)
func WithCounterOptons(opts ...grpc_prometheus.CounterOption) Option {
return func(o *options) {
o.copts = append(o.copts, opts...)
}
}
func WithHandlingTimeHistogram(opts ...grpc_prometheus.HistogramOption) Option {
return func(o *options) {
o.hopts = append(o.hopts, opts...)
}
}
func WithHistogramOpts(opts ...grpc_prometheus.HistogramOption) Option {
return func(o *options) {
o.hopts = append(o.hopts, opts...)
}
}
func WithExemplarFromContext(fn ExemplarFromCtxFunc) Option {
return func(o *options) {
o.fn = fn
}
}
func WithRegisterer(reg prometheus.Registerer) Option {
return func(o *options) {
o.reg = reg
}
}
type options struct {
copts []grpc_prometheus.CounterOption
hopts []grpc_prometheus.HistogramOption
fn func(ctx context.Context) prometheus.Labels
reg prometheus.Registerer
}
func (o *options) apply(opts ...Option) *options {
for _, v := range opts {
v(o)
}
if o.reg == nil {
o.reg = prometheus.DefaultRegisterer
}
return o
}

View File

@ -1,41 +1,40 @@
package tracing
import (
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
"github.com/opentracing/opentracing-go"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"google.golang.org/grpc"
"go.linka.cloud/grpc-toolkit/interceptors"
)
type tracing struct {
opts []otgrpc.Option
opts []otelgrpc.Option
}
func NewInterceptors(opts ...otgrpc.Option) interceptors.Interceptors {
func NewInterceptors(opts ...otelgrpc.Option) interceptors.Interceptors {
return tracing{opts: opts}
}
func NewClientInterceptors(opts ...otgrpc.Option) interceptors.ClientInterceptors {
func NewClientInterceptors(opts ...otelgrpc.Option) interceptors.ClientInterceptors {
return tracing{opts: opts}
}
func (t tracing) UnaryClientInterceptor() grpc.UnaryClientInterceptor {
return otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer(), t.opts...)
return otelgrpc.UnaryClientInterceptor(t.opts...)
}
func (t tracing) StreamClientInterceptor() grpc.StreamClientInterceptor {
return otgrpc.OpenTracingStreamClientInterceptor(opentracing.GlobalTracer(), t.opts...)
return otelgrpc.StreamClientInterceptor(t.opts...)
}
func NewServerInterceptors(opts ...otgrpc.Option) interceptors.ServerInterceptors {
func NewServerInterceptors(opts ...otelgrpc.Option) interceptors.ServerInterceptors {
return tracing{opts: opts}
}
func (t tracing) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return otgrpc.OpenTracingServerInterceptor(opentracing.GlobalTracer(), t.opts...)
return otelgrpc.UnaryServerInterceptor(t.opts...)
}
func (t tracing) StreamServerInterceptor() grpc.StreamServerInterceptor {
return otgrpc.OpenTracingStreamServerInterceptor(opentracing.GlobalTracer(), t.opts...)
return otelgrpc.StreamServerInterceptor(t.opts...)
}