Skip to content

Commit ff3132f

Browse files
authored
Support writing to a named logger (#21)
1 parent 9c91e63 commit ff3132f

File tree

5 files changed

+246
-68
lines changed

5 files changed

+246
-68
lines changed

.github/workflows/go.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
name: Test
2020
strategy:
2121
matrix:
22-
go-version: [1.13.x, 1.14.x]
22+
go-version: [1.14.x, 1.15.x]
2323
platform: [ubuntu-latest, macos-latest, windows-latest]
2424
runs-on: ${{ matrix.platform }}
2525
steps:

README.md

+75-30
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,26 @@ The code inside `init` function is equivalent to the following:
5151

5252
```go
5353
func init() {
54-
err := log.NewConsole(0, log.ConsoleConfig{
55-
Level: log.LevelTrace,
56-
})
54+
err := log.NewConsole(0,
55+
log.ConsoleConfig{
56+
Level: log.LevelTrace,
57+
},
58+
)
59+
if err != nil {
60+
panic("unable to create new logger: " + err.Error())
61+
}
62+
}
63+
```
64+
65+
Or expand further:
66+
67+
```go
68+
func init() {
69+
err := log.NewConsoleWithName(log.DefaultConsoleName, 0,
70+
log.ConsoleConfig{
71+
Level: log.LevelTrace,
72+
},
73+
)
5774
if err != nil {
5875
panic("unable to create new logger: " + err.Error())
5976
}
@@ -70,9 +87,11 @@ In production, you may want to make log less verbose and be asynchronous:
7087
func init() {
7188
// The buffer size mainly depends on number of logs could be produced at the same time,
7289
// 100 is a good default.
73-
err := log.NewConsole(100, log.ConsoleConfig{
74-
Level: log.LevelInfo,
75-
})
90+
err := log.NewConsole(100,
91+
log.ConsoleConfig{
92+
Level: log.LevelInfo,
93+
},
94+
)
7695
if err != nil {
7796
panic("unable to create new logger: " + err.Error())
7897
}
@@ -94,10 +113,12 @@ func init() {
94113
if err != nil {
95114
panic("unable to create new logger: " + err.Error())
96115
}
97-
err := log.NewFile(log.FileConfig{
98-
Level: log.LevelInfo,
99-
Filename: "clog.log",
100-
})
116+
err := log.NewFile(
117+
log.FileConfig{
118+
Level: log.LevelInfo,
119+
Filename: "clog.log",
120+
},
121+
)
101122
if err != nil {
102123
panic("unable to create new logger: " + err.Error())
103124
}
@@ -106,6 +127,22 @@ func init() {
106127

107128
In this example, all logs will be printed to console, and only logs with level Info or higher (i.e. Warn, Error and Fatal) will be written into file.
108129

130+
### Write to a specific logger
131+
132+
When multiple loggers are registered, it is also possible to write logs to a special logger by giving its name.
133+
134+
```go
135+
func main() {
136+
log.TraceTo(log.DefaultConsoleName, "Hello %s!", "World")
137+
log.InfoTo(log.DefaultConsoleName, "Hello %s!", "World")
138+
log.WarnTo(log.DefaultConsoleName, "Hello %s!", "World")
139+
log.ErrorTo(log.DefaultConsoleName, "So bad... %v", err)
140+
log.FatalTo(log.DefaultConsoleName, "Boom! %v", err)
141+
142+
// ...
143+
}
144+
```
145+
109146
### Caller Location
110147

111148
When using `log.Error` and `log.Fatal` functions, the caller location is written along with logs.
@@ -134,14 +171,16 @@ File logger is the single most powerful builtin logger, it has the ability to ro
134171

135172
```go
136173
func init() {
137-
err := log.NewFile(100, log.FileConfig{
138-
Level: log.LevelInfo,
139-
Filename: "clog.log",
140-
FileRotationConfig: log.FileRotationConfig {
141-
Rotate: true,
142-
Daily: true,
143-
},
144-
})
174+
err := log.NewFile(100,
175+
log.FileConfig{
176+
Level: log.LevelInfo,
177+
Filename: "clog.log",
178+
FileRotationConfig: log.FileRotationConfig {
179+
Rotate: true,
180+
Daily: true,
181+
},
182+
},
183+
)
145184
if err != nil {
146185
panic("unable to create new logger: " + err.Error())
147186
}
@@ -152,10 +191,12 @@ In case you have some other packages that write to a file, and you want to take
152191

153192
```go
154193
func init() {
155-
w, err := log.NewFileWriter("filename", log.FileRotationConfig{
156-
Rotate: true,
157-
Daily: true,
158-
})
194+
w, err := log.NewFileWriter("filename",
195+
log.FileRotationConfig{
196+
Rotate: true,
197+
Daily: true,
198+
},
199+
)
159200
if err != nil {
160201
panic("unable to create new logger: " + err.Error())
161202
}
@@ -168,10 +209,12 @@ Slack logger is also supported in a simple way:
168209

169210
```go
170211
func init() {
171-
err := log.NewSlack(100, log.SlackConfig{
172-
Level: log.LevelInfo,
173-
URL: "https://url-to-slack-webhook",
174-
})
212+
err := log.NewSlack(100,
213+
log.SlackConfig{
214+
Level: log.LevelInfo,
215+
URL: "https://url-to-slack-webhook",
216+
},
217+
)
175218
if err != nil {
176219
panic("unable to create new logger: " + err.Error())
177220
}
@@ -186,10 +229,12 @@ Discord logger is supported in rich format via [Embed Object](https://discordapp
186229

187230
```go
188231
func init() {
189-
err := log.NewDiscord(100, log.DiscordConfig{
190-
Level: log.LevelInfo,
191-
URL: "https://url-to-discord-webhook",
192-
})
232+
err := log.NewDiscord(100,
233+
log.DiscordConfig{
234+
Level: log.LevelInfo,
235+
URL: "https://url-to-discord-webhook",
236+
},
237+
)
193238
if err != nil {
194239
panic("unable to create new logger: " + err.Error())
195240
}

clog.go

+46-4
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ func Fatal(format string, v ...interface{}) {
7070
// In test environment, Fatal or FatalDepth won't stop the manager or exit the program.
7171
var isTestEnv = false
7272

73-
// FatalDepth writes formatted log with given skip depth in Fatal level then exits.
74-
func FatalDepth(skip int, format string, v ...interface{}) {
75-
mgr.write(LevelFatal, skip, format, v...)
76-
73+
func exit() {
7774
if isTestEnv {
7875
return
7976
}
@@ -82,6 +79,51 @@ func FatalDepth(skip int, format string, v ...interface{}) {
8279
os.Exit(1)
8380
}
8481

82+
// FatalDepth writes formatted log with given skip depth in Fatal level then exits.
83+
func FatalDepth(skip int, format string, v ...interface{}) {
84+
mgr.write(LevelFatal, skip, format, v...)
85+
exit()
86+
}
87+
88+
// TraceTo writes formatted log in Trace level to the logger with given name.
89+
func TraceTo(name, format string, v ...interface{}) {
90+
mgr.writeTo(name, LevelTrace, 0, format, v...)
91+
}
92+
93+
// InfoTo writes formatted log in Info level to the logger with given name.
94+
func InfoTo(name, format string, v ...interface{}) {
95+
mgr.writeTo(name, LevelInfo, 0, format, v...)
96+
}
97+
98+
// WarnTo writes formatted log in Warn level to the logger with given name.
99+
func WarnTo(name, format string, v ...interface{}) {
100+
mgr.writeTo(name, LevelWarn, 0, format, v...)
101+
}
102+
103+
// ErrorTo writes formatted log in Error level to the logger with given name.
104+
func ErrorTo(name, format string, v ...interface{}) {
105+
ErrorDepthTo(name, 4, format, v...)
106+
}
107+
108+
// ErrorDepthTo writes formatted log with given skip depth in Error level to
109+
// the logger with given name.
110+
func ErrorDepthTo(name string, skip int, format string, v ...interface{}) {
111+
mgr.writeTo(name, LevelError, skip, format, v...)
112+
}
113+
114+
// FatalTo writes formatted log in Fatal level to the logger with given name
115+
// then exits.
116+
func FatalTo(name, format string, v ...interface{}) {
117+
FatalDepthTo(name, 4, format, v...)
118+
}
119+
120+
// FatalDepthTo writes formatted log with given skip depth in Fatal level to
121+
// the logger with given name then exits.
122+
func FatalDepthTo(name string, skip int, format string, v ...interface{}) {
123+
mgr.writeTo(name, LevelFatal, skip, format, v...)
124+
exit()
125+
}
126+
85127
// Stop propagates cancellation to all loggers and waits for completion.
86128
// This function should always be called before exiting the program.
87129
func Stop() {

clog_test.go

+93-22
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,36 @@ func (l *chanLogger) Write(m Messager) error {
3636
return nil
3737
}
3838

39-
func Test_chanLogger(t *testing.T) {
40-
initer := func(name string, level Level) Initer {
41-
return func(_ string, vs ...interface{}) (Logger, error) {
42-
var cfg *chanConfig
43-
for i := range vs {
44-
switch v := vs[i].(type) {
45-
case chanConfig:
46-
cfg = &v
47-
}
48-
}
49-
50-
if cfg == nil {
51-
return nil, fmt.Errorf("config object with the type '%T' not found", chanConfig{})
39+
func chanLoggerIniter(name string, level Level) Initer {
40+
return func(_ string, vs ...interface{}) (Logger, error) {
41+
var cfg *chanConfig
42+
for i := range vs {
43+
switch v := vs[i].(type) {
44+
case chanConfig:
45+
cfg = &v
5246
}
47+
}
5348

54-
return &chanLogger{
55-
c: cfg.c,
56-
noopLogger: &noopLogger{
57-
name: name,
58-
level: level,
59-
},
60-
}, nil
49+
if cfg == nil {
50+
return nil, fmt.Errorf("config object with the type '%T' not found", chanConfig{})
6151
}
52+
53+
return &chanLogger{
54+
c: cfg.c,
55+
noopLogger: &noopLogger{
56+
name: name,
57+
level: level,
58+
},
59+
}, nil
6260
}
61+
}
6362

63+
func Test_chanLogger(t *testing.T) {
6464
test1 := "mode1"
65-
test1Initer := initer(test1, LevelTrace)
65+
test1Initer := chanLoggerIniter(test1, LevelTrace)
6666

6767
test2 := "mode2"
68-
test2Initer := initer(test2, LevelError)
68+
test2Initer := chanLoggerIniter(test2, LevelError)
6969

7070
c1 := make(chan string)
7171
c2 := make(chan string)
@@ -130,3 +130,74 @@ func Test_chanLogger(t *testing.T) {
130130
})
131131
}
132132
}
133+
134+
func Test_writeToNamedLogger(t *testing.T) {
135+
test1 := "alice"
136+
test1Initer := chanLoggerIniter(test1, LevelTrace)
137+
138+
test2 := "bob"
139+
test2Initer := chanLoggerIniter(test2, LevelTrace)
140+
141+
c1 := make(chan string)
142+
c2 := make(chan string)
143+
144+
defer Remove(test1)
145+
defer Remove(test2)
146+
assert.Nil(t, New(test1, test1Initer, 1, chanConfig{
147+
c: c1,
148+
}))
149+
assert.Nil(t, New(test2, test2Initer, 1, chanConfig{
150+
c: c2,
151+
}))
152+
153+
tests := []struct {
154+
name string
155+
fn func(string, string, ...interface{})
156+
containsStr1 string
157+
containsStr2 string
158+
}{
159+
{
160+
name: "trace",
161+
fn: TraceTo,
162+
containsStr1: "[TRACE] log message",
163+
containsStr2: "",
164+
},
165+
{
166+
name: "info",
167+
fn: InfoTo,
168+
containsStr1: "[ INFO] log message",
169+
containsStr2: "",
170+
},
171+
{
172+
name: "warn",
173+
fn: WarnTo,
174+
containsStr1: "[ WARN] log message",
175+
containsStr2: "",
176+
},
177+
{
178+
name: "error",
179+
fn: ErrorTo,
180+
containsStr1: "()] log message",
181+
containsStr2: "",
182+
},
183+
{
184+
name: "fatal",
185+
fn: FatalTo,
186+
containsStr1: "()] log message",
187+
containsStr2: "",
188+
},
189+
}
190+
for _, tt := range tests {
191+
t.Run(tt.name, func(t *testing.T) {
192+
assert.Equal(t, 2, mgr.len())
193+
194+
tt.fn(test1, "log message")
195+
196+
assert.Contains(t, <-c1, tt.containsStr1)
197+
198+
if tt.containsStr2 != "" {
199+
assert.Contains(t, <-c2, tt.containsStr2)
200+
}
201+
})
202+
}
203+
}

0 commit comments

Comments
 (0)