podman
170 строк · 4.7 Кб
1/*
2Copyright 2019 The logr Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17// Package stdr implements github.com/go-logr/logr.Logger in terms of
18// Go's standard log package.
19package stdr
20
21import (
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().
30var 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.
37func SetVerbosity(v int) int {
38old := globalVerbosity
39globalVerbosity = v
40return 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)))
48func New(std StdLogger) logr.Logger {
49return 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.
54func NewWithOptions(std StdLogger, opts Options) logr.Logger {
55if std == nil {
56// Go's log.Default() is only available in 1.16 and higher.
57std = log.New(os.Stderr, "", log.LstdFlags)
58}
59
60if opts.Depth < 0 {
61opts.Depth = 0
62}
63
64fopts := funcr.Options{
65LogCaller: funcr.MessageClass(opts.LogCaller),
66}
67
68sl := &logger{
69Formatter: funcr.NewFormatter(fopts),
70std: std,
71}
72
73// For skipping our own logger.Info/Error.
74sl.Formatter.AddCallDepth(1 + opts.Depth)
75
76return logr.New(sl)
77}
78
79// Options carries parameters which influence the way logs are generated.
80type 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.
85Depth 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.
89LogCaller 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.
95type MessageClass int
96
97const (
98// None ignores all message classes.
99None MessageClass = iota
100// All considers all message classes.
101All
102// Info only considers info messages.
103Info
104// Error only considers error messages.
105Error
106)
107
108// StdLogger is the subset of the Go stdlib log.Logger API that is needed for
109// this adapter.
110type StdLogger interface {
111// Output is the same as log.Output and log.Logger.Output.
112Output(calldepth int, logline string) error
113}
114
115type logger struct {
116funcr.Formatter
117std StdLogger
118}
119
120var _ logr.LogSink = &logger{}
121var _ logr.CallDepthLogSink = &logger{}
122
123func (l logger) Enabled(level int) bool {
124return globalVerbosity >= level
125}
126
127func (l logger) Info(level int, msg string, kvList ...interface{}) {
128prefix, args := l.FormatInfo(level, msg, kvList)
129if prefix != "" {
130args = prefix + ": " + args
131}
132_ = l.std.Output(l.Formatter.GetDepth()+1, args)
133}
134
135func (l logger) Error(err error, msg string, kvList ...interface{}) {
136prefix, args := l.FormatError(err, msg, kvList)
137if prefix != "" {
138args = prefix + ": " + args
139}
140_ = l.std.Output(l.Formatter.GetDepth()+1, args)
141}
142
143func (l logger) WithName(name string) logr.LogSink {
144l.Formatter.AddName(name)
145return &l
146}
147
148func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
149l.Formatter.AddValues(kvList)
150return &l
151}
152
153func (l logger) WithCallDepth(depth int) logr.LogSink {
154l.Formatter.AddCallDepth(depth)
155return &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.
162type Underlier interface {
163GetUnderlying() 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.
168func (l logger) GetUnderlying() StdLogger {
169return l.std
170}
171