Skip to content

Commit c71fb83

Browse files
authored
Merge pull request #24 from dl1998/implement-logrecord
Add LogRecord support
2 parents 0b00946 + c82e0e5 commit c71fb83

File tree

25 files changed

+943
-192
lines changed

25 files changed

+943
-192
lines changed

docs/architecture/diagrams/plantuml/class_diagram.plantuml

Lines changed: 101 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package pkg {
55
package common {
66
package formatter {
77
class "<<module>>" {
8-
+ EvaluatePreset(loggerName : string, logLevel : level.Level, skipCaller : int) : map[string]interface{}
8+
+ ParseKey(key : string, record : logrecord.Interface) : interface{}
99
}
1010
}
1111
package handler {
@@ -43,6 +43,7 @@ package pkg {
4343
+ Previous() : Level
4444
}
4545
class "<<module>>" {
46+
~ mapping : map[Level]string
4647
+ All : level.Level
4748
+ Trace : level.Level
4849
+ Debug : level.Level
@@ -59,19 +60,48 @@ package pkg {
5960
}
6061
"<<module>>" ..> Level : uses
6162
}
63+
package logrecord {
64+
interface Interface {
65+
+ Name() : string
66+
+ Time() : string
67+
+ Timestamp() : int64
68+
+ Level() : level.Level
69+
+ FileName() : string
70+
+ FileLine() : int
71+
}
72+
struct LogRecord implements Interface {
73+
~ name : string
74+
~ timeFormat : string
75+
~ timestamp : time.Time
76+
~ level : level.Level
77+
~ fileName : string
78+
~ fileLine : int
79+
+ Name() : string
80+
+ Time() : string
81+
+ Timestamp() : int64
82+
+ Level() : level.Level
83+
+ FileName() : string
84+
+ FileLine() : int
85+
}
86+
class "<<module>>" {
87+
+ New(name : string, level : level.Level, timeFormat : string, skipCaller : int) : *LogRecord
88+
}
89+
90+
"<<module>>" ..> LogRecord : uses
91+
}
6292
}
6393
package logger {
6494
package formatter {
6595
interface Interface {
6696
+ Template() : string
67-
+ Format(message : string, loggerName : string, logLevel : level.Level, colored : bool) : string
97+
+ Format(record : logrecord.Interface, colored : bool) : string
6898
}
6999

70100
struct Formatter implements Interface {
71101
~ template : string
72102
+ IsEqual(anotherFormatter : *Formatter) : bool
73103
+ Template() : string
74-
+ Format(message : string, loggerName : string, logLevel : level.Level, colored : bool) : string
104+
+ Format(record : logrecord.Interface, colored : bool) : string
75105
}
76106

77107
class "<<module>>" {
@@ -90,7 +120,7 @@ package pkg {
90120
+ ToLevel() level.Level
91121
+ SetToLevel(toLevel level.Level)
92122
+ Formatter() : formatter.Interface
93-
+ Write(logName : string, logLevel : level.Level, message : string, parameters : ...any)
123+
+ Write(record : logrecord.Interface)
94124
}
95125
struct Handler implements Interface {
96126
~ *handler.Handler
@@ -101,7 +131,7 @@ package pkg {
101131
+ ToLevel() : level.Level
102132
+ SetToLevel(level : level.Level)
103133
+ Formatter() : formatter.Interface
104-
+ Write(logName : string, logLevel : level.Level, message : string, parameters : ...any)
134+
+ Write(record : logrecord.Interface)
105135
}
106136
class "<<module>>" {
107137
~ osOpenFile : os.OpenFile(name : string, flag : int, perm : FileMode) : (*File, error)
@@ -116,6 +146,33 @@ package pkg {
116146

117147
"<<module>>" ..> Handler : uses
118148
}
149+
package logrecord {
150+
interface Interface {
151+
+ Name() : string
152+
+ Time() : string
153+
+ Timestamp() : int64
154+
+ Level() : level.Level
155+
+ FileName() : string
156+
+ FileLine() : int
157+
+ Message() : string
158+
}
159+
struct LogRecord implements Interface {
160+
~ *logrecord.LogRecord
161+
~ message : string
162+
+ Name() : string
163+
+ Time() : string
164+
+ Timestamp() : int64
165+
+ Level() : level.Level
166+
+ FileName() : string
167+
+ FileLine() : int
168+
+ Message() : string
169+
}
170+
class "<<module>>" {
171+
+ New(name : string, level : level.Level, timeFormat : string, message : string, parameters : []any, skipCaller : int) : *LogRecord
172+
}
173+
174+
"<<module>>" ..> LogRecord : uses
175+
}
119176
interface baseLoggerInterface {
120177
+ Log(level : level.Level, message : string, parameters : ...any)
121178
+ Name() : string
@@ -219,27 +276,27 @@ package pkg {
219276
struct baseFormatter {
220277
~ template : map[string]string
221278
+ Template() : map[string]string
222-
+ Format(loggerName : string, logLevel : level.Level, parameters : ...any) : map[string]interface{}
279+
+ Format(record : logrecord.Interface) : map[string]interface{}
223280
}
224281

225282
interface Interface {
226283
+ Template() : string
227-
+ Format(loggerName : string, logLevel : level.Level, colored : bool, parameters : ...any) : string
284+
+ Format(record : logrecord.Interface, colored : bool) : string
228285
}
229286

230287
struct JSONFormatter implements Interface {
231288
~ baseFormatter : baseInterface
232289
~ pretty : bool
233290
+ Template() : string
234-
+ Format(loggerName : string, logLevel : level.Level, colored : bool, parameters : ...any) : string
291+
+ Format(record : logrecord.Interface, colored : bool) : string
235292
}
236293

237294
struct KeyValueFormatter implements Interface {
238295
~ baseFormatter : baseInterface
239296
~ keyValueDelimiter : string
240297
~ pairSeparator : string
241298
+ Template() : string
242-
+ Format(loggerName : string, logLevel : level.Level, colored : bool, parameters : ...any) : string
299+
+ Format(record : logrecord.Interface, colored : bool) : string
243300
}
244301

245302
class "<<module>>" {
@@ -262,7 +319,7 @@ package pkg {
262319
+ ToLevel() level.Level
263320
+ SetToLevel(toLevel level.Level)
264321
+ Formatter() : formatter.Interface
265-
+ Write(logName : string, logLevel : level.Level, parameters : ...any)
322+
+ Write(record : logrecord.Interface)
266323
}
267324

268325
struct Handler implements Interface {
@@ -274,7 +331,7 @@ package pkg {
274331
+ ToLevel() : level.Level
275332
+ SetToLevel(level : level.Level)
276333
+ Formatter() : formatter.Interface
277-
+ Write(logName : string, logLevel : level.Level, parameters : ...any)
334+
+ Write(record : logrecord.Interface)
278335
}
279336

280337
class "<<module>>" {
@@ -289,6 +346,33 @@ package pkg {
289346

290347
"<<module>>" ..> Handler : uses
291348
}
349+
package logrecord {
350+
interface Interface {
351+
+ Name() : string
352+
+ Time() : string
353+
+ Timestamp() : int64
354+
+ Level() : level.Level
355+
+ FileName() : string
356+
+ FileLine() : int
357+
+ Parameters() : map[string]interface{}
358+
}
359+
struct LogRecord implements Interface {
360+
~ *logrecord.LogRecord
361+
~ parameters : map[string]interface{}
362+
+ Name() : string
363+
+ Time() : string
364+
+ Timestamp() : int64
365+
+ Level() : level.Level
366+
+ FileName() : string
367+
+ FileLine() : int
368+
+ Parameters() : map[string]interface{}
369+
}
370+
class "<<module>>" {
371+
+ New(name : string, level : level.Level, timeFormat : string, parameters : map[string]interface{}, skipCaller : int) : *LogRecord
372+
}
373+
374+
"<<module>>" ..> LogRecord : uses
375+
}
292376
interface baseLoggerInterface {
293377
+ Log(level : level.Level, parameters : ...any)
294378
+ Name() : string
@@ -358,7 +442,7 @@ package pkg {
358442
~ rootLogger : *Logger
359443
~ fromLevel : level.Level
360444
~ toLevel : level.Level
361-
~ template : string
445+
~ template : map[string]string
362446
~ init()
363447
+ New(name : string) : *Logger
364448
+ WithFromLevel(fromLevel : level.Level) : Option
@@ -397,6 +481,7 @@ package pkg {
397481
}
398482
}
399483

484+
"pkg.common.formatter.<<module>>" ..> "pkg.common.logrecord.Interface" : uses
400485
pkg.common.handler.Handler *-- pkg.common.level.Level : contains
401486
pkg.logger.handler.Handler *-- pkg.common.handler.Handler : contains
402487
pkg.logger.handler.Handler *-- pkg.logger.formatter.Interface : contains
@@ -406,6 +491,10 @@ pkg.structuredlogger.handler.Handler *-- pkg.common.handler.Handler : contains
406491
pkg.structuredlogger.handler.Handler *-- pkg.structuredlogger.formatter.Interface : contains
407492
pkg.structuredlogger.baseLogger *-- "0..*" pkg.structuredlogger.handler.Interface : contains
408493
pkg.structuredlogger.formatter.baseFormatter ..> "pkg.common.formatter.<<module>>" : uses
494+
pkg.logger.logrecord.LogRecord *-- "pkg.common.logrecord.LogRecord" : contains
495+
pkg.structuredlogger.logrecord.LogRecord *-- "pkg.common.logrecord.LogRecord" : contains
496+
pkg.logger.handler.Handler ..> pkg.logger.logrecord.Interface : uses
497+
pkg.structuredlogger.handler.Handler ..> pkg.structuredlogger.logrecord.Interface : uses
409498

410499

411500
@enduml
199 KB
Loading

docs/architecture/diagrams/svg/class_diagram.svg

Lines changed: 1 addition & 1 deletion
Loading

internal/testutils/testutils.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,19 @@ func AssertEquals[T any](t *testing.T, expected T, actual T) {
1313
t.Fatalf("\nExpected: %v\nActual: %v", expected, actual)
1414
}
1515
}
16+
17+
// AssertNil checks if the value is nil.
18+
func AssertNil(t *testing.T, value any) {
19+
t.Helper()
20+
if value != nil {
21+
t.Fatalf("\nExpected: nil\nActual: %v", value)
22+
}
23+
}
24+
25+
// AssertNotNil checks if the value is not nil.
26+
func AssertNotNil(t *testing.T, value any) {
27+
t.Helper()
28+
if value == nil {
29+
t.Fatalf("\nExpected: not nil\nActual: %v", value)
30+
}
31+
}

pkg/common/formatter/formatter.go

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,31 @@
22
package formatter
33

44
import (
5-
"github.com/dl1998/go-logging/pkg/common/level"
6-
"runtime"
7-
"time"
5+
"github.com/dl1998/go-logging/pkg/common/logrecord"
86
)
97

10-
// EvaluatePreset evaluates pre-defined set of formatting options and returns map
11-
// with mapping of the option to interpolated value.
12-
func EvaluatePreset(loggerName string, logLevel level.Level, skipCaller int) map[string]interface{} {
13-
_, functionName, functionLine, _ := runtime.Caller(skipCaller)
14-
var presets = map[string]interface{}{
15-
"%(name)": loggerName, // Logger name
16-
"%(time)": time.Now().Format(time.TimeOnly), // Current time (format: HH:MM:ss)
17-
"%(date)": time.Now().Format(time.DateOnly), // Current date (format: yyyy-mm-dd)
18-
"%(isotime)": time.Now().Format(time.RFC3339), // Current date and time (format: yyyy-mm-ddTHH:MM:ssGMT)
19-
"%(timestamp)": time.Now().Unix(), // Current timestamp
20-
"%(level)": logLevel.String(), // Logging log level name
21-
"%(levelnr)": logLevel.DigitRepresentation(), // Logging log level number
22-
"%(fname)": functionName, // Name of the function from which logger has been called
23-
"%(fline)": functionLine, // Line number from which logger has been called
8+
// ParseKey parses the key and returns the value.
9+
func ParseKey(key string, record logrecord.Interface) interface{} {
10+
var value interface{}
11+
12+
switch key {
13+
case "%(name)":
14+
value = record.Name()
15+
case "%(level)":
16+
value = record.Level().String()
17+
case "%(levelnr)":
18+
value = record.Level().DigitRepresentation()
19+
case "%(datetime)":
20+
value = record.Time()
21+
case "%(timestamp)":
22+
value = record.Timestamp()
23+
case "%(fname)":
24+
value = record.FileName()
25+
case "%(fline)":
26+
value = record.FileLine()
27+
default:
28+
value = key
2429
}
25-
return presets
30+
31+
return value
2632
}

pkg/common/formatter/formatter_test.go

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,68 @@ package formatter
44
import (
55
"github.com/dl1998/go-logging/internal/testutils"
66
"github.com/dl1998/go-logging/pkg/common/level"
7+
"github.com/dl1998/go-logging/pkg/common/logrecord"
78
"testing"
89
)
910

10-
var loggerName = "test"
11-
var loggingLevel = level.Debug
11+
var (
12+
loggerName = "test"
13+
loggingLevel = level.Debug
14+
timeFormat = ""
15+
skipCaller = 1
16+
)
17+
18+
// TestParseKey tests that ParseKey returns correct value for the key.
19+
func TestParseKey(t *testing.T) {
20+
record := logrecord.New(loggerName, loggingLevel, timeFormat, skipCaller)
1221

13-
// TestFormatter_EvaluatePreset tests that Formatter.EvaluatePreset correctly
14-
// evaluates tags.
15-
func TestEvaluatePreset(t *testing.T) {
16-
preset := EvaluatePreset(loggerName, loggingLevel, 1)
22+
tests := map[string]struct {
23+
key string
24+
expected interface{}
25+
}{
26+
"Name": {key: "%(name)", expected: loggerName},
27+
"Level name": {key: "%(level)", expected: loggingLevel.String()},
28+
"Level number": {key: "%(levelnr)", expected: loggingLevel.DigitRepresentation()},
29+
"Date time": {key: "%(datetime)", expected: record.Time()},
30+
"Timestamp": {key: "%(timestamp)", expected: record.Timestamp()},
31+
"Function name": {key: "%(fname)", expected: record.FileName()},
32+
"Function line": {key: "%(fline)", expected: record.FileLine()},
33+
"Not a key": {key: "not a key", expected: "not a key"},
34+
}
1735

18-
testutils.AssertEquals(t, loggerName, preset["%(name)"].(string))
19-
testutils.AssertEquals(t, loggingLevel.String(), preset["%(level)"].(string))
36+
for name, test := range tests {
37+
t.Run(name, func(t *testing.T) {
38+
value := ParseKey(test.key, record)
39+
40+
testutils.AssertEquals(t, test.expected, value)
41+
})
42+
}
2043
}
2144

22-
// BenchmarkFormatter_EvaluatePreset performs benchmarking of the Formatter.EvaluatePreset().
23-
func BenchmarkEvaluatePreset(b *testing.B) {
24-
for index := 0; index < b.N; index++ {
25-
EvaluatePreset(loggerName, loggingLevel, 1)
45+
// BenchmarkParseKey performs benchmarking of the ParseKey().
46+
func BenchmarkParseKey(b *testing.B) {
47+
record := logrecord.New(loggerName, loggingLevel, timeFormat, skipCaller)
48+
49+
benchmarks := map[string]struct {
50+
key string
51+
}{
52+
"Name": {key: "%(name)"},
53+
"Level name": {key: "%(level)"},
54+
"Level number": {key: "%(levelnr)"},
55+
"Date time": {key: "%(datetime)"},
56+
"Timestamp": {key: "%(timestamp)"},
57+
"Function name": {key: "%(fname)"},
58+
"Function line": {key: "%(fline)"},
59+
"Not a key": {key: "not a key"},
60+
}
61+
62+
for name, benchmark := range benchmarks {
63+
b.Run(name, func(b *testing.B) {
64+
b.ResetTimer()
65+
66+
for index := 0; index < b.N; index++ {
67+
ParseKey(benchmark.key, record)
68+
}
69+
})
2670
}
2771
}

0 commit comments

Comments
 (0)