Skip to content

Commit 3e99e98

Browse files
committed
[logger] rework Adapter interface
Simplify adapter for the future changes in named logger and stacktraces. Since not all loggers have the named variant and stacktrace addition - this functionality will be handled by the logger itself, adding these values as fields. Change-Id: Ib1ccd966ef2ffa943c2ce47ff1e882f282c62a16
1 parent bb3745f commit 3e99e98

14 files changed

Lines changed: 534 additions & 269 deletions

File tree

e/log_test.go

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,34 @@ func TestLog(t *testing.T) {
3333

3434
assert.Equal(t, []bufferadapter.LogEntry{
3535
{
36-
LoggerName: "",
37-
Level: logger.LevelError,
38-
Msg: e1.Error(),
39-
Error: nil,
40-
Fields: nil,
36+
Level: logger.LevelError,
37+
Msg: e1.Error(),
38+
Error: nil,
39+
Fields: nil,
4140
},
4241
{
43-
LoggerName: "",
44-
Level: logger.LevelWarning,
45-
Msg: e1.Error(),
46-
Error: nil,
47-
Fields: nil,
42+
Level: logger.LevelWarning,
43+
Msg: e1.Error(),
44+
Error: nil,
45+
Fields: nil,
4846
},
4947
{
50-
LoggerName: "",
51-
Level: logger.LevelInfo,
52-
Msg: e2.Error(),
53-
Error: nil,
54-
Fields: nil,
48+
Level: logger.LevelInfo,
49+
Msg: e2.Error(),
50+
Error: nil,
51+
Fields: nil,
5552
},
5653
{
57-
LoggerName: "",
58-
Level: logger.LevelDebug,
59-
Msg: e3.Reason(),
60-
Error: e1,
61-
Fields: e3.Fields(),
54+
Level: logger.LevelDebug,
55+
Msg: e3.Reason(),
56+
Error: e1,
57+
Fields: e3.Fields(),
6258
},
6359
{
64-
LoggerName: "",
65-
Level: logger.LevelTrace,
66-
Msg: e4.Reason(),
67-
Error: nil,
68-
Fields: nil,
60+
Level: logger.LevelTrace,
61+
Msg: e4.Reason(),
62+
Error: nil,
63+
Fields: nil,
6964
},
7065
}, buff.GetAll())
7166
}

logger/adapter.go

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,67 @@ import (
44
"dev.gaijin.team/go/golib/fields"
55
)
66

7-
// Adapter is an interface that allows to encapsulate any logger inside [Logger].
7+
// Adapter is an interface that allows to encapsulate any logger backend inside
8+
// [Logger].
9+
//
10+
// Adapters provide a bridge between the logger abstraction and concrete logging
11+
// implementations (zap, logrus, slog, etc.). They handle the translation of
12+
// logger's generic API calls to backend-specific operations.
13+
//
14+
// For examples of adapter implementations, see the adapters subpackages.
815
type Adapter interface {
9-
// Log logs a message with the provided level, message, optional error, and an
10-
// arbitrary number of fields.
16+
// Log logs a message with the provided level, message, optional error, and
17+
// additional fields. The level parameter is one of the logger level constants
18+
// (LevelError, LevelWarning, LevelInfo, LevelDebug, LevelTrace) or a custom
19+
// level value.
20+
//
21+
// The err parameter may be nil if no error is associated with the log message.
22+
// Adapters should handle nil errors gracefully.
23+
//
24+
// The fs parameter contains zero or more fields that should be attached to the
25+
// log entry. This may include both fields from WithFields calls and fields
26+
// passed directly to the Log call.
1127
Log(level int, msg string, err error, fs ...fields.Field)
1228

13-
// WithFields returns a logger adapter with the given fields attached to it.
29+
// WithFields returns a new adapter instance with the given fields attached.
30+
// The returned adapter should include these fields in all subsequent Log calls.
31+
//
32+
// This method must return a new adapter instance and must not modify the
33+
// original adapter.
34+
//
35+
// Rationale:
36+
//
37+
// Although it might look unnecessary to alter the adapter instead of carrying
38+
// fields in the logger itself, this design allows adapters to optimize field
39+
// handling based on their backend capabilities.
40+
//
41+
// Some logging backends may support efficient field storage and reuse, while
42+
// others may require fields to be passed with each log call. For example zap
43+
// pre-encodes fields and then reuses encoded values, instead of encoding them
44+
// each time a log entry is created.
45+
//
46+
// By attaching fields to the adapter, we enable adapters to implement the
47+
// most efficient strategy for their backend.
1448
WithFields(fs ...fields.Field) Adapter
1549

16-
// WithName returns a logger adapter with the given name attached to it.
17-
WithName(name string) Adapter
18-
19-
// WithStackTrace returns a logger adapter with the stack trace attached to it.
20-
WithStackTrace(trace string) Adapter
21-
22-
// Flush all logs to the output. It is a no-op for non-buffered loggers.
50+
// Flush flushes any buffered log entries to the output. This is a no-op for
51+
// non-buffered loggers.
2352
//
24-
// It is application's responsibility to call this method before it exits.
53+
// It is the application's responsibility to call [Logger.Flush] before exiting
54+
// to ensure all log entries are written. Adapters should return any errors
55+
// that occur during flushing.
2556
Flush() error
2657
}
2758

28-
// NopAdapter is a no-op logger adapter, it does nothing even if any of its
29-
// methods called.
59+
// NopAdapter is a no-op logger adapter that discards all log messages.
60+
//
61+
// This adapter is useful for testing or when logging needs to be disabled
62+
// entirely. All methods are no-ops and return immediately without performing
63+
// any work.
3064
type NopAdapter struct{}
3165

3266
func (NopAdapter) Log(int, string, error, ...fields.Field) {}
3367

3468
func (a NopAdapter) WithFields(...fields.Field) Adapter { return a }
3569

36-
func (a NopAdapter) WithName(string) Adapter { return a }
37-
38-
func (a NopAdapter) WithStackTrace(string) Adapter { return a }
39-
4070
func (NopAdapter) Flush() error { return nil }

logger/bufferadapter/adapter.go

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import (
99
)
1010

1111
type LogEntry struct {
12-
LoggerName string `exhaustruct:"optional"`
13-
Level int
14-
Msg string
15-
Error error `exhaustruct:"optional"`
16-
Fields fields.List `exhaustruct:"optional"`
12+
Level int
13+
Msg string
14+
Error error `exhaustruct:"optional"`
15+
Fields fields.List `exhaustruct:"optional"`
1716
}
1817

1918
// LogEntries is a buffer for storing log entries in memory. It is safe for
@@ -65,7 +64,6 @@ func (le *LogEntries) GetAll() []LogEntry {
6564
// [LogEntries] collection.
6665
type Adapter struct {
6766
buff *LogEntries `exhaustruct:"optional"`
68-
name string `exhaustruct:"optional"`
6967
fs fields.List `exhaustruct:"optional"`
7068
}
7169

@@ -81,11 +79,10 @@ func New() (*Adapter, *LogEntries) {
8179

8280
func (a *Adapter) Log(level int, msg string, err error, fs ...fields.Field) {
8381
e := LogEntry{
84-
LoggerName: a.name,
85-
Level: level,
86-
Msg: msg,
87-
Error: err,
88-
Fields: append(slices.Clone(a.fs), fs...),
82+
Level: level,
83+
Msg: msg,
84+
Error: err,
85+
Fields: append(slices.Clone(a.fs), fs...),
8986
}
9087

9188
a.buff.Add(e)
@@ -94,27 +91,10 @@ func (a *Adapter) Log(level int, msg string, err error, fs ...fields.Field) {
9491
func (a *Adapter) WithFields(fs ...fields.Field) logger.Adapter {
9592
return &Adapter{
9693
buff: a.buff,
97-
name: a.name,
9894
fs: append(slices.Clone(a.fs), fs...),
9995
}
10096
}
10197

102-
func (a *Adapter) WithName(name string) logger.Adapter {
103-
return &Adapter{
104-
buff: a.buff,
105-
name: name,
106-
fs: slices.Clone(a.fs),
107-
}
108-
}
109-
110-
func (a *Adapter) WithStackTrace(_ string) logger.Adapter {
111-
return &Adapter{
112-
buff: a.buff,
113-
name: a.name,
114-
fs: slices.Clone(a.fs),
115-
}
116-
}
117-
11898
func (*Adapter) Flush() error {
11999
return nil
120100
}

logger/bufferadapter/adapter_test.go

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,46 +56,26 @@ func TestAdapter(t *testing.T) {
5656
t.Parallel()
5757

5858
adapterSrc, buff := bufferadapter.New()
59-
adapter := adapterSrc.WithName("my-logger").WithFields(fields.F("foo", "bar"))
59+
adapter := adapterSrc.WithFields(fields.F("foo", "bar"))
6060

6161
require.NotSame(t, adapterSrc, adapter)
6262

6363
adapter.Log(42, "foo", nil)
6464
require.Equal(t, 1, buff.Len())
6565
assert.Equal(t, bufferadapter.LogEntry{
66-
LoggerName: "my-logger",
67-
Level: 42,
68-
Msg: "foo",
69-
Fields: fields.List{fields.F("foo", "bar")},
66+
Level: 42,
67+
Msg: "foo",
68+
Fields: fields.List{fields.F("foo", "bar")},
7069
}, buff.Get(0))
7170

7271
adapter.Log(42, "foo", nil, fields.F("baz", "qux"))
7372
require.Equal(t, 2, buff.Len())
7473
assert.Equal(t, bufferadapter.LogEntry{
75-
LoggerName: "my-logger",
76-
Level: 42,
77-
Msg: "foo",
78-
Fields: fields.List{fields.F("foo", "bar"), fields.F("baz", "qux")},
74+
Level: 42,
75+
Msg: "foo",
76+
Fields: fields.List{fields.F("foo", "bar"), fields.F("baz", "qux")},
7977
}, buff.Get(1))
8078
})
81-
82-
t.Run(".WithName()", func(t *testing.T) {
83-
t.Parallel()
84-
85-
adapterSrc, buff := bufferadapter.New()
86-
adapter := adapterSrc.WithFields(fields.F("foo", "bar")).WithName("my-logger")
87-
88-
require.NotSame(t, adapterSrc, adapter)
89-
90-
adapter.Log(42, "foo", nil)
91-
require.Equal(t, 1, buff.Len())
92-
assert.Equal(t, bufferadapter.LogEntry{
93-
LoggerName: "my-logger",
94-
Level: 42,
95-
Msg: "foo",
96-
Fields: fields.List{fields.F("foo", "bar")},
97-
}, buff.Get(0))
98-
})
9979
}
10080

10181
func TestLogEntries(t *testing.T) {

logger/logger.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const (
2020
type Logger struct {
2121
// maxLevel is a maximum log-level of logger, assuming that log-levels are
2222
// ordered from the most important to the least important, meaning the higher
23-
// log-level - the less important a log message is.
23+
// log-level value - the less important a log message is.
2424
//
2525
// In case log-level is higher than defined maximum, it won't be passed to
2626
// adapter.
@@ -146,17 +146,13 @@ func (l Logger) WithFields(fs ...fields.Field) Logger {
146146

147147
// WithStackTrace returns a new child-logger with the stack trace attached to it.
148148
func (l Logger) WithStackTrace(_ uint) Logger {
149-
//revive:disable-next-line:modifies-value-receiver
150-
l.adapter = l.adapter.WithStackTrace("")
151-
149+
// ToDo: rework the feature
152150
return l
153151
}
154152

155153
// WithName returns a new child-logger with the given name assigned to it.
156-
func (l Logger) WithName(name string) Logger {
157-
//revive:disable-next-line:modifies-value-receiver
158-
l.adapter = l.adapter.WithName(name)
159-
154+
func (l Logger) WithName(_ string) Logger {
155+
// ToDo: rework the feature
160156
return l
161157
}
162158

0 commit comments

Comments
 (0)