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  }