mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-05 14:57:49 +00:00
types/logger: add Context and related helpers
We often need both a log function and a context. We can do this by adding the log function as a context value. This commit adds helper glue to make that easy. It is designed to allow incremental adoption. Updates tailscale/corp#3138 Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
parent
f93cf6fa03
commit
deb2f5e793
@ -18,6 +18,8 @@
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
// Logf is the basic Tailscale logger type: a printf-like func.
|
||||
@ -25,6 +27,27 @@
|
||||
// Logf functions must be safe for concurrent use.
|
||||
type Logf func(format string, args ...interface{})
|
||||
|
||||
// A Context is a context.Context that should contain a custom log function, obtainable from FromContext.
|
||||
// If no log function is present, FromContext will return log.Printf.
|
||||
// To construct a Context, use Add
|
||||
type Context context.Context
|
||||
|
||||
type logfKey struct{}
|
||||
|
||||
// FromContext extracts a log function from ctx.
|
||||
func FromContext(ctx Context) Logf {
|
||||
v := ctx.Value(logfKey{})
|
||||
if v == nil {
|
||||
return log.Printf
|
||||
}
|
||||
return v.(Logf)
|
||||
}
|
||||
|
||||
// Ctx constructs a Context from ctx with fn as its custom log function.
|
||||
func Ctx(ctx context.Context, fn Logf) Context {
|
||||
return context.WithValue(ctx, logfKey{}, fn)
|
||||
}
|
||||
|
||||
// WithPrefix wraps f, prefixing each format with the provided prefix.
|
||||
func WithPrefix(f Logf, prefix string) Logf {
|
||||
return func(format string, args ...interface{}) {
|
||||
|
@ -7,11 +7,14 @@
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestFuncWriter(t *testing.T) {
|
||||
@ -183,3 +186,28 @@ func TestRateLimitedFnReentrancy(t *testing.T) {
|
||||
rlogf("boom") // this used to deadlock
|
||||
}))
|
||||
}
|
||||
|
||||
func TestContext(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// Test that FromContext returns log.Printf when the context has no custom log function.
|
||||
defer log.SetOutput(log.Writer())
|
||||
defer log.SetFlags(log.Flags())
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
log.SetFlags(0)
|
||||
logf := FromContext(ctx)
|
||||
logf("a")
|
||||
c.Assert(buf.String(), qt.Equals, "a\n")
|
||||
|
||||
// Test that FromContext and Ctx work together.
|
||||
var called bool
|
||||
markCalled := func(string, ...interface{}) {
|
||||
called = true
|
||||
}
|
||||
ctx = Ctx(ctx, markCalled)
|
||||
logf = FromContext(ctx)
|
||||
logf("a")
|
||||
c.Assert(called, qt.IsTrue)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user