mirror of
https://github.com/linka-cloud/grpc.git
synced 2025-06-22 01:02:29 +00:00
interceptors: migrate to otel and add logging interceptor
Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
77
interceptors/logging/interceptor.go
Normal file
77
interceptors/logging/interceptor.go
Normal 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...)
|
||||
},
|
||||
)
|
||||
}
|
@ -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 {
|
||||
|
59
interceptors/metrics/options.go
Normal file
59
interceptors/metrics/options.go
Normal 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
|
||||
}
|
@ -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...)
|
||||
}
|
||||
|
Reference in New Issue
Block a user