123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /*
- 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
- }
|