123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- // Copyright (c) 2016 Uber Technologies, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- package zap
- import (
- "bytes"
- "fmt"
- "log"
- "os"
- "sync"
- "go.uber.org/zap/zapcore"
- )
- const (
- _loggerWriterDepth = 2
- _programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +
- "https://github.com/uber-go/zap/issues/new and reference this error: %v"
- )
- var (
- _globalMu sync.RWMutex
- _globalL = NewNop()
- _globalS = _globalL.Sugar()
- )
- // L returns the global Logger, which can be reconfigured with ReplaceGlobals.
- // It's safe for concurrent use.
- func L() *Logger {
- _globalMu.RLock()
- l := _globalL
- _globalMu.RUnlock()
- return l
- }
- // S returns the global SugaredLogger, which can be reconfigured with
- // ReplaceGlobals. It's safe for concurrent use.
- func S() *SugaredLogger {
- _globalMu.RLock()
- s := _globalS
- _globalMu.RUnlock()
- return s
- }
- // ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
- // function to restore the original values. It's safe for concurrent use.
- func ReplaceGlobals(logger *Logger) func() {
- _globalMu.Lock()
- prev := _globalL
- _globalL = logger
- _globalS = logger.Sugar()
- _globalMu.Unlock()
- return func() { ReplaceGlobals(prev) }
- }
- // NewStdLog returns a *log.Logger which writes to the supplied zap Logger at
- // InfoLevel. To redirect the standard library's package-global logging
- // functions, use RedirectStdLog instead.
- func NewStdLog(l *Logger) *log.Logger {
- logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
- f := logger.Info
- return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
- }
- // NewStdLogAt returns *log.Logger which writes to supplied zap logger at
- // required level.
- func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
- logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
- logFunc, err := levelToFunc(logger, level)
- if err != nil {
- return nil, err
- }
- return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
- }
- // RedirectStdLog redirects output from the standard library's package-global
- // logger to the supplied logger at InfoLevel. Since zap already handles caller
- // annotations, timestamps, etc., it automatically disables the standard
- // library's annotations and prefixing.
- //
- // It returns a function to restore the original prefix and flags and reset the
- // standard library's output to os.Stderr.
- func RedirectStdLog(l *Logger) func() {
- f, err := redirectStdLogAt(l, InfoLevel)
- if err != nil {
- // Can't get here, since passing InfoLevel to redirectStdLogAt always
- // works.
- panic(fmt.Sprintf(_programmerErrorTemplate, err))
- }
- return f
- }
- // RedirectStdLogAt redirects output from the standard library's package-global
- // logger to the supplied logger at the specified level. Since zap already
- // handles caller annotations, timestamps, etc., it automatically disables the
- // standard library's annotations and prefixing.
- //
- // It returns a function to restore the original prefix and flags and reset the
- // standard library's output to os.Stderr.
- func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
- return redirectStdLogAt(l, level)
- }
- func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
- flags := log.Flags()
- prefix := log.Prefix()
- log.SetFlags(0)
- log.SetPrefix("")
- logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
- logFunc, err := levelToFunc(logger, level)
- if err != nil {
- return nil, err
- }
- log.SetOutput(&loggerWriter{logFunc})
- return func() {
- log.SetFlags(flags)
- log.SetPrefix(prefix)
- log.SetOutput(os.Stderr)
- }, nil
- }
- func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
- switch lvl {
- case DebugLevel:
- return logger.Debug, nil
- case InfoLevel:
- return logger.Info, nil
- case WarnLevel:
- return logger.Warn, nil
- case ErrorLevel:
- return logger.Error, nil
- case DPanicLevel:
- return logger.DPanic, nil
- case PanicLevel:
- return logger.Panic, nil
- case FatalLevel:
- return logger.Fatal, nil
- }
- return nil, fmt.Errorf("unrecognized level: %q", lvl)
- }
- type loggerWriter struct {
- logFunc func(msg string, fields ...Field)
- }
- func (l *loggerWriter) Write(p []byte) (int, error) {
- p = bytes.TrimSpace(p)
- l.logFunc(string(p))
- return len(p), nil
- }
|