ctxlog.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package ctxlog
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/ydb-platform/ydb/library/go/core/log"
  6. )
  7. type ctxKey struct{}
  8. // ContextFields returns log.Fields bound with ctx.
  9. // If no fields are bound, it returns nil.
  10. func ContextFields(ctx context.Context) []log.Field {
  11. fs, _ := ctx.Value(ctxKey{}).([]log.Field)
  12. return fs
  13. }
  14. // WithFields returns a new context that is bound with given fields and based
  15. // on parent ctx.
  16. func WithFields(ctx context.Context, fields ...log.Field) context.Context {
  17. if len(fields) == 0 {
  18. return ctx
  19. }
  20. return context.WithValue(ctx, ctxKey{}, mergeFields(ContextFields(ctx), fields))
  21. }
  22. // Trace logs at Trace log level using fields both from arguments and ones that
  23. // are bound to ctx.
  24. func Trace(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  25. log.AddCallerSkip(l, 1).Trace(msg, mergeFields(ContextFields(ctx), fields)...)
  26. }
  27. // Debug logs at Debug log level using fields both from arguments and ones that
  28. // are bound to ctx.
  29. func Debug(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  30. log.AddCallerSkip(l, 1).Debug(msg, mergeFields(ContextFields(ctx), fields)...)
  31. }
  32. // Info logs at Info log level using fields both from arguments and ones that
  33. // are bound to ctx.
  34. func Info(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  35. log.AddCallerSkip(l, 1).Info(msg, mergeFields(ContextFields(ctx), fields)...)
  36. }
  37. // Warn logs at Warn log level using fields both from arguments and ones that
  38. // are bound to ctx.
  39. func Warn(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  40. log.AddCallerSkip(l, 1).Warn(msg, mergeFields(ContextFields(ctx), fields)...)
  41. }
  42. // Error logs at Error log level using fields both from arguments and ones that
  43. // are bound to ctx.
  44. func Error(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  45. log.AddCallerSkip(l, 1).Error(msg, mergeFields(ContextFields(ctx), fields)...)
  46. }
  47. // Fatal logs at Fatal log level using fields both from arguments and ones that
  48. // are bound to ctx.
  49. func Fatal(ctx context.Context, l log.Logger, msg string, fields ...log.Field) {
  50. log.AddCallerSkip(l, 1).Fatal(msg, mergeFields(ContextFields(ctx), fields)...)
  51. }
  52. // Tracef logs at Trace log level using fields that are bound to ctx.
  53. // The message is formatted using provided arguments.
  54. func Tracef(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  55. msg := fmt.Sprintf(format, args...)
  56. log.AddCallerSkip(l, 1).Trace(msg, ContextFields(ctx)...)
  57. }
  58. // Debugf logs at Debug log level using fields that are bound to ctx.
  59. // The message is formatted using provided arguments.
  60. func Debugf(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  61. msg := fmt.Sprintf(format, args...)
  62. log.AddCallerSkip(l, 1).Debug(msg, ContextFields(ctx)...)
  63. }
  64. // Infof logs at Info log level using fields that are bound to ctx.
  65. // The message is formatted using provided arguments.
  66. func Infof(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  67. msg := fmt.Sprintf(format, args...)
  68. log.AddCallerSkip(l, 1).Info(msg, ContextFields(ctx)...)
  69. }
  70. // Warnf logs at Warn log level using fields that are bound to ctx.
  71. // The message is formatted using provided arguments.
  72. func Warnf(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  73. msg := fmt.Sprintf(format, args...)
  74. log.AddCallerSkip(l, 1).Warn(msg, ContextFields(ctx)...)
  75. }
  76. // Errorf logs at Error log level using fields that are bound to ctx.
  77. // The message is formatted using provided arguments.
  78. func Errorf(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  79. msg := fmt.Sprintf(format, args...)
  80. log.AddCallerSkip(l, 1).Error(msg, ContextFields(ctx)...)
  81. }
  82. // Fatalf logs at Fatal log level using fields that are bound to ctx.
  83. // The message is formatted using provided arguments.
  84. func Fatalf(ctx context.Context, l log.Logger, format string, args ...interface{}) {
  85. msg := fmt.Sprintf(format, args...)
  86. log.AddCallerSkip(l, 1).Fatal(msg, ContextFields(ctx)...)
  87. }
  88. func mergeFields(a, b []log.Field) []log.Field {
  89. if a == nil {
  90. return b
  91. }
  92. if b == nil {
  93. return a
  94. }
  95. // NOTE: just append() here is unsafe. If a caller passed slice of fields
  96. // followed by ... with capacity greater than length, then simultaneous
  97. // logging will lead to a data race condition.
  98. //
  99. // See https://golang.org/ref/spec#Passing_arguments_to_..._parameters
  100. c := make([]log.Field, len(a)+len(b))
  101. n := copy(c, a)
  102. copy(c[n:], b)
  103. return c
  104. }