gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

stdr.go (4855B)


      1 /*
      2 Copyright 2019 The logr Authors.
      3 
      4 Licensed under the Apache License, Version 2.0 (the "License");
      5 you may not use this file except in compliance with the License.
      6 You may obtain a copy of the License at
      7 
      8     http://www.apache.org/licenses/LICENSE-2.0
      9 
     10 Unless required by applicable law or agreed to in writing, software
     11 distributed under the License is distributed on an "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 See the License for the specific language governing permissions and
     14 limitations under the License.
     15 */
     16 
     17 // Package stdr implements github.com/go-logr/logr.Logger in terms of
     18 // Go's standard log package.
     19 package stdr
     20 
     21 import (
     22 	"log"
     23 	"os"
     24 
     25 	"github.com/go-logr/logr"
     26 	"github.com/go-logr/logr/funcr"
     27 )
     28 
     29 // The global verbosity level.  See SetVerbosity().
     30 var globalVerbosity int
     31 
     32 // SetVerbosity sets the global level against which all info logs will be
     33 // compared.  If this is greater than or equal to the "V" of the logger, the
     34 // message will be logged.  A higher value here means more logs will be written.
     35 // The previous verbosity value is returned.  This is not concurrent-safe -
     36 // callers must be sure to call it from only one goroutine.
     37 func SetVerbosity(v int) int {
     38 	old := globalVerbosity
     39 	globalVerbosity = v
     40 	return old
     41 }
     42 
     43 // New returns a logr.Logger which is implemented by Go's standard log package,
     44 // or something like it.  If std is nil, this will use a default logger
     45 // instead.
     46 //
     47 // Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
     48 func New(std StdLogger) logr.Logger {
     49 	return NewWithOptions(std, Options{})
     50 }
     51 
     52 // NewWithOptions returns a logr.Logger which is implemented by Go's standard
     53 // log package, or something like it.  See New for details.
     54 func NewWithOptions(std StdLogger, opts Options) logr.Logger {
     55 	if std == nil {
     56 		// Go's log.Default() is only available in 1.16 and higher.
     57 		std = log.New(os.Stderr, "", log.LstdFlags)
     58 	}
     59 
     60 	if opts.Depth < 0 {
     61 		opts.Depth = 0
     62 	}
     63 
     64 	fopts := funcr.Options{
     65 		LogCaller: funcr.MessageClass(opts.LogCaller),
     66 	}
     67 
     68 	sl := &logger{
     69 		Formatter: funcr.NewFormatter(fopts),
     70 		std:       std,
     71 	}
     72 
     73 	// For skipping our own logger.Info/Error.
     74 	sl.Formatter.AddCallDepth(1 + opts.Depth)
     75 
     76 	return logr.New(sl)
     77 }
     78 
     79 // Options carries parameters which influence the way logs are generated.
     80 type Options struct {
     81 	// Depth biases the assumed number of call frames to the "true" caller.
     82 	// This is useful when the calling code calls a function which then calls
     83 	// stdr (e.g. a logging shim to another API).  Values less than zero will
     84 	// be treated as zero.
     85 	Depth int
     86 
     87 	// LogCaller tells stdr to add a "caller" key to some or all log lines.
     88 	// Go's log package has options to log this natively, too.
     89 	LogCaller MessageClass
     90 
     91 	// TODO: add an option to log the date/time
     92 }
     93 
     94 // MessageClass indicates which category or categories of messages to consider.
     95 type MessageClass int
     96 
     97 const (
     98 	// None ignores all message classes.
     99 	None MessageClass = iota
    100 	// All considers all message classes.
    101 	All
    102 	// Info only considers info messages.
    103 	Info
    104 	// Error only considers error messages.
    105 	Error
    106 )
    107 
    108 // StdLogger is the subset of the Go stdlib log.Logger API that is needed for
    109 // this adapter.
    110 type StdLogger interface {
    111 	// Output is the same as log.Output and log.Logger.Output.
    112 	Output(calldepth int, logline string) error
    113 }
    114 
    115 type logger struct {
    116 	funcr.Formatter
    117 	std StdLogger
    118 }
    119 
    120 var _ logr.LogSink = &logger{}
    121 var _ logr.CallDepthLogSink = &logger{}
    122 
    123 func (l logger) Enabled(level int) bool {
    124 	return globalVerbosity >= level
    125 }
    126 
    127 func (l logger) Info(level int, msg string, kvList ...interface{}) {
    128 	prefix, args := l.FormatInfo(level, msg, kvList)
    129 	if prefix != "" {
    130 		args = prefix + ": " + args
    131 	}
    132 	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
    133 }
    134 
    135 func (l logger) Error(err error, msg string, kvList ...interface{}) {
    136 	prefix, args := l.FormatError(err, msg, kvList)
    137 	if prefix != "" {
    138 		args = prefix + ": " + args
    139 	}
    140 	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
    141 }
    142 
    143 func (l logger) WithName(name string) logr.LogSink {
    144 	l.Formatter.AddName(name)
    145 	return &l
    146 }
    147 
    148 func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
    149 	l.Formatter.AddValues(kvList)
    150 	return &l
    151 }
    152 
    153 func (l logger) WithCallDepth(depth int) logr.LogSink {
    154 	l.Formatter.AddCallDepth(depth)
    155 	return &l
    156 }
    157 
    158 // Underlier exposes access to the underlying logging implementation.  Since
    159 // callers only have a logr.Logger, they have to know which implementation is
    160 // in use, so this interface is less of an abstraction and more of way to test
    161 // type conversion.
    162 type Underlier interface {
    163 	GetUnderlying() StdLogger
    164 }
    165 
    166 // GetUnderlying returns the StdLogger underneath this logger.  Since StdLogger
    167 // is itself an interface, the result may or may not be a Go log.Logger.
    168 func (l logger) GetUnderlying() StdLogger {
    169 	return l.std
    170 }