| /* | |
| Copyright 2019 The logr Authors. | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| // Package stdr implements github.com/go-logr/logr.Logger in terms of | |
| // Go's standard log package. | |
| package stdr | |
| import ( | |
| "log" | |
| "os" | |
| "github.com/go-logr/logr" | |
| "github.com/go-logr/logr/funcr" | |
| ) | |
| // The global verbosity level. See SetVerbosity(). | |
| var globalVerbosity int | |
| // SetVerbosity sets the global level against which all info logs will be | |
| // compared. If this is greater than or equal to the "V" of the logger, the | |
| // message will be logged. A higher value here means more logs will be written. | |
| // The previous verbosity value is returned. This is not concurrent-safe - | |
| // callers must be sure to call it from only one goroutine. | |
| func SetVerbosity(v int) int { | |
| old := globalVerbosity | |
| globalVerbosity = v | |
| return old | |
| } | |
| // New returns a logr.Logger which is implemented by Go's standard log package, | |
| // or something like it. If std is nil, this will use a default logger | |
| // instead. | |
| // | |
| // Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile))) | |
| func New(std StdLogger) logr.Logger { | |
| return NewWithOptions(std, Options{}) | |
| } | |
| // NewWithOptions returns a logr.Logger which is implemented by Go's standard | |
| // log package, or something like it. See New for details. | |
| func NewWithOptions(std StdLogger, opts Options) logr.Logger { | |
| if std == nil { | |
| // Go's log.Default() is only available in 1.16 and higher. | |
| std = log.New(os.Stderr, "", log.LstdFlags) | |
| } | |
| if opts.Depth < 0 { | |
| opts.Depth = 0 | |
| } | |
| fopts := funcr.Options{ | |
| LogCaller: funcr.MessageClass(opts.LogCaller), | |
| } | |
| sl := &logger{ | |
| Formatter: funcr.NewFormatter(fopts), | |
| std: std, | |
| } | |
| // For skipping our own logger.Info/Error. | |
| sl.Formatter.AddCallDepth(1 + opts.Depth) | |
| return logr.New(sl) | |
| } | |
| // Options carries parameters which influence the way logs are generated. | |
| type Options struct { | |
| // Depth biases the assumed number of call frames to the "true" caller. | |
| // This is useful when the calling code calls a function which then calls | |
| // stdr (e.g. a logging shim to another API). Values less than zero will | |
| // be treated as zero. | |
| Depth int | |
| // LogCaller tells stdr to add a "caller" key to some or all log lines. | |
| // Go's log package has options to log this natively, too. | |
| LogCaller MessageClass | |
| // TODO: add an option to log the date/time | |
| } | |
| // MessageClass indicates which category or categories of messages to consider. | |
| type MessageClass int | |
| const ( | |
| // None ignores all message classes. | |
| None MessageClass = iota | |
| // All considers all message classes. | |
| All | |
| // Info only considers info messages. | |
| Info | |
| // Error only considers error messages. | |
| Error | |
| ) | |
| // StdLogger is the subset of the Go stdlib log.Logger API that is needed for | |
| // this adapter. | |
| type StdLogger interface { | |
| // Output is the same as log.Output and log.Logger.Output. | |
| Output(calldepth int, logline string) error | |
| } | |
| type logger struct { | |
| funcr.Formatter | |
| std StdLogger | |
| } | |
| var _ logr.LogSink = &logger{} | |
| var _ logr.CallDepthLogSink = &logger{} | |
| func (l logger) Enabled(level int) bool { | |
| return globalVerbosity >= level | |
| } | |
| func (l logger) Info(level int, msg string, kvList ...interface{}) { | |
| prefix, args := l.FormatInfo(level, msg, kvList) | |
| if prefix != "" { | |
| args = prefix + ": " + args | |
| } | |
| _ = l.std.Output(l.Formatter.GetDepth()+1, args) | |
| } | |
| func (l logger) Error(err error, msg string, kvList ...interface{}) { | |
| prefix, args := l.FormatError(err, msg, kvList) | |
| if prefix != "" { | |
| args = prefix + ": " + args | |
| } | |
| _ = l.std.Output(l.Formatter.GetDepth()+1, args) | |
| } | |
| func (l logger) WithName(name string) logr.LogSink { | |
| l.Formatter.AddName(name) | |
| return &l | |
| } | |
| func (l logger) WithValues(kvList ...interface{}) logr.LogSink { | |
| l.Formatter.AddValues(kvList) | |
| return &l | |
| } | |
| func (l logger) WithCallDepth(depth int) logr.LogSink { | |
| l.Formatter.AddCallDepth(depth) | |
| return &l | |
| } | |
| // Underlier exposes access to the underlying logging implementation. Since | |
| // callers only have a logr.Logger, they have to know which implementation is | |
| // in use, so this interface is less of an abstraction and more of way to test | |
| // type conversion. | |
| type Underlier interface { | |
| GetUnderlying() StdLogger | |
| } | |
| // GetUnderlying returns the StdLogger underneath this logger. Since StdLogger | |
| // is itself an interface, the result may or may not be a Go log.Logger. | |
| func (l logger) GetUnderlying() StdLogger { | |
| return l.std | |
| } |