Skip to content

Commit

Permalink
feat(rpc): Add interceptor for rpc
Browse files Browse the repository at this point in the history
-   Add middleware.Recovery, middleware.ErrorLog, middleware.ServerTracing function for rpc api

#123
  • Loading branch information
lc-1010 committed Jul 14, 2023
1 parent 7fffeb7 commit f7bd795
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 1 deletion.
25 changes: 24 additions & 1 deletion cmd/gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import (
assetfs "github.com/elazarl/go-bindata-assetfs"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/lc-1010/OneBlogService/cmd/internal/middleware"
"github.com/lc-1010/OneBlogService/global"
"github.com/lc-1010/OneBlogService/pkg/swagger"
"github.com/lc-1010/OneBlogService/pkg/tracer"
pb "github.com/lc-1010/OneBlogService/proto"
"github.com/lc-1010/OneBlogService/server"

Expand All @@ -35,6 +38,22 @@ var port string
func init() {
flag.StringVar(&port, "port", "8004", "启动端口号")
flag.Parse()
err := setupTracer()
if err != nil {
log.Fatalf("init setupTracer err:%v", err)
}
}
func setupTracer() error {
tracerProvider, err := tracer.NewJaegerTrancer(
"grpc",
"127.0.0.1",
"6831",
)
if err != nil {
return err
}
global.Tracer = tracerProvider
return nil
}

const SERVICE_NAME = "tag-service"
Expand All @@ -51,7 +70,11 @@ func grpcHandlderFunc(grpcServer *grpc.Server, otherHander http.Handler) http.Ha

func runGrpcServer() *grpc.Server {
opts := []grpc.ServerOption{
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer()),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
middleware.Recovery,
middleware.ErrorLog,
middleware.ServerTracing,
)),
}
s := grpc.NewServer(opts...)

Expand Down
101 changes: 101 additions & 0 deletions cmd/internal/middleware/server_interceptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package middleware

import (
"context"
"log"
"runtime/debug"
"time"

"github.com/lc-1010/OneBlogService/global"
"github.com/lc-1010/OneBlogService/pkg/errcode"
"github.com/lc-1010/OneBlogService/pkg/metatext"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)

func Recovery(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
defer func() {
if e := recover(); e != nil {
recoverLog := "recovery log: method:%s, message:%v, stack:%s"
log.Printf(recoverLog, info.FullMethod,
e, string(debug.Stack()[:]))
}
}()
return handler(ctx, req)
}

// ErrorLog logs any errors that occur during the execution of the grpc server handler function.
//
// ErrorLog takes in the following parameters:
// - ctx: the context.Context object that represents the request context.
// - req: the input request object of any type.
// - info: the *grpc.UnaryServerInfo object that contains information about the server and method being called.
// - handler: the grpc.UnaryHandler function that handles the request and returns a response and an error.
//
// ErrorLog returns the following values:
// - resp: the response object of any type returned by the handler function.
// - err: an error object that contains any error that occurred during the execution of the handler function.
func ErrorLog(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
resp, err := handler(ctx, req)
if err != nil {
errLog := "error log:method:%s,code :%v,messsage:%v,details:%v"
s := errcode.FromError(err)
log.Printf(errLog, info.FullMethod, s.Code(), s.Err())
}
return resp, err
}

func AccessLog(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
requestLog := "access request log:method :%s,begin_time:%d,request:%v"
beginTime := time.Now().Local().Unix()
log.Printf(requestLog, info.FullMethod, beginTime, req)

//handler process
resp, err := handler(ctx, req)

responseLog := "access response log:method:%s,begin_time:%d,end_time:%d response:%v"
endTime := time.Now().Local().Unix()
log.Printf(responseLog, info.FullMethod, beginTime, endTime, resp)
return resp, err
}

// ServerTracing applies tracing to a gRPC server handler.
//
// It takes a context.Context object, a request object of any type,
// a *grpc.UnaryServerInfo object, and a grpc.UnaryHandler function.
//
// It returns a response object of any type and an error.
func ServerTracing(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(nil)
}
// 将请求添加到 metadata
mdmap := metatext.MetadataTextMap{MD: md}
attrs := []attribute.KeyValue{}

mdmap.Set("method", info.FullMethod)
mdmap.Set("remote-addr", md.Get("x-forwarded-for")[0])

_ = mdmap.ForeachKey(func(key, val string) error {
attrs = append(attrs, attribute.String(key, val))
return nil
})

tr := global.Tracer.Tracer("grpc")
spanName := info.FullMethod
attrs = append(attrs, attribute.String("service", "flag-test-ok"))

spanOpts := []trace.SpanStartOption{
trace.WithAttributes(
attrs...,
),
}

c, span := tr.Start(ctx, spanName, spanOpts...)
defer span.End()

return handler(c, req)
}
27 changes: 27 additions & 0 deletions pkg/metatext/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package metatext

import (
"strings"

"google.golang.org/grpc/metadata"
)

type MetadataTextMap struct {
metadata.MD
}

func (m MetadataTextMap) ForeachKey(handler func(key, val string) error) error {
for k, vs := range m.MD {
for _, v := range vs {
if err := handler(k, v); err != nil {
return err
}
}
}
return nil
}

func (m MetadataTextMap) Set(key, val string) {
key = strings.ToLower(key)
m.MD.Append(key, val)
}

0 comments on commit f7bd795

Please sign in to comment.