statinterceptor.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package serverinterceptors
  2. import (
  3. "context"
  4. "encoding/json"
  5. "sync"
  6. "time"
  7. "github.com/zeromicro/go-zero/core/collection"
  8. "github.com/zeromicro/go-zero/core/lang"
  9. "github.com/zeromicro/go-zero/core/logx"
  10. "github.com/zeromicro/go-zero/core/stat"
  11. "github.com/zeromicro/go-zero/core/syncx"
  12. "github.com/zeromicro/go-zero/core/timex"
  13. "google.golang.org/grpc"
  14. "google.golang.org/grpc/peer"
  15. )
  16. const defaultSlowThreshold = time.Millisecond * 500
  17. var (
  18. ignoreContentMethods sync.Map
  19. slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
  20. )
  21. // StatConf defines the static configuration for stat interceptor.
  22. type StatConf struct {
  23. SlowThreshold time.Duration `json:",default=500ms"`
  24. IgnoreContentMethods []string `json:",optional"`
  25. }
  26. // DontLogContentForMethod disable logging content for given method.
  27. // Deprecated: use StatConf instead.
  28. func DontLogContentForMethod(method string) {
  29. ignoreContentMethods.Store(method, lang.Placeholder)
  30. }
  31. // SetSlowThreshold sets the slow threshold.
  32. // Deprecated: use StatConf instead.
  33. func SetSlowThreshold(threshold time.Duration) {
  34. slowThreshold.Set(threshold)
  35. }
  36. // UnaryStatInterceptor returns a func that uses given metrics to report stats.
  37. func UnaryStatInterceptor(metrics *stat.Metrics, conf StatConf) grpc.UnaryServerInterceptor {
  38. staticNotLoggingContentMethods := collection.NewSet()
  39. staticNotLoggingContentMethods.AddStr(conf.IgnoreContentMethods...)
  40. return func(ctx context.Context, req any, info *grpc.UnaryServerInfo,
  41. handler grpc.UnaryHandler) (resp any, err error) {
  42. startTime := timex.Now()
  43. defer func() {
  44. duration := timex.Since(startTime)
  45. metrics.Add(stat.Task{
  46. Duration: duration,
  47. })
  48. logDuration(ctx, info.FullMethod, req, duration,
  49. staticNotLoggingContentMethods, conf.SlowThreshold)
  50. }()
  51. return handler(ctx, req)
  52. }
  53. }
  54. func isSlow(duration, durationThreshold time.Duration) bool {
  55. return duration > slowThreshold.Load() ||
  56. (durationThreshold > 0 && duration > durationThreshold)
  57. }
  58. func logDuration(ctx context.Context, method string, req any, duration time.Duration,
  59. ignoreMethods *collection.Set, durationThreshold time.Duration) {
  60. var addr string
  61. client, ok := peer.FromContext(ctx)
  62. if ok {
  63. addr = client.Addr.String()
  64. }
  65. logger := logx.WithContext(ctx).WithDuration(duration)
  66. if !shouldLogContent(method, ignoreMethods) {
  67. if isSlow(duration, durationThreshold) {
  68. logger.Slowf("[RPC] slowcall - %s - %s", addr, method)
  69. }
  70. } else {
  71. content, err := json.Marshal(req)
  72. if err != nil {
  73. logx.WithContext(ctx).Errorf("%s - %s", addr, err.Error())
  74. } else if duration > slowThreshold.Load() {
  75. logger.Slowf("[RPC] slowcall - %s - %s - %s", addr, method, string(content))
  76. } else {
  77. logger.Infof("%s - %s - %s", addr, method, string(content))
  78. }
  79. }
  80. }
  81. func shouldLogContent(method string, ignoreMethods *collection.Set) bool {
  82. _, ok := ignoreContentMethods.Load(method)
  83. return !ok && !ignoreMethods.Contains(method)
  84. }