1 // Copyright (c) 2016 Uber Technologies, Inc.
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:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
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
30 "go.uber.org/zap/zapcore"
34 _stdLogDefaultDepth = 2
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"
41 _globalMu sync.RWMutex
43 _globalS = _globalL.Sugar()
46 // L returns the global Logger, which can be reconfigured with ReplaceGlobals.
47 // It's safe for concurrent use.
55 // S returns the global SugaredLogger, which can be reconfigured with
56 // ReplaceGlobals. It's safe for concurrent use.
57 func S() *SugaredLogger {
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() {
70 _globalS = logger.Sugar()
72 return func() { ReplaceGlobals(prev) }
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))
81 return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
84 // NewStdLogAt returns *log.Logger which writes to supplied zap logger at
86 func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
87 logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
88 logFunc, err := levelToFunc(logger, level)
92 return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
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.
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)
105 // Can't get here, since passing InfoLevel to redirectStdLogAt always
107 panic(fmt.Sprintf(_programmerErrorTemplate, err))
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.
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)
123 func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
125 prefix := log.Prefix()
128 logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
129 logFunc, err := levelToFunc(logger, level)
133 log.SetOutput(&loggerWriter{logFunc})
136 log.SetPrefix(prefix)
137 log.SetOutput(os.Stderr)
141 func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
144 return logger.Debug, nil
146 return logger.Info, nil
148 return logger.Warn, nil
150 return logger.Error, nil
152 return logger.DPanic, nil
154 return logger.Panic, nil
156 return logger.Fatal, nil
158 return nil, fmt.Errorf("unrecognized level: %q", lvl)
161 type loggerWriter struct {
162 logFunc func(msg string, fields ...Field)
165 func (l *loggerWriter) Write(p []byte) (int, error) {
166 p = bytes.TrimSpace(p)