logging_logrus

Server Interceptor的json格式

  1. {
  2. "level": "info", // string logrus log levels
  3. "msg": "finished unary call", // string log message
  4. "grpc.code": "OK", // string grpc status code
  5. "grpc.method": "Ping", // string method name
  6. "grpc.service": "mwitkow.testproto.TestService", // string full name of the called service
  7. "grpc.start_time": "2006-01-02T15:04:05Z07:00", // string RFC3339 representation of the start time
  8. "grpc.request.deadline": "2006-01-02T15:04:05Z07:00", // string RFC3339 deadline of the current request if supplied
  9. "grpc.request.value": "something", // string value on the request
  10. "grpc.time_ms": 1.234, // float32 run time of the call in ms
  11. "peer.address": {
  12. "IP": "127.0.0.1", // string IP address of calling party
  13. "Port": 60216, // int port call is coming in on
  14. "Zone": "" // string peer zone for caller
  15. },
  16. "span.kind": "server", // string client | server
  17. "system": "grpc" // string
  18. "custom_field": "custom_value", // string user defined field
  19. "custom_tags.int": 1337, // int user defined tag on the ctx
  20. "custom_tags.string": "something", // string user defined tag on the ctx
  21. }

Payload Interceptor的json格式

  1. {
  2. "level": "info", // string logrus log levels
  3. "msg": "client request payload logged as grpc.request.content", // string log message
  4. "grpc.request.content": { // object content of RPC request
  5. "value": "something", // string defined by caller
  6. "sleepTimeMs": 9999 // int defined by caller
  7. },
  8. "grpc.method": "Ping", // string method being called
  9. "grpc.service": "mwitkow.testproto.TestService", // string service being called
  10. "span.kind": "client", // string client | server
  11. "system": "grpc" // string
  12. }

e1:Initialization

  1. // Logrus entry is used, allowing pre-definition of certain fields by the user.
  2. logrusEntry := logrus.NewEntry(logrusLogger)
  3. // Shared options for the logger, with a custom gRPC code to log level function.
  4. opts := []grpc_logrus.Option{
  5. grpc_logrus.WithLevels(customFunc),
  6. }
  7. // Make sure that log statements internal to gRPC library are logged using the logrus Logger as well.
  8. grpc_logrus.ReplaceGrpcLogger(logrusEntry)
  9. // Create a server, make sure we put the grpc_ctxtags context before everything else.
  10. _ = grpc.NewServer(
  11. grpc_middleware.WithUnaryServerChain(
  12. grpc_ctxtags.UnaryServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
  13. grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...),
  14. ),
  15. grpc_middleware.WithStreamServerChain(
  16. grpc_ctxtags.StreamServerInterceptor(grpc_ctxtags.WithFieldExtractor(grpc_ctxtags.CodeGenRequestFieldExtractor)),
  17. grpc_logrus.StreamServerInterceptor(logrusEntry, opts...),
  18. ),
  19. )

e2:InitializationWithDurationFieldOverride

  1. // Logrus entry is used, allowing pre-definition of certain fields by the user.
  2. logrusEntry := logrus.NewEntry(logrusLogger)
  3. // Shared options for the logger, with a custom duration to log field function.
  4. opts := []grpc_logrus.Option{
  5. grpc_logrus.WithDurationField(func(duration time.Duration) (key string, value interface{}) {
  6. return "grpc.time_ns", duration.Nanoseconds()
  7. }),
  8. }
  9. _ = grpc.NewServer(
  10. grpc_middleware.WithUnaryServerChain(
  11. grpc_ctxtags.UnaryServerInterceptor(),
  12. grpc_logrus.UnaryServerInterceptor(logrusEntry, opts...),
  13. ),
  14. grpc_middleware.WithStreamServerChain(
  15. grpc_ctxtags.StreamServerInterceptor(),
  16. grpc_logrus.StreamServerInterceptor(logrusEntry, opts...),
  17. ),
  18. )

func ReplaceGrpcLogger(logger logrus.Entry) 替换grpclog,应该在初始化就调用
func StreamClientInterceptor(entry
logrus.Entry, opts …Option) grpc.StreamClientInterceptor
func StreamServerInterceptor(entry logrus.Entry, opts …Option) grpc.StreamServerInterceptor
func UnaryClientInterceptor(entry
logrus.Entry, opts …Option) grpc.UnaryClientInterceptor
func UnaryServerInterceptor(entry *logrus.Entry, opts …Option) grpc.UnaryServerInterceptor

  1. func PayloadStreamClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.StreamClientInterceptor
  2. func PayloadStreamServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor
  3. func PayloadUnaryClientInterceptor(entry *logrus.Entry, decider grpc_logging.ClientPayloadLoggingDecider) grpc.UnaryClientInterceptor
  4. func PayloadUnaryServerInterceptor(entry *logrus.Entry, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor

type CodeToLevel

  1. type CodeToLevel func(code codes.Code) logrus.Level

func DefaultClientCodeToLevel(code codes.Code) logrus.Level
func DefaultCodeToLevel(code codes.Code) logrus.Level

type DurationToField

  1. type DurationToField func(duration time.Duration) (key string, value interface{})

type MessageProducer

自定义日志

  1. type MessageProducer func(ctx context.Context, format string, level logrus.Level, code codes.Code, err error, fields logrus.Fields)

type Option

func WithCodes(f grpc_logging.ErrorToCode) Option
func WithLevels(f CodeToLevel) Option 将grpc映射为日志等级,用于自定义
func WithDurationField(f DurationToField) Option 记录请求耗时
func WithTimestampFormat(format string) Option 自定义时间格式
func WithMessageProducer(f MessageProducer) Option
func WithDecider(f grpc_logging.Decider) Option 决策器,判断是否需要进行日志记录

  1. opts := []grpc_logrus.Option{
  2. grpc_logrus.WithDecider(func(methodFullName string, err error) bool {
  3. // will not log gRPC calls if it was a call to healthcheck and no error was raised
  4. if err == nil && methodFullName == "blah.foo.healthcheck" {
  5. return false
  6. }
  7. // by default you will log all calls
  8. return true
  9. }),
  10. }
  11. _ = []grpc.ServerOption{
  12. grpc_middleware.WithStreamServerChain(
  13. grpc_ctxtags.StreamServerInterceptor(),
  14. grpc_logrus.StreamServerInterceptor(logrus.NewEntry(logrus.New()), opts...)),
  15. grpc_middleware.WithUnaryServerChain(
  16. grpc_ctxtags.UnaryServerInterceptor(),
  17. grpc_logrus.UnaryServerInterceptor(logrus.NewEntry(logrus.New()), opts...)),
  18. }

例子:

  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/grpc-ecosystem/go-grpc-middleware"
  7. "github.com/grpc-ecosystem/go-grpc-middleware/ratelimit"
  8. juju "github.com/juju/ratelimit"
  9. logrus1 "github.com/sirupsen/logrus"
  10. "google.golang.org/grpc"
  11. "gopkg.in/natefinch/lumberjack.v2"
  12. "log"
  13. "net"
  14. pb "study/grpc/protobuf/person"
  15. "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
  16. "time"
  17. )
  18. const (
  19. port = ":8080"
  20. )
  21. type Limiter struct{
  22. Bucket *juju.Bucket
  23. }
  24. func (this *Limiter) Limit() bool {
  25. token := this.Bucket.TakeAvailable(1)
  26. fmt.Println("桶可用数量:",this.Bucket.Available())
  27. if token == 0 {
  28. return true
  29. }
  30. return false
  31. }
  32. func main() {
  33. logs :=logrus1.New()
  34. logs.Formatter = &logrus1.TextFormatter{TimestampFormat:"2006-01-02 15:04:05.999999999"}
  35. logs.Level = logrus1.InfoLevel
  36. logs.SetOutput(&lumberjack.Logger{
  37. Filename: "./log/foo.log",
  38. MaxSize: 1 , // megabytes
  39. MaxBackups: 3,
  40. MaxAge: 28, //days
  41. Compress: true, // disabled by default
  42. })
  43. logEntry := logrus1.NewEntry(logs)
  44. grpc_logrus.ReplaceGrpcLogger(logEntry)
  45. lis, err := net.Listen("tcp", port)
  46. if err != nil {
  47. log.Fatalf("failed to listen: %v", err)
  48. }
  49. limiter := &Limiter{juju.NewBucket(time.Second*2,2)}
  50. opts := grpc_middleware.WithUnaryServerChain(
  51. grpc_logrus.UnaryServerInterceptor(
  52. logEntry,
  53. grpc_logrus.WithLevels(grpc_logrus.DefaultCodeToLevel),
  54. ), // 日志
  55. ratelimit.UnaryServerInterceptor(limiter), // 限速
  56. )
  57. s := grpc.NewServer(opts) //起一个服务,注意这一的参数,如果是一元转换过来的,只能填写一个
  58. pb.RegisterPersonserverServer(s,&Server{})
  59. if err := s.Serve(lis); err != nil {
  60. log.Fatalf("failed to serve: %v", err)
  61. }
  62. }

logrus/ctxlogrus

func AddFields(ctx context.Context, fields logrus.Fields)
func Extract(ctx context.Context) *logrus.Entry

  1. ctx := context.Background()
  2. // setting tags will be added to the logger as log fields
  3. grpc_ctxtags.Extract(ctx).Set("custom_tags.string", "something").Set("custom_tags.int", 1337)
  4. // Extract a single request-scoped logrus.Logger and log messages.
  5. l := ctxlogrus.Extract(ctx)
  6. l.Info("some ping")
  7. l.Info("another ping")

func ToContext(ctx context.Context, entry *logrus.Entry) context.Context