9 "github.com/go-kit/kit/log"
10 "github.com/go-stack/stack"
13 func TestContext(t *testing.T) {
15 buf := &bytes.Buffer{}
16 logger := log.NewLogfmtLogger(buf)
18 kvs := []interface{}{"a", 123}
19 lc := log.With(logger, kvs...)
20 kvs[1] = 0 // With should copy its key values
22 lc = log.With(lc, "b", "c") // With should stack
23 if err := lc.Log("msg", "message"); err != nil {
26 if want, have := "a=123 b=c msg=message\n", buf.String(); want != have {
27 t.Errorf("\nwant: %shave: %s", want, have)
31 lc = log.WithPrefix(lc, "p", "first")
32 if err := lc.Log("msg", "message"); err != nil {
35 if want, have := "p=first a=123 b=c msg=message\n", buf.String(); want != have {
36 t.Errorf("\nwant: %shave: %s", want, have)
40 func TestContextMissingValue(t *testing.T) {
42 var output []interface{}
43 logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
48 log.WithPrefix(log.With(logger, "k1"), "k0").Log("k2")
49 if want, have := 6, len(output); want != have {
50 t.Errorf("want len(output) == %v, have %v", want, have)
52 for i := 1; i < 6; i += 2 {
53 if want, have := log.ErrMissingValue, output[i]; want != have {
54 t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
59 // Test that context.Log has a consistent function stack depth when binding
60 // Valuers, regardless of how many times With has been called.
61 func TestContextStackDepth(t *testing.T) {
63 fn := fmt.Sprintf("%n", stack.Caller(0))
65 var output []interface{}
67 logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
72 stackValuer := log.Valuer(func() interface{} {
73 for i, c := range stack.Trace() {
74 if fmt.Sprintf("%n", c) == fn {
78 t.Fatal("Test function not found in stack trace.")
82 logger = log.With(logger, "stack", stackValuer)
84 // Call through interface to get baseline.
86 want := output[1].(int)
88 for len(output) < 10 {
90 if have := output[1]; have != want {
91 t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want)
94 wrapped := log.With(logger)
96 if have := output[1]; have != want {
97 t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want)
100 logger = log.With(logger, "k", "v")
104 // Test that With returns a Logger safe for concurrent use. This test
105 // validates that the stored logging context does not get corrupted when
106 // multiple clients concurrently log additional keyvals.
108 // This test must be run with go test -cpu 2 (or more) to achieve its goal.
109 func TestWithConcurrent(t *testing.T) {
110 // Create some buckets to count how many events each goroutine logs.
112 counts := [goroutines]int{}
114 // This logger extracts a goroutine id from the last value field and
115 // increments the referenced bucket.
116 logger := log.LoggerFunc(func(kv ...interface{}) error {
117 goroutine := kv[len(kv)-1].(int)
122 // With must be careful about handling slices that can grow without
123 // copying the underlying array, so give it a challenge.
124 l := log.With(logger, make([]interface{}, 0, 2)...)
126 // Start logging concurrently. Each goroutine logs its id so the logger
127 // can bucket the event counts.
128 var wg sync.WaitGroup
131 for i := 0; i < goroutines; i++ {
134 for j := 0; j < n; j++ {
135 l.Log("goroutineIdx", idx)
141 for bucket, have := range counts {
142 if want := n; want != have {
143 t.Errorf("bucket %d: want %d, have %d", bucket, want, have) // note Errorf
148 func BenchmarkDiscard(b *testing.B) {
149 logger := log.NewNopLogger()
152 for i := 0; i < b.N; i++ {
157 func BenchmarkOneWith(b *testing.B) {
158 logger := log.NewNopLogger()
159 lc := log.With(logger, "k", "v")
162 for i := 0; i < b.N; i++ {
167 func BenchmarkTwoWith(b *testing.B) {
168 logger := log.NewNopLogger()
169 lc := log.With(logger, "k", "v")
170 for i := 1; i < 2; i++ {
171 lc = log.With(lc, "k", "v")
175 for i := 0; i < b.N; i++ {
180 func BenchmarkTenWith(b *testing.B) {
181 logger := log.NewNopLogger()
182 lc := log.With(logger, "k", "v")
183 for i := 1; i < 10; i++ {
184 lc = log.With(lc, "k", "v")
188 for i := 0; i < b.N; i++ {