// Copyright (c) 2016 Uber Technologies, Inc.1//2// Permission is hereby granted, free of charge, to any person obtaining a copy3// of this software and associated documentation files (the "Software"), to deal4// in the Software without restriction, including without limitation the rights5// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell6// copies of the Software, and to permit persons to whom the Software is7// furnished to do so, subject to the following conditions:8//9// The above copyright notice and this permission notice shall be included in10// all copies or substantial portions of the Software.11//12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,17// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN18// THE SOFTWARE.1920package zap2122import (23"bytes"24"fmt"25"log"26"os"27"sync"2829"go.uber.org/zap/zapcore"30)3132const (33_stdLogDefaultDepth = 134_loggerWriterDepth = 235_programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +36"https://github.com/uber-go/zap/issues/new and reference this error: %v"37)3839var (40_globalMu sync.RWMutex41_globalL = NewNop()42_globalS = _globalL.Sugar()43)4445// L returns the global Logger, which can be reconfigured with ReplaceGlobals.46// It's safe for concurrent use.47func L() *Logger {48_globalMu.RLock()49l := _globalL50_globalMu.RUnlock()51return l52}5354// S returns the global SugaredLogger, which can be reconfigured with55// ReplaceGlobals. It's safe for concurrent use.56func S() *SugaredLogger {57_globalMu.RLock()58s := _globalS59_globalMu.RUnlock()60return s61}6263// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a64// function to restore the original values. It's safe for concurrent use.65func ReplaceGlobals(logger *Logger) func() {66_globalMu.Lock()67prev := _globalL68_globalL = logger69_globalS = logger.Sugar()70_globalMu.Unlock()71return func() { ReplaceGlobals(prev) }72}7374// NewStdLog returns a *log.Logger which writes to the supplied zap Logger at75// InfoLevel. To redirect the standard library's package-global logging76// functions, use RedirectStdLog instead.77func NewStdLog(l *Logger) *log.Logger {78logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))79f := logger.Info80return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)81}8283// NewStdLogAt returns *log.Logger which writes to supplied zap logger at84// required level.85func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {86logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))87logFunc, err := levelToFunc(logger, level)88if err != nil {89return nil, err90}91return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil92}9394// RedirectStdLog redirects output from the standard library's package-global95// logger to the supplied logger at InfoLevel. Since zap already handles caller96// annotations, timestamps, etc., it automatically disables the standard97// library's annotations and prefixing.98//99// It returns a function to restore the original prefix and flags and reset the100// standard library's output to os.Stderr.101func RedirectStdLog(l *Logger) func() {102f, err := redirectStdLogAt(l, InfoLevel)103if err != nil {104// Can't get here, since passing InfoLevel to redirectStdLogAt always105// works.106panic(fmt.Sprintf(_programmerErrorTemplate, err))107}108return f109}110111// RedirectStdLogAt redirects output from the standard library's package-global112// logger to the supplied logger at the specified level. Since zap already113// handles caller annotations, timestamps, etc., it automatically disables the114// standard library's annotations and prefixing.115//116// It returns a function to restore the original prefix and flags and reset the117// standard library's output to os.Stderr.118func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {119return redirectStdLogAt(l, level)120}121122func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {123flags := log.Flags()124prefix := log.Prefix()125log.SetFlags(0)126log.SetPrefix("")127logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))128logFunc, err := levelToFunc(logger, level)129if err != nil {130return nil, err131}132log.SetOutput(&loggerWriter{logFunc})133return func() {134log.SetFlags(flags)135log.SetPrefix(prefix)136log.SetOutput(os.Stderr)137}, nil138}139140func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {141switch lvl {142case DebugLevel:143return logger.Debug, nil144case InfoLevel:145return logger.Info, nil146case WarnLevel:147return logger.Warn, nil148case ErrorLevel:149return logger.Error, nil150case DPanicLevel:151return logger.DPanic, nil152case PanicLevel:153return logger.Panic, nil154case FatalLevel:155return logger.Fatal, nil156}157return nil, fmt.Errorf("unrecognized level: %q", lvl)158}159160type loggerWriter struct {161logFunc func(msg string, fields ...Field)162}163164func (l *loggerWriter) Write(p []byte) (int, error) {165p = bytes.TrimSpace(p)166l.logFunc(string(p))167return len(p), nil168}169170171