github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/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 _, o := range opts { 37 o.applySimpleOption(l) 38 } 39 40 return l 41 } 42 43 type defaultLogger struct { 44 coloring bool 45 logQuery bool 46 minLevel Level 47 clock clockwork.Clock 48 w io.Writer 49 } 50 51 func (l *defaultLogger) format(namespace []string, msg string, logLevel Level) string { 52 b := xstring.Buffer() 53 defer b.Free() 54 if l.coloring { 55 b.WriteString(logLevel.Color()) 56 } 57 b.WriteString(l.clock.Now().Format(dateLayout)) 58 b.WriteByte(' ') 59 lvl := logLevel.String() 60 if l.coloring { 61 b.WriteString(colorReset) 62 b.WriteString(logLevel.BoldColor()) 63 } 64 b.WriteString(lvl) 65 if l.coloring { 66 b.WriteString(colorReset) 67 b.WriteString(logLevel.Color()) 68 } 69 b.WriteString(" '") 70 for i, name := range namespace { 71 if i != 0 { 72 b.WriteByte('.') 73 } 74 b.WriteString(name) 75 } 76 b.WriteString("' => ") 77 b.WriteString(msg) 78 if l.coloring { 79 b.WriteString(colorReset) 80 } 81 82 return b.String() 83 } 84 85 func (l *defaultLogger) Log(ctx context.Context, msg string, fields ...Field) { 86 lvl := LevelFromContext(ctx) 87 if lvl < l.minLevel { 88 return 89 } 90 91 _, _ = io.WriteString(l.w, l.format( 92 NamesFromContext(ctx), 93 l.appendFields(msg, fields...), 94 lvl, 95 )+"\n") 96 } 97 98 type wrapper struct { 99 logQuery bool 100 logger Logger 101 } 102 103 func wrapLogger(l Logger, opts ...Option) *wrapper { 104 ll := &wrapper{ 105 logger: l, 106 } 107 for _, o := range opts { 108 if o != nil { 109 o.applyHolderOption(ll) 110 } 111 } 112 113 return ll 114 } 115 116 func (l *defaultLogger) appendFields(msg string, fields ...Field) string { 117 if len(fields) == 0 { 118 return msg 119 } 120 b := xstring.Buffer() 121 defer b.Free() 122 b.WriteString(msg) 123 b.WriteString(" {") 124 for i := range fields { 125 if i != 0 { 126 b.WriteByte(',') 127 } 128 fmt.Fprintf(b, `%q:%q`, fields[i].Key(), fields[i].String()) 129 } 130 b.WriteByte('}') 131 132 return b.String() 133 } 134 135 func (l *wrapper) Log(ctx context.Context, msg string, fields ...Field) { 136 l.logger.Log(ctx, msg, fields...) 137 }