github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/log/logger.go (about) 1 package log 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/jonboulle/clockwork" 9 10 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring" 11 ) 12 13 const ( 14 dateLayout = "2006-01-02 15:04:05.000" 15 ) 16 17 type Logger interface { 18 // Log logs the message with specified options and fields. 19 // Implementations must not in any way use slice of fields after Log returns. 20 Log(ctx context.Context, msg string, fields ...Field) 21 } 22 23 var _ Logger = (*defaultLogger)(nil) 24 25 type simpleLoggerOption interface { 26 applySimpleOption(l *defaultLogger) 27 } 28 29 func Default(w io.Writer, opts ...simpleLoggerOption) *defaultLogger { 30 l := &defaultLogger{ 31 coloring: false, 32 minLevel: INFO, 33 clock: clockwork.NewRealClock(), 34 w: w, 35 } 36 for _, opt := range opts { 37 if opt != nil { 38 opt.applySimpleOption(l) 39 } 40 } 41 42 return l 43 } 44 45 type defaultLogger struct { 46 coloring bool 47 logQuery bool 48 minLevel Level 49 clock clockwork.Clock 50 w io.Writer 51 } 52 53 func (l *defaultLogger) format(namespace []string, msg string, logLevel Level) string { 54 b := xstring.Buffer() 55 defer b.Free() 56 if l.coloring { 57 b.WriteString(logLevel.Color()) 58 } 59 b.WriteString(l.clock.Now().Format(dateLayout)) 60 b.WriteByte(' ') 61 lvl := logLevel.String() 62 if l.coloring { 63 b.WriteString(colorReset) 64 b.WriteString(logLevel.BoldColor()) 65 } 66 b.WriteString(lvl) 67 if l.coloring { 68 b.WriteString(colorReset) 69 b.WriteString(logLevel.Color()) 70 } 71 b.WriteString(" '") 72 for i, name := range namespace { 73 if i != 0 { 74 b.WriteByte('.') 75 } 76 b.WriteString(name) 77 } 78 b.WriteString("' => ") 79 b.WriteString(msg) 80 if l.coloring { 81 b.WriteString(colorReset) 82 } 83 84 return b.String() 85 } 86 87 func (l *defaultLogger) Log(ctx context.Context, msg string, fields ...Field) { 88 lvl := LevelFromContext(ctx) 89 if lvl < l.minLevel { 90 return 91 } 92 93 _, _ = io.WriteString(l.w, l.format( 94 NamesFromContext(ctx), 95 l.appendFields(msg, fields...), 96 lvl, 97 )+"\n") 98 } 99 100 type wrapper struct { 101 logQuery bool 102 logger Logger 103 } 104 105 func wrapLogger(l Logger, opts ...Option) *wrapper { 106 ll := &wrapper{ 107 logger: l, 108 } 109 for _, opt := range opts { 110 if opt != nil { 111 opt.applyHolderOption(ll) 112 } 113 } 114 115 return ll 116 } 117 118 func (l *defaultLogger) appendFields(msg string, fields ...Field) string { 119 if len(fields) == 0 { 120 return msg 121 } 122 b := xstring.Buffer() 123 defer b.Free() 124 b.WriteString(msg) 125 b.WriteString(" {") 126 for i := range fields { 127 if i != 0 { 128 b.WriteByte(',') 129 } 130 fmt.Fprintf(b, `%q:%q`, fields[i].Key(), fields[i].String()) 131 } 132 b.WriteByte('}') 133 134 return b.String() 135 } 136 137 func (l *wrapper) Log(ctx context.Context, msg string, fields ...Field) { 138 l.logger.Log(ctx, msg, fields...) 139 }