Skip to content

Commit 18f5418

Browse files
committed
Added Hooks
hooks allow intercepting and modifying the fields in each log entry. Can be added globally at the factory level, or at the logger level.
1 parent 4ff7923 commit 18f5418

File tree

12 files changed

+400
-110
lines changed

12 files changed

+400
-110
lines changed

.golangci.yml

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,6 @@ linters-settings:
9090
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
9191
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
9292
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
93-
golint:
94-
# minimal confidence for issues, default is 0.8
95-
# min-confidence: 0.8
9693
gofmt:
9794
# simplify code: gofmt with `-s` option, true by default
9895
# simplify: true
@@ -119,11 +116,19 @@ linters-settings:
119116
include-go-root: false
120117
packages:
121118
- github.com/magiconair/properties/assert
122-
- gopkg.in/go-playground/assert.v1
123-
- github.com/pborman/uuid #replace with github.com/google/uuid
124119
inTests:
125120
- github.com/davecgh/go-spew/spew
126121
- github.com/stretchr/testify
122+
gomodguard:
123+
blocked:
124+
modules:
125+
- gopkg.in/go-playground/assert.v1:
126+
recommendations:
127+
- github.com/stretchr/testify
128+
reason: "testify is the test assertion framework we use"
129+
- github.com/pborman/uuid:
130+
recommendations:
131+
- github.com/google/uuid
127132
misspell:
128133
# Correct spellings using locale preferences for US or UK.
129134
# Default is to use a neutral variety of English.
@@ -201,25 +206,44 @@ linters:
201206
- depguard
202207
## - dogsled # checks for too many blank identifiers. don't care
203208
- dupl
209+
- errorlint
210+
# - exhaustive
211+
# - exhaustivestruct
212+
- exportloopref
204213
## - funlen # checks function length. don't care
214+
# - gci
205215
## - gochecknoglobals # too common
206216
- gochecknoinits
217+
- gocognit
207218
- goconst
208219
- gocritic
209220
## - gocyclo # checks cyclomatic complexity. don't care
221+
# - godot
210222
## - godox # checks for TODO comments. not standardized
223+
- goerr113
211224
## - gofmt # checks code is formatted, handled by make prep
225+
# - gofumpt
226+
# - goheader
212227
## - goimports # checks import order. We're not using goimports
213-
- golint
228+
- revive
229+
# - gomnd
230+
- gomodguard
231+
- goprintffuncname
214232
- gosec
215-
- interfacer
216233
## - lll # checks line length. not enforced
217234
## - maligned # optimizies struct field order, but structs are usually ordered for legibility
218235
- misspell
219236
- nakedret
237+
- nestif
238+
# - nlreturn # don't really like how this looks in all cases. wsl covers similar ground anyway.
239+
- noctx
240+
- nolintlint
220241
# - prealloc # slice optimizations, but promotes too much premature optimization
221-
- scopelint
242+
- rowserrcheck
243+
- exportloopref
222244
- stylecheck
245+
# - testpackage
246+
- tparallel
223247
- unconvert
224248
## - unparam # too many false positives
225249
## - whitespace # not enforced
@@ -235,8 +259,10 @@ issues:
235259
# But independently from this option we use default exclude patterns,
236260
# it can be disabled by `exclude-use-default: false`. To list all
237261
# excluded by default patterns execute `golangci-lint run --help`
238-
# exclude:
239-
# - abcdef
262+
exclude:
263+
- Error return value of .(.*\.Write). is not checked
264+
# we use merry errors a lot, and goerr113 doesn't recognize it as a valid sentinel error
265+
- use wrapped static errors instead
240266

241267
# Excluding configuration per-path, per-linter, per-text and per-source
242268
exclude-rules:
@@ -250,11 +276,17 @@ issues:
250276
- scopelint
251277
- gochecknoinits
252278
- gochecknoglobals
279+
- wsl
280+
- goconst
253281
- path: cmd
254282
linters:
255283
# init() functions are pretty common in main packages
256284
- gochecknoinits
257285
- gochecknoglobals
286+
# exclude requiring comments on all exported stuff
287+
- linters:
288+
- revive
289+
text: "exported:"
258290

259291
# Exclude known linters from partially hard-vendored code,
260292
# which is impossible to exclude via "nolint" comments.

benchmark_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,16 @@ var errExample = errors.New("fail")
7676

7777
func fakeFields() []interface{} {
7878
return []interface{}{
79-
//"int", 1,
80-
//"int64",int64(2),
81-
//"float", 3.0,
82-
//"string", "four!",
83-
//"bool", true,
84-
//"time", time.Unix(0, 0),
85-
//"error", errExample,
86-
//"duration", time.Second,
87-
//"user-defined type", _jane,
88-
//"another string", "done!",
79+
// "int", 1,
80+
// "int64",int64(2),
81+
// "float", 3.0,
82+
// "string", "four!",
83+
// "bool", true,
84+
// "time", time.Unix(0, 0),
85+
// "error", errExample,
86+
// "duration", time.Second,
87+
// "user-defined type", _jane,
88+
// "another string", "done!",
8989
zap.Int("int", 1),
9090
zap.Int64("int64", 2),
9191
zap.Float64("float", 3.0),

console_encoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func (c *consoleEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field)
147147
// Add the message itself.
148148
if c.MessageKey != "" {
149149
c.colorReset(final.buf)
150-
//c.colorBright(&final)
150+
// c.colorBright(&final)
151151
final.safeAddString(ent.Message, false)
152152
// ensure a minimum of 2 spaces between the message and the fields,
153153
// to improve readability

core.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type innerCore struct {
3232
zapcore.Core
3333
addCaller bool
3434
errorOutput zapcore.WriteSyncer
35+
hooks []HookFunc
3536
}
3637

3738
// Core is the concrete implementation of Logger. It has some additional
@@ -41,6 +42,8 @@ type Core struct {
4142
*atomicInnerCore
4243
context []zap.Field
4344
callerSkip int
45+
// these are logger-scoped hooks, which only hook into this particular logger
46+
hooks []HookFunc
4447
}
4548

4649
// Log is the core logging method, used by the convenience methods Debug(), Info(), and Error().
@@ -94,10 +97,27 @@ func (l *Core) log(lvl Level, template string, fmtArgs, context []interface{}) b
9497
ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(l.callerSkip + callerSkipOffset))
9598
if !ce.Entry.Caller.Defined {
9699
_, _ = fmt.Fprintf(c.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC())
100+
_ = ce.ErrorOutput.Sync()
97101
}
98102
}
99103

100-
ce.Write(append(l.context, l.sweetenFields(context)...)...)
104+
fields := append(l.context, l.sweetenFields(context)...) //nolint:gocritic
105+
106+
// execute global hooks, which might modify the fields
107+
for i := range c.hooks {
108+
if f := c.hooks[i](ce, fields); f != nil {
109+
fields = f
110+
}
111+
}
112+
113+
// execute logger hooks
114+
for i := range l.hooks {
115+
if f := l.hooks[i](ce, fields); f != nil {
116+
fields = f
117+
}
118+
}
119+
120+
ce.Write(fields...)
101121
return true
102122
}
103123

factory.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type Factory struct {
3131
sync.Mutex
3232

3333
addCaller bool
34+
35+
hooks []HookFunc
3436
}
3537

3638
// Encoder serializes log entries. Re-exported from zap for now to avoid exporting zap.
@@ -125,6 +127,7 @@ func (r *Factory) newInnerCore(name string, info *loggerInfo) *innerCore {
125127
Core: zc,
126128
addCaller: r.addCaller,
127129
errorOutput: zapcore.AddSync(os.Stderr),
130+
hooks: r.hooks,
128131
}
129132
}
130133

@@ -167,6 +170,40 @@ func (r *Factory) SetDefaultLevel(l Level) {
167170
r.defaultLevel.SetLevel(zapcore.Level(l))
168171
}
169172

173+
type Entry = zapcore.Entry
174+
type CheckedEntry = zapcore.CheckedEntry
175+
type Field = zapcore.Field
176+
177+
// HookFunc adapts a single function to the Hook interface.
178+
type HookFunc func(*CheckedEntry, []Field) []Field
179+
180+
// Hooks adds functions which are called before a log entry is encoded. The hook function
181+
// is given the entry and the total set of fields to be logged. The set of fields which are
182+
// returned are then logged. Hook functions can return a modified set of fields, or just return
183+
// the unaltered fields.
184+
//
185+
// The Entry is not modified. It is purely informational.
186+
//
187+
// If a hook returns an error, that error is logged, but the in-flight log entry
188+
// will proceed with the original set of fields.
189+
//
190+
// These global hooks will be injected into all loggers owned by this factory. They will
191+
// execute before any hooks installed in individual loggers.
192+
func (r *Factory) Hooks(hooks ...HookFunc) {
193+
r.Lock()
194+
defer r.Unlock()
195+
r.hooks = append(r.hooks, hooks...)
196+
r.refreshLoggers()
197+
}
198+
199+
// ClearHooks removes all hooks.
200+
func (r *Factory) ClearHooks() {
201+
r.Lock()
202+
defer r.Unlock()
203+
r.hooks = nil
204+
r.refreshLoggers()
205+
}
206+
170207
func parseConfigString(s string) map[string]interface{} {
171208
if s == "" {
172209
return nil

go.mod

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
module github.com/gemalto/flume
22

33
require (
4-
github.com/ansel1/merry v1.5.1
5-
github.com/mattn/go-colorable v0.1.7 // indirect
4+
github.com/ansel1/merry v1.6.1
5+
github.com/mattn/go-colorable v0.1.8 // indirect
6+
github.com/mattn/go-isatty v0.0.13 // indirect
67
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
7-
github.com/stretchr/testify v1.4.0
8-
go.uber.org/multierr v1.5.0
9-
go.uber.org/zap v1.15.0
10-
golang.org/x/sys v0.0.0-20200817085935-3ff754bf58a9 // indirect
11-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
8+
github.com/stretchr/testify v1.7.0
9+
go.uber.org/atomic v1.9.0 // indirect
10+
go.uber.org/multierr v1.7.0
11+
go.uber.org/zap v1.18.1
12+
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
1213
)
1314

1415
go 1.14

0 commit comments

Comments
 (0)