github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/log/log.go (about)

     1  // Copyright 2018 The gVisor Authors.
     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 implements a library for logging.
    16  //
    17  // This is separate from the standard logging package because logging may be a
    18  // high-impact activity, and therefore we wanted to provide as much flexibility
    19  // as possible in the underlying implementation.
    20  //
    21  // Note that logging should still be considered high-impact, and should not be
    22  // done in the hot path. If necessary, logging statements should be protected
    23  // with guards regarding the logging level. For example,
    24  //
    25  //	if log.IsLogging(log.Debug) {
    26  //		log.Debugf(...)
    27  //	}
    28  //
    29  // This is because the log.Debugf(...) statement alone will generate a
    30  // significant amount of garbage and churn in many cases, even if no log
    31  // message is ultimately emitted.
    32  package log
    33  
    34  import (
    35  	"fmt"
    36  	"io"
    37  	stdlog "log"
    38  	"os"
    39  	"runtime"
    40  	"sync/atomic"
    41  	"time"
    42  
    43  	"github.com/SagerNet/gvisor/pkg/linewriter"
    44  	"github.com/SagerNet/gvisor/pkg/sync"
    45  )
    46  
    47  // Level is the log level.
    48  type Level uint32
    49  
    50  // The following levels are fixed, and can never be changed. Since some control
    51  // RPCs allow for changing the level as an integer, it is only possible to add
    52  // additional levels, and the existing one cannot be removed.
    53  const (
    54  	// Warning indicates that output should always be emitted.
    55  	Warning Level = iota
    56  
    57  	// Info indicates that output should normally be emitted.
    58  	Info
    59  
    60  	// Debug indicates that output should not normally be emitted.
    61  	Debug
    62  )
    63  
    64  func (l Level) String() string {
    65  	switch l {
    66  	case Warning:
    67  		return "Warning"
    68  	case Info:
    69  		return "Info"
    70  	case Debug:
    71  		return "Debug"
    72  	default:
    73  		return fmt.Sprintf("Invalid level: %d", l)
    74  	}
    75  }
    76  
    77  // Emitter is the final destination for logs.
    78  type Emitter interface {
    79  	// Emit emits the given log statement. This allows for control over the
    80  	// timestamp used for logging.
    81  	Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{})
    82  }
    83  
    84  // Writer writes the output to the given writer.
    85  type Writer struct {
    86  	// Next is where output is written.
    87  	Next io.Writer
    88  
    89  	// mu protects fields below.
    90  	mu sync.Mutex
    91  
    92  	// errors counts failures to write log messages so it can be reported
    93  	// when writer start to work again. Needs to be accessed using atomics
    94  	// to make race detector happy because it's read outside the mutex.
    95  	errors int32
    96  }
    97  
    98  // Write writes out the given bytes, handling non-blocking sockets.
    99  func (l *Writer) Write(data []byte) (int, error) {
   100  	n := 0
   101  
   102  	for n < len(data) {
   103  		w, err := l.Next.Write(data[n:])
   104  		n += w
   105  
   106  		// Is it a non-blocking socket?
   107  		if pathErr, ok := err.(*os.PathError); ok && pathErr.Timeout() {
   108  			runtime.Gosched()
   109  			continue
   110  		}
   111  
   112  		// Some other error?
   113  		if err != nil {
   114  			l.mu.Lock()
   115  			atomic.AddInt32(&l.errors, 1)
   116  			l.mu.Unlock()
   117  			return n, err
   118  		}
   119  	}
   120  
   121  	// Do we need to end with a '\n'?
   122  	if len(data) == 0 || data[len(data)-1] != '\n' {
   123  		l.Write([]byte{'\n'})
   124  	}
   125  
   126  	// Dirty read in case there were errors (rare).
   127  	if atomic.LoadInt32(&l.errors) > 0 {
   128  		l.mu.Lock()
   129  		defer l.mu.Unlock()
   130  
   131  		// Recheck condition under lock.
   132  		if e := atomic.LoadInt32(&l.errors); e > 0 {
   133  			msg := fmt.Sprintf("\n*** Dropped %d log messages ***\n", e)
   134  			if _, err := l.Next.Write([]byte(msg)); err == nil {
   135  				atomic.StoreInt32(&l.errors, 0)
   136  			}
   137  		}
   138  	}
   139  
   140  	return n, nil
   141  }
   142  
   143  // Emit emits the message.
   144  func (l *Writer) Emit(_ int, _ Level, _ time.Time, format string, args ...interface{}) {
   145  	fmt.Fprintf(l, format, args...)
   146  }
   147  
   148  // MultiEmitter is an emitter that emits to multiple Emitters.
   149  type MultiEmitter []Emitter
   150  
   151  // Emit emits to all emitters.
   152  func (m *MultiEmitter) Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{}) {
   153  	for _, e := range *m {
   154  		e.Emit(1+depth, level, timestamp, format, v...)
   155  	}
   156  }
   157  
   158  // TestLogger is implemented by testing.T and testing.B.
   159  type TestLogger interface {
   160  	Logf(format string, v ...interface{})
   161  }
   162  
   163  // TestEmitter may be used for wrapping tests.
   164  type TestEmitter struct {
   165  	TestLogger
   166  }
   167  
   168  // Emit emits to the TestLogger.
   169  func (t *TestEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...interface{}) {
   170  	t.Logf(format, v...)
   171  }
   172  
   173  // Logger is a high-level logging interface. It is in fact, not used within the
   174  // log package. Rather it is provided for others to provide contextual loggers
   175  // that may append some addition information to log statement. BasicLogger
   176  // satisfies this interface, and may be passed around as a Logger.
   177  type Logger interface {
   178  	// Debugf logs a debug statement.
   179  	Debugf(format string, v ...interface{})
   180  
   181  	// Infof logs at an info level.
   182  	Infof(format string, v ...interface{})
   183  
   184  	// Warningf logs at a warning level.
   185  	Warningf(format string, v ...interface{})
   186  
   187  	// IsLogging returns true iff this level is being logged. This may be
   188  	// used to short-circuit expensive operations for debugging calls.
   189  	IsLogging(level Level) bool
   190  }
   191  
   192  // BasicLogger is the default implementation of Logger.
   193  type BasicLogger struct {
   194  	Level
   195  	Emitter
   196  }
   197  
   198  // Debugf implements logger.Debugf.
   199  func (l *BasicLogger) Debugf(format string, v ...interface{}) {
   200  	l.DebugfAtDepth(1, format, v...)
   201  }
   202  
   203  // Infof implements logger.Infof.
   204  func (l *BasicLogger) Infof(format string, v ...interface{}) {
   205  	l.InfofAtDepth(1, format, v...)
   206  }
   207  
   208  // Warningf implements logger.Warningf.
   209  func (l *BasicLogger) Warningf(format string, v ...interface{}) {
   210  	l.WarningfAtDepth(1, format, v...)
   211  }
   212  
   213  // DebugfAtDepth logs at a specific depth.
   214  func (l *BasicLogger) DebugfAtDepth(depth int, format string, v ...interface{}) {
   215  	if l.IsLogging(Debug) {
   216  		l.Emit(1+depth, Debug, time.Now(), format, v...)
   217  	}
   218  }
   219  
   220  // InfofAtDepth logs at a specific depth.
   221  func (l *BasicLogger) InfofAtDepth(depth int, format string, v ...interface{}) {
   222  	if l.IsLogging(Info) {
   223  		l.Emit(1+depth, Info, time.Now(), format, v...)
   224  	}
   225  }
   226  
   227  // WarningfAtDepth logs at a specific depth.
   228  func (l *BasicLogger) WarningfAtDepth(depth int, format string, v ...interface{}) {
   229  	if l.IsLogging(Warning) {
   230  		l.Emit(1+depth, Warning, time.Now(), format, v...)
   231  	}
   232  }
   233  
   234  // IsLogging implements logger.IsLogging.
   235  func (l *BasicLogger) IsLogging(level Level) bool {
   236  	return atomic.LoadUint32((*uint32)(&l.Level)) >= uint32(level)
   237  }
   238  
   239  // SetLevel sets the logging level.
   240  func (l *BasicLogger) SetLevel(level Level) {
   241  	atomic.StoreUint32((*uint32)(&l.Level), uint32(level))
   242  }
   243  
   244  // logMu protects Log below. We use atomic operations to read the value, but
   245  // updates require logMu to ensure consistency.
   246  var logMu sync.Mutex
   247  
   248  // log is the default logger.
   249  var log atomic.Value
   250  
   251  // Log retrieves the global logger.
   252  func Log() *BasicLogger {
   253  	return log.Load().(*BasicLogger)
   254  }
   255  
   256  // SetTarget sets the log target.
   257  //
   258  // This is not thread safe and shouldn't be called concurrently with any
   259  // logging calls.
   260  func SetTarget(target Emitter) {
   261  	logMu.Lock()
   262  	defer logMu.Unlock()
   263  	oldLog := Log()
   264  	log.Store(&BasicLogger{Level: oldLog.Level, Emitter: target})
   265  }
   266  
   267  // SetLevel sets the log level.
   268  func SetLevel(newLevel Level) {
   269  	Log().SetLevel(newLevel)
   270  }
   271  
   272  // Debugf logs to the global logger.
   273  func Debugf(format string, v ...interface{}) {
   274  	Log().DebugfAtDepth(1, format, v...)
   275  }
   276  
   277  // Infof logs to the global logger.
   278  func Infof(format string, v ...interface{}) {
   279  	Log().InfofAtDepth(1, format, v...)
   280  }
   281  
   282  // Warningf logs to the global logger.
   283  func Warningf(format string, v ...interface{}) {
   284  	Log().WarningfAtDepth(1, format, v...)
   285  }
   286  
   287  // DebugfAtDepth logs to the global logger.
   288  func DebugfAtDepth(depth int, format string, v ...interface{}) {
   289  	Log().DebugfAtDepth(1+depth, format, v...)
   290  }
   291  
   292  // InfofAtDepth logs to the global logger.
   293  func InfofAtDepth(depth int, format string, v ...interface{}) {
   294  	Log().InfofAtDepth(1+depth, format, v...)
   295  }
   296  
   297  // WarningfAtDepth logs to the global logger.
   298  func WarningfAtDepth(depth int, format string, v ...interface{}) {
   299  	Log().WarningfAtDepth(1+depth, format, v...)
   300  }
   301  
   302  // defaultStackSize is the default buffer size to allocate for stack traces.
   303  const defaultStackSize = 1 << 16 // 64KB
   304  
   305  // maxStackSize is the maximum buffer size to allocate for stack traces.
   306  const maxStackSize = 1 << 26 // 64MB
   307  
   308  // Stacks returns goroutine stacks, like panic.
   309  func Stacks(all bool) []byte {
   310  	var trace []byte
   311  	for s := defaultStackSize; s <= maxStackSize; s *= 4 {
   312  		trace = make([]byte, s)
   313  		nbytes := runtime.Stack(trace, all)
   314  		if nbytes == s {
   315  			continue
   316  		}
   317  		return trace[:nbytes]
   318  	}
   319  	trace = append(trace, []byte("\n\n...<too large, truncated>")...)
   320  	return trace
   321  }
   322  
   323  // Traceback logs the given message and dumps a stacktrace of the current
   324  // goroutine.
   325  //
   326  // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb).
   327  func Traceback(format string, v ...interface{}) {
   328  	v = append(v, Stacks(false))
   329  	Warningf(format+":\n%s", v...)
   330  }
   331  
   332  // TracebackAll logs the given message and dumps a stacktrace of all goroutines.
   333  //
   334  // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb).
   335  func TracebackAll(format string, v ...interface{}) {
   336  	v = append(v, Stacks(true))
   337  	Warningf(format+":\n%s", v...)
   338  }
   339  
   340  // IsLogging returns whether the global logger is logging.
   341  func IsLogging(level Level) bool {
   342  	return Log().IsLogging(level)
   343  }
   344  
   345  // CopyStandardLogTo redirects the stdlib log package global output to the global
   346  // logger for the specified level.
   347  func CopyStandardLogTo(l Level) error {
   348  	var f func(string, ...interface{})
   349  
   350  	switch l {
   351  	case Debug:
   352  		f = Debugf
   353  	case Info:
   354  		f = Infof
   355  	case Warning:
   356  		f = Warningf
   357  	default:
   358  		return fmt.Errorf("unknown log level %v", l)
   359  	}
   360  
   361  	stdlog.SetOutput(linewriter.NewWriter(func(p []byte) {
   362  		// We must not retain p, but log formatting is not required to
   363  		// be synchronous (though the in-package implementations are),
   364  		// so we must make a copy.
   365  		b := make([]byte, len(p))
   366  		copy(b, p)
   367  
   368  		f("%s", b)
   369  	}))
   370  
   371  	return nil
   372  }
   373  
   374  func init() {
   375  	// Store the initial value for the log.
   376  	log.Store(&BasicLogger{Level: Info, Emitter: GoogleEmitter{&Writer{Next: os.Stderr}}})
   377  }