Skip to content

Commit 312f113

Browse files
committed
[FAB-13237] metrics for log records
Created counters to track the number of log records checked and written. (filtered = checked - written) Change-Id: I1b4dcbdc636891e8deca41440c40d58415edc438 Signed-off-by: Saad Karim <skarim@us.ibm.com> Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
1 parent 8ec8a33 commit 312f113

File tree

12 files changed

+486
-66
lines changed

12 files changed

+486
-66
lines changed

common/flogging/core.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ type Core struct {
4949
Encoders map[Encoding]zapcore.Encoder
5050
Selector EncodingSelector
5151
Output zapcore.WriteSyncer
52+
Observer Observer
53+
}
54+
55+
//go:generate counterfeiter -o mock/observer.go -fake-name Observer . Observer
56+
57+
type Observer interface {
58+
Check(e zapcore.Entry, ce *zapcore.CheckedEntry)
59+
WriteEntry(e zapcore.Entry, fields []zapcore.Field)
5260
}
5361

5462
func (c *Core) With(fields []zapcore.Field) zapcore.Core {
@@ -65,10 +73,15 @@ func (c *Core) With(fields []zapcore.Field) zapcore.Core {
6573
Encoders: clones,
6674
Selector: c.Selector,
6775
Output: c.Output,
76+
Observer: c.Observer,
6877
}
6978
}
7079

7180
func (c *Core) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
81+
if c.Observer != nil {
82+
c.Observer.Check(e, ce)
83+
}
84+
7285
if c.Enabled(e.Level) && c.Levels.Level(e.LoggerName).Enabled(e.Level) {
7386
return ce.AddCore(e, c)
7487
}
@@ -93,6 +106,10 @@ func (c *Core) Write(e zapcore.Entry, fields []zapcore.Field) error {
93106
c.Sync()
94107
}
95108

109+
if c.Observer != nil {
110+
c.Observer.WriteEntry(e, fields)
111+
}
112+
96113
return nil
97114
}
98115

common/flogging/core_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"testing"
1313

1414
"github.com/hyperledger/fabric/common/flogging"
15+
"github.com/hyperledger/fabric/common/flogging/mock"
1516
"github.com/stretchr/testify/assert"
1617
"go.uber.org/zap"
1718
"go.uber.org/zap/buffer"
@@ -21,6 +22,7 @@ import (
2122
func TestCoreWith(t *testing.T) {
2223
core := &flogging.Core{
2324
Encoders: map[flogging.Encoding]zapcore.Encoder{},
25+
Observer: &mock.Observer{},
2426
}
2527
clone := core.With([]zapcore.Field{zap.String("key", "value")})
2628
assert.Equal(t, core, clone)
@@ -187,3 +189,63 @@ func TestCoreSync(t *testing.T) {
187189
err = core.Sync()
188190
assert.EqualError(t, err, "bummer")
189191
}
192+
193+
func TestObserverCheck(t *testing.T) {
194+
observer := &mock.Observer{}
195+
entry := zapcore.Entry{
196+
Level: zapcore.DebugLevel,
197+
Message: "message",
198+
}
199+
checkedEntry := &zapcore.CheckedEntry{}
200+
201+
levels := &flogging.LoggerLevels{}
202+
levels.ActivateSpec("debug")
203+
core := &flogging.Core{
204+
LevelEnabler: zap.LevelEnablerFunc(func(l zapcore.Level) bool { return true }),
205+
Levels: levels,
206+
Observer: observer,
207+
}
208+
209+
ce := core.Check(entry, checkedEntry)
210+
assert.Exactly(t, ce, checkedEntry)
211+
212+
assert.Equal(t, 1, observer.CheckCallCount())
213+
observedEntry, observedCE := observer.CheckArgsForCall(0)
214+
assert.Equal(t, entry, observedEntry)
215+
assert.Equal(t, ce, observedCE)
216+
}
217+
218+
func TestObserverWriteEntry(t *testing.T) {
219+
observer := &mock.Observer{}
220+
entry := zapcore.Entry{
221+
Level: zapcore.DebugLevel,
222+
Message: "message",
223+
}
224+
fields := []zapcore.Field{
225+
{Key: "key1", Type: zapcore.SkipType},
226+
{Key: "key2", Type: zapcore.SkipType},
227+
}
228+
229+
levels := &flogging.LoggerLevels{}
230+
levels.ActivateSpec("debug")
231+
selector := &sw{}
232+
output := &sw{}
233+
core := &flogging.Core{
234+
LevelEnabler: zap.LevelEnablerFunc(func(l zapcore.Level) bool { return true }),
235+
Levels: levels,
236+
Selector: selector,
237+
Encoders: map[flogging.Encoding]zapcore.Encoder{
238+
flogging.CONSOLE: zapcore.NewConsoleEncoder(zapcore.EncoderConfig{}),
239+
},
240+
Output: output,
241+
Observer: observer,
242+
}
243+
244+
err := core.Write(entry, fields)
245+
assert.NoError(t, err)
246+
247+
assert.Equal(t, 1, observer.WriteEntryCallCount())
248+
observedEntry, observedFields := observer.WriteEntryArgsForCall(0)
249+
assert.Equal(t, entry, observedEntry)
250+
assert.Equal(t, fields, observedFields)
251+
}

common/flogging/logging.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type Logging struct {
5252
encoderConfig zapcore.EncoderConfig
5353
multiFormatter *fabenc.MultiFormatter
5454
writer zapcore.WriteSyncer
55+
observer Observer
5556
}
5657

5758
// New creates a new logging system and initializes it with the provided
@@ -208,12 +209,35 @@ func (s *Logging) ZapLogger(name string) *zap.Logger {
208209
},
209210
Selector: s,
210211
Output: s,
212+
Observer: s,
211213
}
212214
s.mutex.RUnlock()
213215

214216
return NewZapLogger(core).Named(name)
215217
}
216218

219+
func (s *Logging) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) {
220+
s.mutex.RLock()
221+
if s.observer != nil {
222+
s.observer.Check(e, ce)
223+
}
224+
s.mutex.RUnlock()
225+
}
226+
227+
func (s *Logging) WriteEntry(e zapcore.Entry, fields []zapcore.Field) {
228+
s.mutex.RLock()
229+
if s.observer != nil {
230+
s.observer.WriteEntry(e, fields)
231+
}
232+
s.mutex.RUnlock()
233+
}
234+
235+
func (s *Logging) SetObserver(observer Observer) {
236+
s.mutex.Lock()
237+
s.observer = observer
238+
s.mutex.Unlock()
239+
}
240+
217241
// Logger instantiates a new FabricLogger with the specified name. The name is
218242
// used to determine which log levels are enabled.
219243
func (s *Logging) Logger(name string) *FabricLogger {

common/flogging/logging_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,28 @@ func TestInvalidLoggerName(t *testing.T) {
108108
})
109109
}
110110
}
111+
112+
func TestCheck(t *testing.T) {
113+
l := &flogging.Logging{}
114+
observer := &mock.Observer{}
115+
e := zapcore.Entry{}
116+
117+
// set observer
118+
l.SetObserver(observer)
119+
l.Check(e, nil)
120+
assert.Equal(t, 1, observer.CheckCallCount())
121+
e, ce := observer.CheckArgsForCall(0)
122+
assert.Equal(t, e, zapcore.Entry{})
123+
assert.Nil(t, ce)
124+
125+
l.WriteEntry(e, nil)
126+
assert.Equal(t, 1, observer.WriteEntryCallCount())
127+
e, f := observer.WriteEntryArgsForCall(0)
128+
assert.Equal(t, e, zapcore.Entry{})
129+
assert.Nil(t, f)
130+
131+
// remove observer
132+
l.SetObserver(nil)
133+
l.Check(zapcore.Entry{}, nil)
134+
assert.Equal(t, 1, observer.CheckCallCount())
135+
}

common/flogging/metrics/observer.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package metrics
8+
9+
import (
10+
"github.com/hyperledger/fabric/common/metrics"
11+
"go.uber.org/zap/zapcore"
12+
)
13+
14+
var (
15+
CheckedCountOpts = metrics.CounterOpts{
16+
Namespace: "logging",
17+
Name: "entries_checked",
18+
Help: "Number of log entries checked against the active logging level",
19+
LabelNames: []string{"level"},
20+
StatsdFormat: "%{#fqname}.%{level}",
21+
}
22+
23+
WriteCountOpts = metrics.CounterOpts{
24+
Namespace: "logging",
25+
Name: "entries_written",
26+
Help: "Number of log entries that are written",
27+
LabelNames: []string{"level"},
28+
StatsdFormat: "%{#fqname}.%{level}",
29+
}
30+
)
31+
32+
type Observer struct {
33+
CheckedCounter metrics.Counter
34+
WrittenCounter metrics.Counter
35+
}
36+
37+
func NewObserver(provider metrics.Provider) *Observer {
38+
return &Observer{
39+
CheckedCounter: provider.NewCounter(CheckedCountOpts),
40+
WrittenCounter: provider.NewCounter(WriteCountOpts),
41+
}
42+
}
43+
44+
func (m *Observer) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) {
45+
m.CheckedCounter.With("level", e.Level.String()).Add(1)
46+
}
47+
48+
func (m *Observer) WriteEntry(e zapcore.Entry, fields []zapcore.Field) {
49+
m.WrittenCounter.With("level", e.Level.String()).Add(1)
50+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package metrics_test
8+
9+
import (
10+
"testing"
11+
12+
"github.com/hyperledger/fabric/common/flogging/metrics"
13+
commonmetrics "github.com/hyperledger/fabric/common/metrics"
14+
"github.com/hyperledger/fabric/common/metrics/metricsfakes"
15+
"github.com/stretchr/testify/assert"
16+
"go.uber.org/zap/zapcore"
17+
)
18+
19+
func TestNewObserver(t *testing.T) {
20+
provider := &metricsfakes.Provider{}
21+
checkedCounter := &metricsfakes.Counter{}
22+
writtenCounter := &metricsfakes.Counter{}
23+
provider.NewCounterStub = func(c commonmetrics.CounterOpts) commonmetrics.Counter {
24+
switch c.Name {
25+
case "entries_checked":
26+
assert.Equal(t, metrics.CheckedCountOpts, c)
27+
return checkedCounter
28+
case "entries_written":
29+
assert.Equal(t, metrics.WriteCountOpts, c)
30+
return writtenCounter
31+
default:
32+
return nil
33+
}
34+
}
35+
36+
expectedObserver := &metrics.Observer{
37+
CheckedCounter: checkedCounter,
38+
WrittenCounter: writtenCounter,
39+
}
40+
m := metrics.NewObserver(provider)
41+
assert.Equal(t, expectedObserver, m)
42+
assert.Equal(t, 2, provider.NewCounterCallCount())
43+
}
44+
45+
func TestCheck(t *testing.T) {
46+
counter := &metricsfakes.Counter{}
47+
counter.WithReturns(counter)
48+
49+
m := metrics.Observer{CheckedCounter: counter}
50+
entry := zapcore.Entry{Level: zapcore.DebugLevel}
51+
checkedEntry := &zapcore.CheckedEntry{}
52+
m.Check(entry, checkedEntry)
53+
54+
assert.Equal(t, 1, counter.WithCallCount())
55+
assert.Equal(t, []string{"level", "debug"}, counter.WithArgsForCall(0))
56+
57+
assert.Equal(t, 1, counter.AddCallCount())
58+
assert.Equal(t, float64(1), counter.AddArgsForCall(0))
59+
}
60+
61+
func TestWrite(t *testing.T) {
62+
counter := &metricsfakes.Counter{}
63+
counter.WithReturns(counter)
64+
65+
m := metrics.Observer{WrittenCounter: counter}
66+
entry := zapcore.Entry{Level: zapcore.DebugLevel}
67+
m.WriteEntry(entry, nil)
68+
69+
assert.Equal(t, 1, counter.WithCallCount())
70+
assert.Equal(t, []string{"level", "debug"}, counter.WithArgsForCall(0))
71+
72+
assert.Equal(t, 1, counter.AddCallCount())
73+
assert.Equal(t, float64(1), counter.AddArgsForCall(0))
74+
}

0 commit comments

Comments
 (0)