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  }