From 1d885ddc098872a06b471bd92be0a8eb394c5dc4 Mon Sep 17 00:00:00 2001 From: Josh Kline Date: Sat, 15 May 2021 13:18:56 -0700 Subject: [PATCH] Expose zaptest.observer.(*ObservedLogs).Filter Export method `observer.(*ObservedLogs).Filter` to allow consumers to filter logs by arbitrary functions for testing. Currently consumers can call `(*ObservedLogs).All` and proceed to filter using `[]LoggedEntry` directly, but the result is then incompatible with existing methods such as `FilterMessage` because there is now way to re-construct an `*ObservedLogs` object. --- zaptest/observer/observer.go | 12 +++++++----- zaptest/observer/observer_test.go | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/zaptest/observer/observer.go b/zaptest/observer/observer.go index 6ae58f5d6..2529b8bee 100644 --- a/zaptest/observer/observer.go +++ b/zaptest/observer/observer.go @@ -80,21 +80,21 @@ func (o *ObservedLogs) AllUntimed() []LoggedEntry { // FilterMessage filters entries to those that have the specified message. func (o *ObservedLogs) FilterMessage(msg string) *ObservedLogs { - return o.filter(func(e LoggedEntry) bool { + return o.Filter(func(e LoggedEntry) bool { return e.Message == msg }) } // FilterMessageSnippet filters entries to those that have a message containing the specified snippet. func (o *ObservedLogs) FilterMessageSnippet(snippet string) *ObservedLogs { - return o.filter(func(e LoggedEntry) bool { + return o.Filter(func(e LoggedEntry) bool { return strings.Contains(e.Message, snippet) }) } // FilterField filters entries to those that have the specified field. func (o *ObservedLogs) FilterField(field zapcore.Field) *ObservedLogs { - return o.filter(func(e LoggedEntry) bool { + return o.Filter(func(e LoggedEntry) bool { for _, ctxField := range e.Context { if ctxField.Equals(field) { return true @@ -106,7 +106,7 @@ func (o *ObservedLogs) FilterField(field zapcore.Field) *ObservedLogs { // FilterFieldKey filters entries to those that have the specified key. func (o *ObservedLogs) FilterFieldKey(key string) *ObservedLogs { - return o.filter(func(e LoggedEntry) bool { + return o.Filter(func(e LoggedEntry) bool { for _, ctxField := range e.Context { if ctxField.Key == key { return true @@ -116,7 +116,9 @@ func (o *ObservedLogs) FilterFieldKey(key string) *ObservedLogs { }) } -func (o *ObservedLogs) filter(match func(LoggedEntry) bool) *ObservedLogs { +// Filter filters entries to those for which the provided function returns +// true. +func (o *ObservedLogs) Filter(match func(LoggedEntry) bool) *ObservedLogs { o.mu.RLock() defer o.mu.RUnlock() diff --git a/zaptest/observer/observer_test.go b/zaptest/observer/observer_test.go index 4e8139493..815e71d16 100644 --- a/zaptest/observer/observer_test.go +++ b/zaptest/observer/observer_test.go @@ -55,7 +55,7 @@ func TestObserver(t *testing.T) { assert.Equal(t, want, logs.AllUntimed(), "Unexpected contents from AllUntimed.") all := logs.All() - require.Equal(t, 1, len(all), "Unexpected numbed of LoggedEntries returned from All.") + require.Equal(t, 1, len(all), "Unexpected number of LoggedEntries returned from All.") assert.NotEqual(t, time.Time{}, all[0].Time, "Expected non-zero time on LoggedEntry.") // copy & zero time for stable assertions @@ -219,6 +219,19 @@ func TestFilters(t *testing.T) { filtered: sink.FilterFieldKey("filterMe"), want: logs[7:9], }, + { + msg: "filter by arbitrary function", + filtered: sink.Filter(func(e LoggedEntry) bool { + return len(e.Context) > 1 + }), + want: func() []LoggedEntry { + // Do not modify logs slice. + w := []LoggedEntry{} + w = append(w, logs[0:5]...) + w = append(w, logs[7]) + return w + }(), + }, } for _, tt := range tests {