github.com/Laisky/zap@v1.27.0/global.go (about) 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 "github.com/Laisky/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 }