adding in logging

This commit is contained in:
Steve Brunton
2017-08-30 22:05:59 -04:00
parent 403b464aec
commit 123cd935a3
107 changed files with 14413 additions and 2 deletions

27
vendor/go.uber.org/zap/zaptest/doc.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package zaptest provides low-level helpers for testing log output. These
// utilities are helpful in zap's own unit tests, but any assertions using
// them are strongly coupled to a single encoding.
//
// Most users should use go.uber.org/zap/zaptest/observer instead of this
// package.
package zaptest // import "go.uber.org/zap/zaptest"

174
vendor/go.uber.org/zap/zaptest/observer/observer.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package observer provides a zapcore.Core that keeps an in-memory,
// encoding-agnostic repesentation of log entries. It's useful for
// applications that want to unit test their log output without tying their
// tests to a particular output encoding.
package observer // import "go.uber.org/zap/zaptest/observer"
import (
"strings"
"sync"
"time"
"go.uber.org/zap/zapcore"
)
// An LoggedEntry is an encoding-agnostic representation of a log message.
// Field availability is context dependant.
type LoggedEntry struct {
zapcore.Entry
Context []zapcore.Field
}
// ObservedLogs is a concurrency-safe, ordered collection of observed logs.
type ObservedLogs struct {
mu sync.RWMutex
logs []LoggedEntry
}
// Len returns the number of items in the collection.
func (o *ObservedLogs) Len() int {
o.mu.RLock()
n := len(o.logs)
o.mu.RUnlock()
return n
}
// All returns a copy of all the observed logs.
func (o *ObservedLogs) All() []LoggedEntry {
o.mu.RLock()
ret := make([]LoggedEntry, len(o.logs))
for i := range o.logs {
ret[i] = o.logs[i]
}
o.mu.RUnlock()
return ret
}
// TakeAll returns a copy of all the observed logs, and truncates the observed
// slice.
func (o *ObservedLogs) TakeAll() []LoggedEntry {
o.mu.Lock()
ret := o.logs
o.logs = nil
o.mu.Unlock()
return ret
}
// AllUntimed returns a copy of all the observed logs, but overwrites the
// observed timestamps with time.Time's zero value. This is useful when making
// assertions in tests.
func (o *ObservedLogs) AllUntimed() []LoggedEntry {
ret := o.All()
for i := range ret {
ret[i].Time = time.Time{}
}
return ret
}
// 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 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 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 {
for _, ctxField := range e.Context {
if ctxField.Equals(field) {
return true
}
}
return false
})
}
func (o *ObservedLogs) filter(match func(LoggedEntry) bool) *ObservedLogs {
o.mu.RLock()
defer o.mu.RUnlock()
var filtered []LoggedEntry
for _, entry := range o.logs {
if match(entry) {
filtered = append(filtered, entry)
}
}
return &ObservedLogs{logs: filtered}
}
func (o *ObservedLogs) add(log LoggedEntry) {
o.mu.Lock()
o.logs = append(o.logs, log)
o.mu.Unlock()
}
// New creates a new Core that buffers logs in memory (without any encoding).
// It's particularly useful in tests.
func New(enab zapcore.LevelEnabler) (zapcore.Core, *ObservedLogs) {
ol := &ObservedLogs{}
return &contextObserver{
LevelEnabler: enab,
logs: ol,
}, ol
}
type contextObserver struct {
zapcore.LevelEnabler
logs *ObservedLogs
context []zapcore.Field
}
func (co *contextObserver) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if co.Enabled(ent.Level) {
return ce.AddCore(ent, co)
}
return ce
}
func (co *contextObserver) With(fields []zapcore.Field) zapcore.Core {
return &contextObserver{
LevelEnabler: co.LevelEnabler,
logs: co.logs,
context: append(co.context[:len(co.context):len(co.context)], fields...),
}
}
func (co *contextObserver) Write(ent zapcore.Entry, fields []zapcore.Field) error {
all := make([]zapcore.Field, 0, len(fields)+len(co.context))
all = append(all, co.context...)
all = append(all, fields...)
co.logs.add(LoggedEntry{ent, all})
return nil
}
func (co *contextObserver) Sync() error {
return nil
}

View File

@@ -0,0 +1,215 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package observer_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
. "go.uber.org/zap/zaptest/observer"
)
func assertEmpty(t testing.TB, logs *ObservedLogs) {
assert.Equal(t, 0, logs.Len(), "Expected empty ObservedLogs to have zero length.")
assert.Equal(t, []LoggedEntry{}, logs.All(), "Unexpected LoggedEntries in empty ObservedLogs.")
}
func TestObserver(t *testing.T) {
observer, logs := New(zap.InfoLevel)
assertEmpty(t, logs)
assert.NoError(t, observer.Sync(), "Unexpected failure in no-op Sync")
obs := zap.New(observer).With(zap.Int("i", 1))
obs.Info("foo")
obs.Debug("bar")
want := []LoggedEntry{{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "foo"},
Context: []zapcore.Field{zap.Int("i", 1)},
}}
assert.Equal(t, 1, logs.Len(), "Unexpected observed logs Len.")
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.")
assert.NotEqual(t, time.Time{}, all[0].Time, "Expected non-zero time on LoggedEntry.")
// copy & zero time for stable assertions
untimed := append([]LoggedEntry{}, all...)
untimed[0].Time = time.Time{}
assert.Equal(t, want, untimed, "Unexpected LoggedEntries from All.")
assert.Equal(t, all, logs.TakeAll(), "Expected All and TakeAll to return identical results.")
assertEmpty(t, logs)
}
func TestObserverWith(t *testing.T) {
sf1, logs := New(zap.InfoLevel)
// need to pad out enough initial fields so that the underlying slice cap()
// gets ahead of its len() so that the sf3/4 With append's could choose
// not to copy (if the implementation doesn't force them)
sf1 = sf1.With([]zapcore.Field{zap.Int("a", 1), zap.Int("b", 2)})
sf2 := sf1.With([]zapcore.Field{zap.Int("c", 3)})
sf3 := sf2.With([]zapcore.Field{zap.Int("d", 4)})
sf4 := sf2.With([]zapcore.Field{zap.Int("e", 5)})
ent := zapcore.Entry{Level: zap.InfoLevel, Message: "hello"}
for i, core := range []zapcore.Core{sf2, sf3, sf4} {
if ce := core.Check(ent, nil); ce != nil {
ce.Write(zap.Int("i", i))
}
}
assert.Equal(t, []LoggedEntry{
{
Entry: ent,
Context: []zapcore.Field{
zap.Int("a", 1),
zap.Int("b", 2),
zap.Int("c", 3),
zap.Int("i", 0),
},
},
{
Entry: ent,
Context: []zapcore.Field{
zap.Int("a", 1),
zap.Int("b", 2),
zap.Int("c", 3),
zap.Int("d", 4),
zap.Int("i", 1),
},
},
{
Entry: ent,
Context: []zapcore.Field{
zap.Int("a", 1),
zap.Int("b", 2),
zap.Int("c", 3),
zap.Int("e", 5),
zap.Int("i", 2),
},
},
}, logs.All(), "expected no field sharing between With siblings")
}
func TestFilters(t *testing.T) {
logs := []LoggedEntry{
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log a"},
Context: []zapcore.Field{zap.String("fStr", "1"), zap.Int("a", 1)},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log a"},
Context: []zapcore.Field{zap.String("fStr", "2"), zap.Int("b", 2)},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log b"},
Context: []zapcore.Field{zap.Int("a", 1), zap.Int("b", 2)},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log c"},
Context: []zapcore.Field{zap.Int("a", 1), zap.Namespace("ns"), zap.Int("a", 2)},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "msg 1"},
Context: []zapcore.Field{zap.Int("a", 1), zap.Namespace("ns")},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any map"},
Context: []zapcore.Field{zap.Any("map", map[string]string{"a": "b"})},
},
{
Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any slice"},
Context: []zapcore.Field{zap.Any("slice", []string{"a"})},
},
}
logger, sink := New(zap.InfoLevel)
for _, log := range logs {
logger.Write(log.Entry, log.Context)
}
tests := []struct {
msg string
filtered *ObservedLogs
want []LoggedEntry
}{
{
msg: "filter by message",
filtered: sink.FilterMessage("log a"),
want: logs[0:2],
},
{
msg: "filter by field",
filtered: sink.FilterField(zap.String("fStr", "1")),
want: logs[0:1],
},
{
msg: "filter by message and field",
filtered: sink.FilterMessage("log a").FilterField(zap.Int("b", 2)),
want: logs[1:2],
},
{
msg: "filter by field with duplicate fields",
filtered: sink.FilterField(zap.Int("a", 2)),
want: logs[3:4],
},
{
msg: "filter doesn't match any messages",
filtered: sink.FilterMessage("no match"),
want: []LoggedEntry{},
},
{
msg: "filter by snippet",
filtered: sink.FilterMessageSnippet("log"),
want: logs[0:4],
},
{
msg: "filter by snippet and field",
filtered: sink.FilterMessageSnippet("a").FilterField(zap.Int("b", 2)),
want: logs[1:2],
},
{
msg: "filter for map",
filtered: sink.FilterField(zap.Any("map", map[string]string{"a": "b"})),
want: logs[5:6],
},
{
msg: "filter for slice",
filtered: sink.FilterField(zap.Any("slice", []string{"a"})),
want: logs[6:7],
},
}
for _, tt := range tests {
got := tt.filtered.AllUntimed()
assert.Equal(t, tt.want, got, tt.msg)
}
}

51
vendor/go.uber.org/zap/zaptest/timeout.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zaptest
import (
"log"
"os"
"strconv"
"time"
)
var _timeoutScale = 1.0
// Timeout scales the provided duration by $TEST_TIMEOUT_SCALE.
func Timeout(base time.Duration) time.Duration {
return time.Duration(float64(base) * _timeoutScale)
}
// Sleep scales the sleep duration by $TEST_TIMEOUT_SCALE.
func Sleep(base time.Duration) {
time.Sleep(Timeout(base))
}
func init() {
if v := os.Getenv("TEST_TIMEOUT_SCALE"); v != "" {
fv, err := strconv.ParseFloat(v, 64)
if err != nil {
panic(err)
}
_timeoutScale = fv
log.Printf("Scaling timeouts by %vx.\n", _timeoutScale)
}
}

96
vendor/go.uber.org/zap/zaptest/writer.go generated vendored Normal file
View File

@@ -0,0 +1,96 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zaptest
import (
"bytes"
"errors"
"io/ioutil"
"strings"
)
// A Syncer is a spy for the Sync portion of zapcore.WriteSyncer.
type Syncer struct {
err error
called bool
}
// SetError sets the error that the Sync method will return.
func (s *Syncer) SetError(err error) {
s.err = err
}
// Sync records that it was called, then returns the user-supplied error (if
// any).
func (s *Syncer) Sync() error {
s.called = true
return s.err
}
// Called reports whether the Sync method was called.
func (s *Syncer) Called() bool {
return s.called
}
// A Discarder sends all writes to ioutil.Discard.
type Discarder struct{ Syncer }
// Write implements io.Writer.
func (d *Discarder) Write(b []byte) (int, error) {
return ioutil.Discard.Write(b)
}
// FailWriter is a WriteSyncer that always returns an error on writes.
type FailWriter struct{ Syncer }
// Write implements io.Writer.
func (w FailWriter) Write(b []byte) (int, error) {
return len(b), errors.New("failed")
}
// ShortWriter is a WriteSyncer whose write method never fails, but
// nevertheless fails to the last byte of the input.
type ShortWriter struct{ Syncer }
// Write implements io.Writer.
func (w ShortWriter) Write(b []byte) (int, error) {
return len(b) - 1, nil
}
// Buffer is an implementation of zapcore.WriteSyncer that sends all writes to
// a bytes.Buffer. It has convenience methods to split the accumulated buffer
// on newlines.
type Buffer struct {
bytes.Buffer
Syncer
}
// Lines returns the current buffer contents, split on newlines.
func (b *Buffer) Lines() []string {
output := strings.Split(b.String(), "\n")
return output[:len(output)-1]
}
// Stripped returns the current buffer contents with the last trailing newline
// stripped.
func (b *Buffer) Stripped() string {
return strings.TrimRight(b.String(), "\n")
}