Skip to content

Commit ff0cd27

Browse files
authored
Merge pull request #9001 from thaJeztah/1.7_backport_log_improve
[release/1.7 backport] log: cleanups and improvements to decouple more from logrus
2 parents 488cd77 + 2a9ae3c commit ff0cd27

File tree

4 files changed

+146
-54
lines changed

4 files changed

+146
-54
lines changed

cmd/containerd/command/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func setLogLevel(context *cli.Context, config *srvconfig.Config) error {
357357
}
358358

359359
func setLogFormat(config *srvconfig.Config) error {
360-
f := config.Debug.Format
360+
f := log.OutputFormat(config.Debug.Format)
361361
if f == "" {
362362
f = log.TextFormat
363363
}

log/context.go

Lines changed: 108 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,27 @@
1414
limitations under the License.
1515
*/
1616

17+
// Package log provides types and functions related to logging, passing
18+
// loggers through a context, and attaching context to the logger.
19+
//
20+
// # Transitional types
21+
//
22+
// This package contains various types that are aliases for types in [logrus].
23+
// These aliases are intended for transitioning away from hard-coding logrus
24+
// as logging implementation. Consumers of this package are encouraged to use
25+
// the type-aliases from this package instead of directly using their logrus
26+
// equivalent.
27+
//
28+
// The intent is to replace these aliases with locally defined types and
29+
// interfaces once all consumers are no longer directly importing logrus
30+
// types.
31+
//
32+
// IMPORTANT: due to the transitional purpose of this package, it is not
33+
// guaranteed for the full logrus API to be provided in the future. As
34+
// outlined, these aliases are provided as a step to transition away from
35+
// a specific implementation which, as a result, exposes the full logrus API.
36+
// While no decisions have been made on the ultimate design and interface
37+
// provided by this package, we do not expect carrying "less common" features.
1738
package log
1839

1940
import (
@@ -23,98 +44,138 @@ import (
2344
"github.com/sirupsen/logrus"
2445
)
2546

26-
var (
27-
// G is an alias for GetLogger.
28-
//
29-
// We may want to define this locally to a package to get package tagged log
30-
// messages.
31-
G = GetLogger
47+
// L is an alias for the standard logger.
48+
var L = &Entry{
49+
Logger: logrus.StandardLogger(),
50+
// Default is three fields plus a little extra room.
51+
Data: make(Fields, 6),
52+
}
3253

33-
// L is an alias for the standard logger.
34-
L = logrus.NewEntry(logrus.StandardLogger())
35-
)
54+
type loggerKey struct{}
3655

37-
type (
38-
loggerKey struct{}
56+
// Fields type to pass to "WithFields".
57+
type Fields = map[string]any
3958

40-
// Fields type to pass to `WithFields`, alias from `logrus`.
41-
Fields = logrus.Fields
59+
// Entry is a logging entry. It contains all the fields passed with
60+
// [Entry.WithFields]. It's finally logged when Trace, Debug, Info, Warn,
61+
// Error, Fatal or Panic is called on it. These objects can be reused and
62+
// passed around as much as you wish to avoid field duplication.
63+
//
64+
// Entry is a transitional type, and currently an alias for [logrus.Entry].
65+
type Entry = logrus.Entry
4266

43-
// Level is a logging level
44-
Level = logrus.Level
45-
)
67+
// RFC3339NanoFixed is [time.RFC3339Nano] with nanoseconds padded using
68+
// zeros to ensure the formatted time is always the same number of
69+
// characters.
70+
const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
71+
72+
// Level is a logging level.
73+
type Level = logrus.Level
4674

75+
// Supported log levels.
4776
const (
48-
// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
49-
// ensure the formatted time is always the same number of characters.
50-
RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
77+
// TraceLevel level. Designates finer-grained informational events
78+
// than [DebugLevel].
79+
TraceLevel Level = logrus.TraceLevel
5180

52-
// TextFormat represents the text logging format
53-
TextFormat = "text"
81+
// DebugLevel level. Usually only enabled when debugging. Very verbose
82+
// logging.
83+
DebugLevel Level = logrus.DebugLevel
5484

55-
// JSONFormat represents the JSON logging format
56-
JSONFormat = "json"
85+
// InfoLevel level. General operational entries about what's going on
86+
// inside the application.
87+
InfoLevel Level = logrus.InfoLevel
5788

58-
// TraceLevel level.
59-
TraceLevel = logrus.TraceLevel
89+
// WarnLevel level. Non-critical entries that deserve eyes.
90+
WarnLevel Level = logrus.WarnLevel
6091

61-
// DebugLevel level.
62-
DebugLevel = logrus.DebugLevel
92+
// ErrorLevel level. Logs errors that should definitely be noted.
93+
// Commonly used for hooks to send errors to an error tracking service.
94+
ErrorLevel Level = logrus.ErrorLevel
6395

64-
// InfoLevel level.
65-
InfoLevel = logrus.InfoLevel
96+
// FatalLevel level. Logs and then calls "logger.Exit(1)". It exits
97+
// even if the logging level is set to Panic.
98+
FatalLevel Level = logrus.FatalLevel
99+
100+
// PanicLevel level. This is the highest level of severity. Logs and
101+
// then calls panic with the message passed to Debug, Info, ...
102+
PanicLevel Level = logrus.PanicLevel
66103
)
67104

68-
// SetLevel sets log level globally.
105+
// SetLevel sets log level globally. It returns an error if the given
106+
// level is not supported.
107+
//
108+
// level can be one of:
109+
//
110+
// - "trace" ([TraceLevel])
111+
// - "debug" ([DebugLevel])
112+
// - "info" ([InfoLevel])
113+
// - "warn" ([WarnLevel])
114+
// - "error" ([ErrorLevel])
115+
// - "fatal" ([FatalLevel])
116+
// - "panic" ([PanicLevel])
69117
func SetLevel(level string) error {
70118
lvl, err := logrus.ParseLevel(level)
71119
if err != nil {
72120
return err
73121
}
74122

75-
logrus.SetLevel(lvl)
123+
L.Logger.SetLevel(lvl)
76124
return nil
77125
}
78126

79127
// GetLevel returns the current log level.
80128
func GetLevel() Level {
81-
return logrus.GetLevel()
129+
return L.Logger.GetLevel()
82130
}
83131

84-
// SetFormat sets log output format
85-
func SetFormat(format string) error {
132+
// OutputFormat specifies a log output format.
133+
type OutputFormat string
134+
135+
// Supported log output formats.
136+
const (
137+
// TextFormat represents the text logging format.
138+
TextFormat OutputFormat = "text"
139+
140+
// JSONFormat represents the JSON logging format.
141+
JSONFormat OutputFormat = "json"
142+
)
143+
144+
// SetFormat sets the log output format ([TextFormat] or [JSONFormat]).
145+
func SetFormat(format OutputFormat) error {
86146
switch format {
87147
case TextFormat:
88-
logrus.SetFormatter(&logrus.TextFormatter{
148+
L.Logger.SetFormatter(&logrus.TextFormatter{
89149
TimestampFormat: RFC3339NanoFixed,
90150
FullTimestamp: true,
91151
})
152+
return nil
92153
case JSONFormat:
93-
logrus.SetFormatter(&logrus.JSONFormatter{
154+
L.Logger.SetFormatter(&logrus.JSONFormatter{
94155
TimestampFormat: RFC3339NanoFixed,
95156
})
157+
return nil
96158
default:
97159
return fmt.Errorf("unknown log format: %s", format)
98160
}
99-
100-
return nil
101161
}
102162

103163
// WithLogger returns a new context with the provided logger. Use in
104164
// combination with logger.WithField(s) for great effect.
105-
func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
106-
e := logger.WithContext(ctx)
107-
return context.WithValue(ctx, loggerKey{}, e)
165+
func WithLogger(ctx context.Context, logger *Entry) context.Context {
166+
return context.WithValue(ctx, loggerKey{}, logger.WithContext(ctx))
108167
}
109168

110169
// GetLogger retrieves the current logger from the context. If no logger is
111170
// available, the default logger is returned.
112-
func GetLogger(ctx context.Context) *logrus.Entry {
113-
logger := ctx.Value(loggerKey{})
171+
func GetLogger(ctx context.Context) *Entry {
172+
return G(ctx)
173+
}
114174

115-
if logger == nil {
116-
return L.WithContext(ctx)
175+
// G is a shorthand for [GetLogger].
176+
func G(ctx context.Context) *Entry {
177+
if logger := ctx.Value(loggerKey{}); logger != nil {
178+
return logger.(*Entry)
117179
}
118-
119-
return logger.(*logrus.Entry)
180+
return L.WithContext(ctx)
120181
}

log/context_test.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,46 @@ package log
1818

1919
import (
2020
"context"
21+
"reflect"
2122
"testing"
2223

23-
"github.com/stretchr/testify/assert"
24+
"github.com/sirupsen/logrus"
2425
)
2526

2627
func TestLoggerContext(t *testing.T) {
28+
const expected = "one"
2729
ctx := context.Background()
30+
ctx = WithLogger(ctx, G(ctx).WithField("test", expected))
31+
if actual := GetLogger(ctx).Data["test"]; actual != expected {
32+
t.Errorf("expected: %v, got: %v", expected, actual)
33+
}
34+
a := G(ctx)
35+
b := GetLogger(ctx)
36+
if !reflect.DeepEqual(a, b) || a != b {
37+
t.Errorf("should be the same: %+v, %+v", a, b)
38+
}
39+
}
2840

29-
ctx = WithLogger(ctx, G(ctx).WithField("test", "one"))
30-
assert.Equal(t, GetLogger(ctx).Data["test"], "one")
31-
assert.Same(t, G(ctx), GetLogger(ctx)) // these should be the same.
41+
func TestCompat(t *testing.T) {
42+
expected := Fields{
43+
"hello1": "world1",
44+
"hello2": "world2",
45+
"hello3": "world3",
46+
}
47+
48+
l := G(context.TODO())
49+
l = l.WithFields(logrus.Fields{"hello1": "world1"})
50+
l = l.WithFields(Fields{"hello2": "world2"})
51+
l = l.WithFields(map[string]any{"hello3": "world3"})
52+
if !reflect.DeepEqual(Fields(l.Data), expected) {
53+
t.Errorf("expected: (%[1]T) %+[1]v, got: (%[2]T) %+[2]v", expected, l.Data)
54+
}
55+
56+
l2 := L
57+
l2 = l2.WithFields(logrus.Fields{"hello1": "world1"})
58+
l2 = l2.WithFields(Fields{"hello2": "world2"})
59+
l2 = l2.WithFields(map[string]any{"hello3": "world3"})
60+
if !reflect.DeepEqual(Fields(l2.Data), expected) {
61+
t.Errorf("expected: (%[1]T) %+[1]v, got: (%[2]T) %+[2]v", expected, l2.Data)
62+
}
3263
}

remotes/docker/resolver.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ func requestFields(req *http.Request) log.Fields {
673673
}
674674
}
675675

676-
return log.Fields(fields)
676+
return fields
677677
}
678678

679679
func responseFields(resp *http.Response) log.Fields {
@@ -691,7 +691,7 @@ func responseFields(resp *http.Response) log.Fields {
691691
}
692692
}
693693

694-
return log.Fields(fields)
694+
return fields
695695
}
696696

697697
// IsLocalhost checks if the registry host is local.

0 commit comments

Comments
 (0)