Skip to content

Commit 90619c9

Browse files
committed
Add support random sample logger and update README doc
1 parent 701c575 commit 90619c9

File tree

7 files changed

+240
-12
lines changed

7 files changed

+240
-12
lines changed

README.md

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,41 @@ Current support following loggers
2020
- console logger
2121
- file logger
2222
- multi logger
23+
- sample logger
2324

2425
For example, init a file logger, to write logs.
2526

2627
```go
27-
log.InitDefaultLogger(log.NewFileLogger(log.DebugLevel, "./logs", ""))
28-
log.Debug("%s, test debug log", "hello")
29-
log.Info("%s, test info log", "hello")
30-
log.Warn("%s, test warn log", "hello")
31-
log.Error(errors.New("log err"), "%s, test error log", "hello")
32-
log.ErrorIf(errors.New("log err"), "%s, test error log", "hello")
33-
log.Log("%s, test log log", "hello")
28+
package main
29+
30+
import (
31+
"errors"
32+
33+
"github.com/no-src/log"
34+
)
35+
36+
func main() {
37+
// init default logger
38+
if logger, err := log.NewFileLogger(log.DebugLevel, "./logs", ""); err == nil {
39+
log.InitDefaultLoggerWithSample(logger, 0.6)
40+
} else {
41+
log.Error(err, "init file logger error")
42+
}
43+
defer log.Close()
44+
45+
// use default logger
46+
log.Debug("%s, test debug log", "hello")
47+
log.Info("%s, test info log", "hello")
48+
log.Warn("%s, test warn log", "hello")
49+
log.Error(errors.New("log err"), "%s, test error log", "hello")
50+
log.ErrorIf(errors.New("log err"), "%s, test error log", "hello")
51+
log.Log("%s, test log log", "hello")
52+
53+
// use default logger by random sampling
54+
log.DebugSample("[sample] %s, test debug log", "hello")
55+
log.InfoSample("[sample] %s, test info log", "hello")
56+
log.WarnSample("[sample] %s, test warn log", "hello")
57+
log.ErrorSample(errors.New("log err"), "[sample] %s,test error log", "hello")
58+
log.ErrorIfSample(errors.New("log err from ErrorIfSample"), "[sample] %s, test error log", "hello")
59+
}
3460
```

default_logger.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
package log
22

3-
var defaultLogger Logger
3+
var (
4+
defaultLogger Logger
5+
defaultSampleLogger Logger
6+
)
7+
8+
const defaultSampleRate = 1
49

510
// InitDefaultLogger init a default logger
6-
// if InitDefaultLogger is not called, default is consoleLogger with InfoLevel
11+
// if not specified, default is consoleLogger with InfoLevel, and default sample rate is 1
712
func InitDefaultLogger(logger Logger) {
13+
InitDefaultLoggerWithSample(logger, defaultSampleRate)
14+
}
15+
16+
// InitDefaultLoggerWithSample init a default logger and sample logger
17+
// if not specified, default is consoleLogger with InfoLevel, and default sample rate is 1
18+
func InitDefaultLoggerWithSample(logger Logger, sampleRate float64) {
819
defaultLogger = logger
920
if defaultLogger == nil {
1021
defaultLogger = NewEmptyLogger()
1122
}
23+
defaultSampleLogger = NewDefaultSampleLogger(defaultLogger, sampleRate)
1224
}
1325

1426
// Debug write the debug log
@@ -39,6 +51,34 @@ func ErrorIf(err error, format string, args ...interface{}) error {
3951
return err
4052
}
4153

54+
// DebugSample write the debug log by random sampling
55+
func DebugSample(format string, args ...interface{}) {
56+
defaultSampleLogger.Debug(format, args...)
57+
}
58+
59+
// InfoSample write the info log by random sampling
60+
func InfoSample(format string, args ...interface{}) {
61+
defaultSampleLogger.Info(format, args...)
62+
}
63+
64+
// WarnSample write the warn log by random sampling
65+
func WarnSample(format string, args ...interface{}) {
66+
defaultSampleLogger.Warn(format, args...)
67+
}
68+
69+
// ErrorSample write the error log by random sampling
70+
func ErrorSample(err error, format string, args ...interface{}) {
71+
defaultSampleLogger.Error(err, format, args...)
72+
}
73+
74+
// ErrorIfSample write the error log by random sampling if err is not nil
75+
func ErrorIfSample(err error, format string, args ...interface{}) error {
76+
if err != nil {
77+
ErrorSample(err, format, args...)
78+
}
79+
return err
80+
}
81+
4282
// Log write the log without level
4383
func Log(format string, args ...interface{}) {
4484
defaultLogger.Log(format, args...)
@@ -55,7 +95,5 @@ func DefaultLogger() Logger {
5595
}
5696

5797
func init() {
58-
if defaultLogger == nil {
59-
defaultLogger = NewConsoleLogger(InfoLevel)
60-
}
98+
InitDefaultLogger(NewConsoleLogger(InfoLevel))
6199
}

log_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func TestLogs(t *testing.T) {
1212
Error(errors.New("log err"), "%s,test error log", "hello")
1313
ErrorIf(errors.New("log err from ErrorIf"), "%s, test error log", "hello")
1414
ErrorIf(nil, "%s, this error log will not be printed", "hello")
15+
testSampleLogs()
1516
Log("%s, test log log", "hello")
1617
Log("%s, test log log again", "world")
1718
DefaultLogger().Write([]byte(""))

sample/sample.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package sample
2+
3+
import (
4+
"math/rand"
5+
"time"
6+
)
7+
8+
// SampleFunc the random sample function
9+
type SampleFunc func(rate float64) bool
10+
11+
var random = rand.New(rand.NewSource(time.Now().UnixNano()))
12+
13+
// DefaultSampleFunc the default random sample function
14+
var DefaultSampleFunc = func(rate float64) bool {
15+
if rate < 0 {
16+
rate = 0
17+
} else if rate > 1 {
18+
rate = 1
19+
}
20+
return random.Float64() <= rate
21+
}

sample/sample_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package sample
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestDefaultSampleFunc(t *testing.T) {
8+
testCases := []struct {
9+
name string
10+
total int
11+
rate float64
12+
}{
13+
{"sample rate -1", 1000, -1},
14+
{"sample rate 0", 1000, 0},
15+
{"sample rate 0.1", 1000, 0.1},
16+
{"sample rate 0.2", 1000, 0.2},
17+
{"sample rate 0.3", 1000, 0.3},
18+
{"sample rate 0.4", 1000, 0.4},
19+
{"sample rate 0.5", 1000, 0.5},
20+
{"sample rate 0.6", 1000, 0.6},
21+
{"sample rate 0.7", 1000, 0.7},
22+
{"sample rate 0.8", 1000, 0.8},
23+
{"sample rate 0.9", 1000, 0.9},
24+
{"sample rate 1", 1000, 1},
25+
{"sample rate 2", 1000, 2},
26+
}
27+
28+
for _, tc := range testCases {
29+
t.Run(tc.name, func(t *testing.T) {
30+
y := 0
31+
n := 0
32+
for i := 0; i < tc.total; i++ {
33+
if DefaultSampleFunc(tc.rate) {
34+
y++
35+
} else {
36+
n++
37+
}
38+
}
39+
t.Logf("[DefaultSampleFunc] total:%d rate:%.2f hit rate:%.2f hit:%d miss:%d", tc.total, tc.rate, float64(y)/float64(tc.total), y, n)
40+
})
41+
}
42+
}

sample_logger.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package log
2+
3+
import "github.com/no-src/log/sample"
4+
5+
type sampleLogger struct {
6+
sampleFunc sample.SampleFunc
7+
rate float64
8+
logger Logger
9+
}
10+
11+
// NewDefaultSampleLogger get a sample logger with custom sample rate
12+
func NewDefaultSampleLogger(logger Logger, sampleRate float64) Logger {
13+
return NewSampleLogger(logger, sample.DefaultSampleFunc, sampleRate)
14+
}
15+
16+
// NewSampleLogger get a sample logger with custom sample rate and sample function
17+
func NewSampleLogger(logger Logger, sampleFunc sample.SampleFunc, sampleRate float64) Logger {
18+
l := &sampleLogger{
19+
sampleFunc: sampleFunc,
20+
rate: sampleRate,
21+
logger: logger,
22+
}
23+
return l
24+
}
25+
26+
func (l *sampleLogger) Debug(format string, args ...interface{}) {
27+
if l.sample() {
28+
l.logger.Debug(format, args...)
29+
}
30+
}
31+
32+
func (l *sampleLogger) Info(format string, args ...interface{}) {
33+
if l.sample() {
34+
l.logger.Info(format, args...)
35+
}
36+
}
37+
38+
func (l *sampleLogger) Warn(format string, args ...interface{}) {
39+
if l.sample() {
40+
l.logger.Warn(format, args...)
41+
}
42+
}
43+
44+
func (l *sampleLogger) Error(err error, format string, args ...interface{}) {
45+
if l.sample() {
46+
l.logger.Error(err, format, args...)
47+
}
48+
}
49+
50+
func (l *sampleLogger) Log(format string, args ...interface{}) {
51+
l.logger.Log(format, args...)
52+
}
53+
54+
func (l *sampleLogger) Close() error {
55+
return l.logger.Close()
56+
}
57+
58+
func (l *sampleLogger) Write(p []byte) (n int, err error) {
59+
return l.logger.Write(p)
60+
}
61+
62+
func (l *sampleLogger) sample() bool {
63+
return l.sampleFunc(l.rate)
64+
}

sample_logger_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package log
2+
3+
import (
4+
"errors"
5+
"testing"
6+
)
7+
8+
func TestSampleLogger(t *testing.T) {
9+
testCases := []struct {
10+
name string
11+
sampleRate float64
12+
}{
13+
{"sample rate less than zero", -1},
14+
{"sample rate equals zero", 0},
15+
{"normal sample rate", 0.5},
16+
{"sample rate equals one", 1},
17+
{"sample rate greater than one", 2},
18+
}
19+
20+
for _, tc := range testCases {
21+
t.Run(tc.name, func(t *testing.T) {
22+
InitDefaultLogger(NewDefaultSampleLogger(NewConsoleLogger(DebugLevel), tc.sampleRate))
23+
TestLogs(t)
24+
Close()
25+
})
26+
}
27+
}
28+
29+
func testSampleLogs() {
30+
DebugSample("[sample] %s, test debug log", "hello")
31+
InfoSample("[sample] %s, test info log", "hello")
32+
WarnSample("[sample] %s, test warn log", "hello")
33+
ErrorSample(errors.New("log err"), "[sample] %s,test error log", "hello")
34+
ErrorIfSample(errors.New("log err from ErrorIfSample"), "[sample] %s, test error log", "hello")
35+
ErrorIfSample(nil, "[sample] %s, this error log will not be printed", "hello")
36+
}

0 commit comments

Comments
 (0)