global.go raw

   1  // Copyright (c) 2016 Uber Technologies, Inc.
   2  //
   3  // Permission is hereby granted, free of charge, to any person obtaining a copy
   4  // of this software and associated documentation files (the "Software"), to deal
   5  // in the Software without restriction, including without limitation the rights
   6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   7  // copies of the Software, and to permit persons to whom the Software is
   8  // furnished to do so, subject to the following conditions:
   9  //
  10  // The above copyright notice and this permission notice shall be included in
  11  // all copies or substantial portions of the Software.
  12  //
  13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19  // THE SOFTWARE.
  20  
  21  package zap
  22  
  23  import (
  24  	"bytes"
  25  	"fmt"
  26  	"log"
  27  	"os"
  28  	"sync"
  29  
  30  	"go.uber.org/zap/zapcore"
  31  )
  32  
  33  const (
  34  	_stdLogDefaultDepth      = 1
  35  	_loggerWriterDepth       = 2
  36  	_programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +
  37  		"https://github.com/uber-go/zap/issues/new and reference this error: %v"
  38  )
  39  
  40  var (
  41  	_globalMu sync.RWMutex
  42  	_globalL  = NewNop()
  43  	_globalS  = _globalL.Sugar()
  44  )
  45  
  46  // L returns the global Logger, which can be reconfigured with ReplaceGlobals.
  47  // It's safe for concurrent use.
  48  func L() *Logger {
  49  	_globalMu.RLock()
  50  	l := _globalL
  51  	_globalMu.RUnlock()
  52  	return l
  53  }
  54  
  55  // S returns the global SugaredLogger, which can be reconfigured with
  56  // ReplaceGlobals. It's safe for concurrent use.
  57  func S() *SugaredLogger {
  58  	_globalMu.RLock()
  59  	s := _globalS
  60  	_globalMu.RUnlock()
  61  	return s
  62  }
  63  
  64  // ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
  65  // function to restore the original values. It's safe for concurrent use.
  66  func ReplaceGlobals(logger *Logger) func() {
  67  	_globalMu.Lock()
  68  	prev := _globalL
  69  	_globalL = logger
  70  	_globalS = logger.Sugar()
  71  	_globalMu.Unlock()
  72  	return func() { ReplaceGlobals(prev) }
  73  }
  74  
  75  // NewStdLog returns a *log.Logger which writes to the supplied zap Logger at
  76  // InfoLevel. To redirect the standard library's package-global logging
  77  // functions, use RedirectStdLog instead.
  78  func NewStdLog(l *Logger) *log.Logger {
  79  	logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
  80  	f := logger.Info
  81  	return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
  82  }
  83  
  84  // NewStdLogAt returns *log.Logger which writes to supplied zap logger at
  85  // required level.
  86  func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
  87  	logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
  88  	logFunc, err := levelToFunc(logger, level)
  89  	if err != nil {
  90  		return nil, err
  91  	}
  92  	return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
  93  }
  94  
  95  // RedirectStdLog redirects output from the standard library's package-global
  96  // logger to the supplied logger at InfoLevel. Since zap already handles caller
  97  // annotations, timestamps, etc., it automatically disables the standard
  98  // library's annotations and prefixing.
  99  //
 100  // It returns a function to restore the original prefix and flags and reset the
 101  // standard library's output to os.Stderr.
 102  func RedirectStdLog(l *Logger) func() {
 103  	f, err := redirectStdLogAt(l, InfoLevel)
 104  	if err != nil {
 105  		// Can't get here, since passing InfoLevel to redirectStdLogAt always
 106  		// works.
 107  		panic(fmt.Sprintf(_programmerErrorTemplate, err))
 108  	}
 109  	return f
 110  }
 111  
 112  // RedirectStdLogAt redirects output from the standard library's package-global
 113  // logger to the supplied logger at the specified level. Since zap already
 114  // handles caller annotations, timestamps, etc., it automatically disables the
 115  // standard library's annotations and prefixing.
 116  //
 117  // It returns a function to restore the original prefix and flags and reset the
 118  // standard library's output to os.Stderr.
 119  func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
 120  	return redirectStdLogAt(l, level)
 121  }
 122  
 123  func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
 124  	flags := log.Flags()
 125  	prefix := log.Prefix()
 126  	log.SetFlags(0)
 127  	log.SetPrefix("")
 128  	logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
 129  	logFunc, err := levelToFunc(logger, level)
 130  	if err != nil {
 131  		return nil, err
 132  	}
 133  	log.SetOutput(&loggerWriter{logFunc})
 134  	return func() {
 135  		log.SetFlags(flags)
 136  		log.SetPrefix(prefix)
 137  		log.SetOutput(os.Stderr)
 138  	}, nil
 139  }
 140  
 141  func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
 142  	switch lvl {
 143  	case DebugLevel:
 144  		return logger.Debug, nil
 145  	case InfoLevel:
 146  		return logger.Info, nil
 147  	case WarnLevel:
 148  		return logger.Warn, nil
 149  	case ErrorLevel:
 150  		return logger.Error, nil
 151  	case DPanicLevel:
 152  		return logger.DPanic, nil
 153  	case PanicLevel:
 154  		return logger.Panic, nil
 155  	case FatalLevel:
 156  		return logger.Fatal, nil
 157  	}
 158  	return nil, fmt.Errorf("unrecognized level: %q", lvl)
 159  }
 160  
 161  type loggerWriter struct {
 162  	logFunc func(msg string, fields ...Field)
 163  }
 164  
 165  func (l *loggerWriter) Write(p []byte) (int, error) {
 166  	p = bytes.TrimSpace(p)
 167  	l.logFunc(string(p))
 168  	return len(p), nil
 169  }
 170