github.com/matrixorigin/matrixone@v1.2.0/pkg/common/log/logger.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package log
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    24  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    25  	"go.uber.org/zap"
    26  	"go.uber.org/zap/zapcore"
    27  )
    28  
    29  // GetServiceLogger returns service logger, it will using the service as the logger name, and
    30  // append FieldNameServiceUUID field to the logger
    31  func GetServiceLogger(logger *zap.Logger, service metadata.ServiceType, uuid string) *MOLogger {
    32  	return wrap(logger.
    33  		Named(fmt.Sprintf("%s-service", strings.ToLower(service.String()))).
    34  		With(zap.String(FieldNameServiceUUID, uuid)))
    35  }
    36  
    37  // GetModuleLogger returns the module logger, it will add ".module" to logger name.
    38  // e.g. if the logger's name is cn-service, module is txn, the new logger's name is
    39  // "cn-service.txn".
    40  func GetModuleLogger(logger *MOLogger, module Module) *MOLogger {
    41  	return wrap(logger.logger.Named(string(module)))
    42  }
    43  
    44  // With creates a child logger and adds structured context to it. Fields added
    45  // to the child don't affect the parent, and vice versa.
    46  func (l *MOLogger) With(fields ...zap.Field) *MOLogger {
    47  	return newMOLogger(l.logger.With(fields...), l.ctx)
    48  }
    49  
    50  // WithOptions creates a child logger with zap options.
    51  func (l *MOLogger) WithOptions(opts ...zap.Option) *MOLogger {
    52  	return newMOLogger(l.logger.WithOptions(opts...), l.ctx)
    53  }
    54  
    55  // Named adds a new path segment to the logger's name. Segments are joined by
    56  // periods. By default, Loggers are unnamed.
    57  func (l *MOLogger) Named(name string) *MOLogger {
    58  	return newMOLogger(l.logger.Named(name), l.ctx)
    59  }
    60  
    61  func (l *MOLogger) WithContext(ctx context.Context) *MOLogger {
    62  	if ctx == nil || ctx == context.TODO() || ctx == context.Background() {
    63  		panic("nil, context.TODO() and context.Background() are not supported")
    64  	}
    65  	if sc := trace.SpanFromContext(ctx).SpanContext(); trace.IsEnable() && sc.IsEmpty() {
    66  		panic("context with empty SpanContext are not supported")
    67  	}
    68  	return newMOLogger(l.logger, ctx)
    69  }
    70  
    71  func newMOLogger(logger *zap.Logger, ctx context.Context) *MOLogger {
    72  	return &MOLogger{
    73  		logger: logger,
    74  		ctx:    ctx,
    75  		m: map[int]*zap.Logger{
    76  			1: logger.WithOptions(zap.AddCallerSkip(1)),
    77  			2: logger.WithOptions(zap.AddCallerSkip(2)),
    78  			3: logger.WithOptions(zap.AddCallerSkip(3)),
    79  		},
    80  	}
    81  }
    82  
    83  // WithProcess if the current log belongs to a certain process, the process name and process ID
    84  // can be recorded. When analyzing the log, all related logs can be retrieved according to the
    85  // process ID.
    86  func (l *MOLogger) WithProcess(process Process) *MOLogger {
    87  	return l.With(zap.String(FieldNameProcess, string(process)))
    88  }
    89  
    90  // Enabled returns true if the level is enabled
    91  func (l *MOLogger) Enabled(level zapcore.Level) bool {
    92  	return l.logger.Core().Enabled(level)
    93  }
    94  
    95  // RawLogger returns the raw zap logger
    96  func (l *MOLogger) RawLogger() *zap.Logger {
    97  	return l.logger
    98  }
    99  
   100  // Info shortcuts to print info log
   101  func (l *MOLogger) Info(msg string, fields ...zap.Field) bool {
   102  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.InfoLevel).AddCallerSkip(1), fields...)
   103  }
   104  
   105  // InfoAction shortcuts to print info action log
   106  func (l *MOLogger) InfoAction(msg string, fields ...zap.Field) func() {
   107  	return l.LogAction(msg, DefaultLogOptions().WithLevel(zap.InfoLevel).AddCallerSkip(1), fields...)
   108  }
   109  
   110  // Debug shortcuts to  print debug log
   111  func (l *MOLogger) Debug(msg string, fields ...zap.Field) bool {
   112  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.DebugLevel).AddCallerSkip(1), fields...)
   113  }
   114  
   115  // InfoDebugAction shortcuts to print debug action log
   116  func (l *MOLogger) DebugAction(msg string, fields ...zap.Field) func() {
   117  	return l.LogAction(msg, DefaultLogOptions().WithLevel(zap.DebugLevel).AddCallerSkip(1), fields...)
   118  }
   119  
   120  // Error shortcuts to  print error log
   121  func (l *MOLogger) Error(msg string, fields ...zap.Field) bool {
   122  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.ErrorLevel).AddCallerSkip(1), fields...)
   123  }
   124  
   125  // Warn shortcuts to  print warn log
   126  func (l *MOLogger) Warn(msg string, fields ...zap.Field) bool {
   127  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.WarnLevel).AddCallerSkip(1), fields...)
   128  }
   129  
   130  // Panic shortcuts to  print panic log
   131  func (l *MOLogger) Panic(msg string, fields ...zap.Field) bool {
   132  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.PanicLevel).AddCallerSkip(1), fields...)
   133  }
   134  
   135  // Fatal shortcuts to print fatal log
   136  func (l *MOLogger) Fatal(msg string, fields ...zap.Field) bool {
   137  	return l.Log(msg, DefaultLogOptions().WithLevel(zap.FatalLevel).AddCallerSkip(1), fields...)
   138  }
   139  
   140  // Log is the entry point for mo log printing. Return true to indicate that the log
   141  // is being recorded by the current LogContext.
   142  func (l *MOLogger) Log(msg string, opts LogOptions, fields ...zap.Field) bool {
   143  	if l.logger == nil {
   144  		panic("missing logger")
   145  	}
   146  
   147  	for _, fiter := range filters {
   148  		if !fiter(opts) {
   149  			return false
   150  		}
   151  	}
   152  
   153  	if opts.ctx == nil {
   154  		opts.ctx = l.ctx
   155  	}
   156  
   157  	logger, has := l.m[opts.callerSkip+1]
   158  	if !has {
   159  		logger = l.logger
   160  	}
   161  	if ce := logger.Check(opts.level, msg); ce != nil {
   162  		if len(opts.fields) > 0 {
   163  			fields = append(fields, opts.fields...)
   164  		}
   165  		if opts.ctx != nil {
   166  			fields = append(fields, trace.ContextField(opts.ctx))
   167  		}
   168  
   169  		ce.Write(fields...)
   170  		return true
   171  	}
   172  	return false
   173  }
   174  
   175  // LogAction used to log an action, or generate 2 logs, the first log occurring
   176  // at the place where the call is made and the second log occurring at the end
   177  // of the function where the LogAction is called, with the additional time consuming.
   178  // e.g.:
   179  //
   180  //	func LogActionExample() {
   181  //	    defer log.Info(zapLogger).LogAction("example action")()
   182  //	}
   183  //
   184  // This method should often be used to log the elapsed time of a function and, as the
   185  // logs appear in pairs, can also be used to check whether a function has been executed.
   186  func (l *MOLogger) LogAction(action string, opts LogOptions, fields ...zap.Field) func() {
   187  	if !l.Log(action, opts.AddCallerSkip(1), fields...) {
   188  		return nothing
   189  	}
   190  	startAt := time.Now()
   191  	return func() {
   192  		fields = append(fields, zap.Duration(FieldNameCost, time.Since(startAt)))
   193  		l.Log(action, opts, fields...)
   194  	}
   195  }
   196  
   197  func wrap(logger *zap.Logger) *MOLogger {
   198  	return wrapWithContext(logger, nil)
   199  }
   200  
   201  func wrapWithContext(logger *zap.Logger, ctx context.Context) *MOLogger {
   202  	if logger == nil {
   203  		panic("zap logger is nil")
   204  	}
   205  	if ctx != nil &&
   206  		(ctx == context.TODO() || ctx == context.Background()) {
   207  		panic("TODO and Background are not supported")
   208  	}
   209  
   210  	return newMOLogger(
   211  		logger,
   212  		ctx,
   213  	)
   214  }
   215  
   216  func nothing() {}
   217  
   218  // DefaultLogOptions default log options
   219  func DefaultLogOptions() LogOptions {
   220  	return LogOptions{}
   221  }
   222  
   223  // WithContext set log trace context.
   224  func (opts LogOptions) WithContext(ctx context.Context) LogOptions {
   225  	if ctx == nil {
   226  		panic("context is nil")
   227  	}
   228  	if ctx == context.TODO() || ctx == context.Background() {
   229  		panic("TODO and Background contexts are not supported")
   230  	}
   231  	if sc := trace.SpanFromContext(ctx).SpanContext(); trace.IsEnable() && sc.IsEmpty() {
   232  		panic("context with empty SpanContext are not supported")
   233  	}
   234  
   235  	opts.ctx = ctx
   236  	return opts
   237  }
   238  
   239  // WithLevel set log print level
   240  func (opts LogOptions) WithLevel(level zapcore.Level) LogOptions {
   241  	opts.level = level
   242  	return opts
   243  }
   244  
   245  // WithSample sample print the log, using log counts as sampling frequency. First time must output.
   246  func (opts LogOptions) WithSample(sampleType SampleType) LogOptions {
   247  	opts.sampleType = sampleType
   248  	return opts
   249  }
   250  
   251  // AddCallerSkip help to show the logger real caller, by skip n call stack
   252  func (opts LogOptions) AddCallerSkip(n int) LogOptions {
   253  	opts.callerSkip += n
   254  	return opts
   255  }
   256  
   257  // WithProcess if the current log belongs to a certain process, the process name and process ID
   258  // can be recorded. When analyzing the log, all related logs can be retrieved according to the
   259  // process ID.
   260  func (opts LogOptions) WithProcess(process Process, processID string) LogOptions {
   261  	opts.fields = append(opts.fields,
   262  		zap.String(FieldNameProcess, string(process)),
   263  		zap.String(FieldNameProcessID, processID))
   264  	return opts
   265  }