forked from hyperledger/fabric
-
Notifications
You must be signed in to change notification settings - Fork 0
/
core.go
125 lines (105 loc) · 3.13 KB
/
core.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package flogging
import (
"go.uber.org/zap/zapcore"
)
type Encoding int8
const (
CONSOLE = iota
JSON
LOGFMT
)
// EncodingSelector is used to determine whether log records are
// encoded as JSON or in human readable CONSOLE or LOGFMT formats.
type EncodingSelector interface {
Encoding() Encoding
}
// Core is a custom implementation of a zapcore.Core. It's a terrible hack that
// only exists to work around the intersection of state associated with
// encoders, implementation hiding in zapcore, and implicit, ad-hoc logger
// initialization within fabric.
//
// In addition to encoding log entries and fields to a buffer, zap Encoder
// implementations also need to maintain field state. When zapcore.Core.With is
// used, the associated encoder is cloned and the fields are added to the
// encoder. This means that encoder instances cannot be shared across cores.
//
// In terms of implementation hiding, it's difficult for our FormatEncoder to
// cleanly wrap the JSON and console implementations from zap as all methods
// from the zapcore.ObjectEncoder would need to be implemented to delegate to
// the correct backend.
//
// This implementation works by associating multiple encoders with a core. When
// fields are added to the core, the fields are added to all of the encoder
// implementations. The core also references the logging configuration to
// determine the proper encoding to use, the writer to delegate to, and the
// enabled levels.
type Core struct {
zapcore.LevelEnabler
Levels *LoggerLevels
Encoders map[Encoding]zapcore.Encoder
Selector EncodingSelector
Output zapcore.WriteSyncer
Observer Observer
}
//go:generate counterfeiter -o mock/observer.go -fake-name Observer . Observer
type Observer interface {
Check(e zapcore.Entry, ce *zapcore.CheckedEntry)
WriteEntry(e zapcore.Entry, fields []zapcore.Field)
}
func (c *Core) With(fields []zapcore.Field) zapcore.Core {
clones := map[Encoding]zapcore.Encoder{}
for name, enc := range c.Encoders {
clone := enc.Clone()
addFields(clone, fields)
clones[name] = clone
}
return &Core{
LevelEnabler: c.LevelEnabler,
Levels: c.Levels,
Encoders: clones,
Selector: c.Selector,
Output: c.Output,
Observer: c.Observer,
}
}
func (c *Core) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if c.Observer != nil {
c.Observer.Check(e, ce)
}
if c.Enabled(e.Level) && c.Levels.Level(e.LoggerName).Enabled(e.Level) {
return ce.AddCore(e, c)
}
return ce
}
func (c *Core) Write(e zapcore.Entry, fields []zapcore.Field) error {
encoding := c.Selector.Encoding()
enc := c.Encoders[encoding]
buf, err := enc.EncodeEntry(e, fields)
if err != nil {
return err
}
_, err = c.Output.Write(buf.Bytes())
buf.Free()
if err != nil {
return err
}
if e.Level >= zapcore.PanicLevel {
c.Sync()
}
if c.Observer != nil {
c.Observer.WriteEntry(e, fields)
}
return nil
}
func (c *Core) Sync() error {
return c.Output.Sync()
}
func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) {
for i := range fields {
fields[i].AddTo(enc)
}
}