Repository: go-kit/kit
Pull request #1173 (2021-07-29 03:48:05)

Replace kit/log with log
The kit/log packages that were copied to their own module become aliases for the new packages to avoid breaking existing code.

This change may also help projects that end up with dependencies using both import paths. They can use the types from the two paths interchangably and will only have one copy of the actual implementations compiled in to them.

Also change all the other Go kit packages to use the new log packages directly.

sagikazarmark: Seems good to me, given deprecation is what we want to go with. I think Peter had different ideas.

Wild idea: would it make sense to create a Logger interface in each package where it is imported to decouple them from the log package.
peterbourgon: I had it in my head that they should be separate packages. I can't recall a precise technical reason why this was a good idea. And I've encountered more than one situation, now, where it's been rather annoying that go-kit/kit/log wasn't an alias for, or equivalent to, or etc. go-kit/log. So I'm basically +1. What things do we need to be careful about?
ChrisHines: > What things do we need to be careful about?

I intentionally left behind the example tests in the gutted packages for two reasons. First, to maintain their role as documentation, and second to serve as a small test that the APIs still work as before.

We should be triply sure that I didn't accidentally cross any wires on any of the forward references. Make sure I didn't alias the wrong type, variable, function, or constant anywhere.

One good sign: With a local `replace` directive to use this PR code in the `go-kit/examples/go.mod` file all the examples build successfully for me even though they all still import `kit/log`. I don't see any of the examples importing any `kit/log/...` packages, though, so we may want to find some code that uses those and make sure they still build properly.

I have some projects that use `kit/log` and `kit/log/level` that I can validate. I can't think of any projects I have that use the other modified packages off the top of my head.
ChrisHines: > Wild idea: would it make sense to create a Logger interface in each package where it is imported to decouple them from the log package.

That would certainly decouple them more than they are today. I'm not sure it's a good idea, but I am not completely opposed.

If we did that I would expect the docs for the new declarations to be a copy/paste of the existing `Logger` interface to help remind people of its full contract. I would also expect an additional comment referring people to the `log` package so they can find those ready made implementations easily.
peterbourgon: > Wild idea: would it make sense to create a Logger interface in each package where it is imported to decouple them from the log package.

My initial reaction was -1, but upon reflection I'm less negative. In any case we can defer this til later.
peterbourgon: @ChrisHines I'll check all the module/package import references carefully, but assuming that's kosher, you're OK with merging, is that right?
ChrisHines: > @ChrisHines I'll check all the module/package import references carefully, but assuming that's kosher, you're OK with merging, is that right?

Correct.
ChrisHines: As an additional datapoint I used a replace directive to bring this branch into a project I have that uses `kit/log` throughout. Everything built fine. I also replaced a single import of `kit/log` with the new `log` repo, leaving all other imports in the project alone. Again everything built fine. That should verify the interchangeability of at least the `log` and `log/level` aliases.
peterbourgon: Some of the imports within go-kit/kit/log, for example in the tests, are still pointing to go-kit/kit/log —

```
ugh ~/src/kit (use-new-log) rg '/kit/log'
log/zap/zap_sugar_logger_test.go
5:      kitzap "github.com/go-kit/kit/log/zap"

log/deprecated_levels/levels_test.go
8:      levels "github.com/go-kit/kit/log/deprecated_levels"

log/term/example_test.go
7:      "github.com/go-kit/kit/log"
8:      "github.com/go-kit/kit/log/term"

...
```

Is that deliberate?
ChrisHines: Yes. `kit/log/zap` and `kit/log/deprecated_levels` were not kept in the new `log` repo, so those only exist in the `kit` repo. The imports in the `example_test.go` files intentionally refer to the `kit/log` packages as a small way to keep testing that the aliases work as intended.
peterbourgon: OK! I'll merge this tomorrow unless there's an objection.

Patch:
diff --git a/auth/jwt/README.md b/auth/jwt/README.md
index 8cf823c..97a3720 100644
--- a/auth/jwt/README.md
+++ b/auth/jwt/README.md
@@ -95,7 +95,7 @@ import (
 	"context"
 
 	"github.com/go-kit/kit/auth/jwt"
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 	grpctransport "github.com/go-kit/kit/transport/grpc"
 )
 
diff --git a/go.mod b/go.mod
index ca4014e..473e73b 100644
--- a/go.mod
+++ b/go.mod
@@ -16,8 +16,7 @@ require (
 	github.com/edsrzf/mmap-go v1.0.0 // indirect
 	github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db // indirect
 	github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 // indirect
-	github.com/go-logfmt/logfmt v0.5.0
-	github.com/go-stack/stack v1.8.0
+	github.com/go-kit/log v0.1.0
 	github.com/go-zookeeper/zk v1.0.2
 	github.com/hashicorp/consul/api v1.8.1
 	github.com/hudl/fargo v1.3.0
diff --git a/go.sum b/go.sum
index d8ab707..7f238d2 100644
--- a/go.sum
+++ b/go.sum
@@ -79,6 +79,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
diff --git a/log/README.md b/log/README.md
index a201a3d..5492dd9 100644
--- a/log/README.md
+++ b/log/README.md
@@ -1,5 +1,14 @@
 # package log
 
+**Deprecation notice:** The core Go kit log packages (log, log/level, log/term, and
+log/syslog) have been moved to their own repository at github.com/go-kit/log.
+The corresponding packages in this directory remain for backwards compatibility.
+Their types alias the types and their functions call the functions provided by
+the new repository. Using either import path should be equivalent. Prefer the
+new import path when practical.
+
+______
+
 `package log` provides a minimal interface for structured logging in services.
 It may be wrapped to encode conventions, enforce type-safety, provide leveled
 logging, and so on. It can be used for both typical application log events,
diff --git a/log/deprecated_levels/levels.go b/log/deprecated_levels/levels.go
index a034212..2807cbd 100644
--- a/log/deprecated_levels/levels.go
+++ b/log/deprecated_levels/levels.go
@@ -1,6 +1,9 @@
+// Package levels implements leveled logging on top of Go kit's log package.
+//
+// Deprecated: Use github.com/go-kit/log/level instead.
 package levels
 
-import "github.com/go-kit/kit/log"
+import "github.com/go-kit/log"
 
 // Levels provides a leveled logging wrapper around a logger. It has five
 // levels: debug, info, warning (warn), error, and critical (crit). If you
diff --git a/log/doc.go b/log/doc.go
index f744382..c9873f4 100644
--- a/log/doc.go
+++ b/log/doc.go
@@ -1,5 +1,7 @@
 // Package log provides a structured logger.
 //
+// Deprecated: Use github.com/go-kit/log instead.
+//
 // Structured logging produces logs easily consumed later by humans or
 // machines. Humans might be interested in debugging errors, or tracing
 // specific requests. Machines might be interested in counting interesting
diff --git a/log/json_logger.go b/log/json_logger.go
index 0cedbf8..edfde2f 100644
--- a/log/json_logger.go
+++ b/log/json_logger.go
@@ -1,91 +1,15 @@
 package log
 
 import (
-	"encoding"
-	"encoding/json"
-	"fmt"
 	"io"
-	"reflect"
-)
 
-type jsonLogger struct {
-	io.Writer
-}
+	"github.com/go-kit/log"
+)
 
 // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
 // single JSON object. Each log event produces no more than one call to
 // w.Write. The passed Writer must be safe for concurrent use by multiple
 // goroutines if the returned Logger will be used concurrently.
 func NewJSONLogger(w io.Writer) Logger {
-	return &jsonLogger{w}
-}
-
-func (l *jsonLogger) Log(keyvals ...interface{}) error {
-	n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
-	m := make(map[string]interface{}, n)
-	for i := 0; i < len(keyvals); i += 2 {
-		k := keyvals[i]
-		var v interface{} = ErrMissingValue
-		if i+1 < len(keyvals) {
-			v = keyvals[i+1]
-		}
-		merge(m, k, v)
-	}
-	enc := json.NewEncoder(l.Writer)
-	enc.SetEscapeHTML(false)
-	return enc.Encode(m)
-}
-
-func merge(dst map[string]interface{}, k, v interface{}) {
-	var key string
-	switch x := k.(type) {
-	case string:
-		key = x
-	case fmt.Stringer:
-		key = safeString(x)
-	default:
-		key = fmt.Sprint(x)
-	}
-
-	// We want json.Marshaler and encoding.TextMarshaller to take priority over
-	// err.Error() and v.String(). But json.Marshall (called later) does that by
-	// default so we force a no-op if it's one of those 2 case.
-	switch x := v.(type) {
-	case json.Marshaler:
-	case encoding.TextMarshaler:
-	case error:
-		v = safeError(x)
-	case fmt.Stringer:
-		v = safeString(x)
-	}
-
-	dst[key] = v
-}
-
-func safeString(str fmt.Stringer) (s string) {
-	defer func() {
-		if panicVal := recover(); panicVal != nil {
-			if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
-				s = "NULL"
-			} else {
-				panic(panicVal)
-			}
-		}
-	}()
-	s = str.String()
-	return
-}
-
-func safeError(err error) (s interface{}) {
-	defer func() {
-		if panicVal := recover(); panicVal != nil {
-			if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
-				s = nil
-			} else {
-				panic(panicVal)
-			}
-		}
-	}()
-	s = err.Error()
-	return
+	return log.NewJSONLogger(w)
 }
diff --git a/log/level/doc.go b/log/level/doc.go
index 505d307..7baf870 100644
--- a/log/level/doc.go
+++ b/log/level/doc.go
@@ -1,6 +1,9 @@
-// Package level implements leveled logging on top of Go kit's log package. To
-// use the level package, create a logger as per normal in your func main, and
-// wrap it with level.NewFilter.
+// Package level implements leveled logging on top of Go kit's log package.
+//
+// Deprecated: Use github.com/go-kit/log/level instead.
+//
+// To use the level package, create a logger as per normal in your func main,
+// and wrap it with level.NewFilter.
 //
 //    var logger log.Logger
 //    logger = log.NewLogfmtLogger(os.Stderr)
diff --git a/log/level/level.go b/log/level/level.go
index c0c050f..803e8b9 100644
--- a/log/level/level.go
+++ b/log/level/level.go
@@ -1,25 +1,28 @@
 package level
 
-import "github.com/go-kit/kit/log"
+import (
+	"github.com/go-kit/log"
+	"github.com/go-kit/log/level"
+)
 
 // Error returns a logger that includes a Key/ErrorValue pair.
 func Error(logger log.Logger) log.Logger {
-	return log.WithPrefix(logger, Key(), ErrorValue())
+	return level.Error(logger)
 }
 
 // Warn returns a logger that includes a Key/WarnValue pair.
 func Warn(logger log.Logger) log.Logger {
-	return log.WithPrefix(logger, Key(), WarnValue())
+	return level.Warn(logger)
 }
 
 // Info returns a logger that includes a Key/InfoValue pair.
 func Info(logger log.Logger) log.Logger {
-	return log.WithPrefix(logger, Key(), InfoValue())
+	return level.Info(logger)
 }
 
 // Debug returns a logger that includes a Key/DebugValue pair.
 func Debug(logger log.Logger) log.Logger {
-	return log.WithPrefix(logger, Key(), DebugValue())
+	return level.Debug(logger)
 }
 
 // NewFilter wraps next and implements level filtering. See the commentary on
@@ -28,76 +31,40 @@ func Debug(logger log.Logger) log.Logger {
 // Info, Warn or Error helper methods are squelched and non-leveled log
 // events are passed to next unmodified.
 func NewFilter(next log.Logger, options ...Option) log.Logger {
-	l := &logger{
-		next: next,
-	}
-	for _, option := range options {
-		option(l)
-	}
-	return l
-}
-
-type logger struct {
-	next           log.Logger
-	allowed        level
-	squelchNoLevel bool
-	errNotAllowed  error
-	errNoLevel     error
-}
-
-func (l *logger) Log(keyvals ...interface{}) error {
-	var hasLevel, levelAllowed bool
-	for i := 1; i < len(keyvals); i += 2 {
-		if v, ok := keyvals[i].(*levelValue); ok {
-			hasLevel = true
-			levelAllowed = l.allowed&v.level != 0
-			break
-		}
-	}
-	if !hasLevel && l.squelchNoLevel {
-		return l.errNoLevel
-	}
-	if hasLevel && !levelAllowed {
-		return l.errNotAllowed
-	}
-	return l.next.Log(keyvals...)
+	return level.NewFilter(next, options...)
 }
 
 // Option sets a parameter for the leveled logger.
-type Option func(*logger)
+type Option = level.Option
 
 // AllowAll is an alias for AllowDebug.
 func AllowAll() Option {
-	return AllowDebug()
+	return level.AllowAll()
 }
 
 // AllowDebug allows error, warn, info and debug level log events to pass.
 func AllowDebug() Option {
-	return allowed(levelError | levelWarn | levelInfo | levelDebug)
+	return level.AllowDebug()
 }
 
 // AllowInfo allows error, warn and info level log events to pass.
 func AllowInfo() Option {
-	return allowed(levelError | levelWarn | levelInfo)
+	return level.AllowInfo()
 }
 
 // AllowWarn allows error and warn level log events to pass.
 func AllowWarn() Option {
-	return allowed(levelError | levelWarn)
+	return level.AllowWarn()
 }
 
 // AllowError allows only error level log events to pass.
 func AllowError() Option {
-	return allowed(levelError)
+	return level.AllowError()
 }
 
 // AllowNone allows no leveled log events to pass.
 func AllowNone() Option {
-	return allowed(0)
-}
-
-func allowed(allowed level) Option {
-	return func(l *logger) { l.allowed = allowed }
+	return level.AllowNone()
 }
 
 // ErrNotAllowed sets the error to return from Log when it squelches a log
@@ -105,7 +72,7 @@ func allowed(allowed level) Option {
 // ErrNotAllowed is nil; in this case the log event is squelched with no
 // error.
 func ErrNotAllowed(err error) Option {
-	return func(l *logger) { l.errNotAllowed = err }
+	return level.ErrNotAllowed(err)
 }
 
 // SquelchNoLevel instructs Log to squelch log events with no level, so that
@@ -113,93 +80,41 @@ func ErrNotAllowed(err error) Option {
 // to true and a log event is squelched in this way, the error value
 // configured with ErrNoLevel is returned to the caller.
 func SquelchNoLevel(squelch bool) Option {
-	return func(l *logger) { l.squelchNoLevel = squelch }
+	return level.SquelchNoLevel(squelch)
 }
 
 // ErrNoLevel sets the error to return from Log when it squelches a log event
 // with no level. By default, ErrNoLevel is nil; in this case the log event is
 // squelched with no error.
 func ErrNoLevel(err error) Option {
-	return func(l *logger) { l.errNoLevel = err }
+	return level.ErrNoLevel(err)
 }
 
 // NewInjector wraps next and returns a logger that adds a Key/level pair to
 // the beginning of log events that don't already contain a level. In effect,
 // this gives a default level to logs without a level.
-func NewInjector(next log.Logger, level Value) log.Logger {
-	return &injector{
-		next:  next,
-		level: level,
-	}
-}
-
-type injector struct {
-	next  log.Logger
-	level interface{}
-}
-
-func (l *injector) Log(keyvals ...interface{}) error {
-	for i := 1; i < len(keyvals); i += 2 {
-		if _, ok := keyvals[i].(*levelValue); ok {
-			return l.next.Log(keyvals...)
-		}
-	}
-	kvs := make([]interface{}, len(keyvals)+2)
-	kvs[0], kvs[1] = key, l.level
-	copy(kvs[2:], keyvals)
-	return l.next.Log(kvs...)
+func NewInjector(next log.Logger, lvl Value) log.Logger {
+	return level.NewInjector(next, lvl)
 }
 
 // Value is the interface that each of the canonical level values implement.
 // It contains unexported methods that prevent types from other packages from
 // implementing it and guaranteeing that NewFilter can distinguish the levels
 // defined in this package from all other values.
-type Value interface {
-	String() string
-	levelVal()
-}
+type Value = level.Value
 
 // Key returns the unique key added to log events by the loggers in this
 // package.
-func Key() interface{} { return key }
+func Key() interface{} { return level.Key() }
 
 // ErrorValue returns the unique value added to log events by Error.
-func ErrorValue() Value { return errorValue }
+func ErrorValue() Value { return level.ErrorValue() }
 
 // WarnValue returns the unique value added to log events by Warn.
-func WarnValue() Value { return warnValue }
+func WarnValue() Value { return level.WarnValue() }
 
 // InfoValue returns the unique value added to log events by Info.
-func InfoValue() Value { return infoValue }
+func InfoValue() Value { return level.InfoValue() }
 
 // DebugValue returns the unique value added to log events by Debug.
-func DebugValue() Value { return debugValue }
-
-var (
-	// key is of type interface{} so that it allocates once during package
-	// initialization and avoids allocating every time the value is added to a
-	// []interface{} later.
-	key interface{} = "level"
-
-	errorValue = &levelValue{level: levelError, name: "error"}
-	warnValue  = &levelValue{level: levelWarn, name: "warn"}
-	infoValue  = &levelValue{level: levelInfo, name: "info"}
-	debugValue = &levelValue{level: levelDebug, name: "debug"}
-)
-
-type level byte
-
-const (
-	levelDebug level = 1 << iota
-	levelInfo
-	levelWarn
-	levelError
-)
-
-type levelValue struct {
-	name string
-	level
-}
-
-func (v *levelValue) String() string { return v.name }
-func (v *levelValue) levelVal()      {}
+func DebugValue() Value { return level.DebugValue() }
diff --git a/log/log.go b/log/log.go
index 29b3b82..164a4f9 100644
--- a/log/log.go
+++ b/log/log.go
@@ -1,19 +1,19 @@
 package log
 
-import "errors"
+import (
+	"github.com/go-kit/log"
+)
 
 // Logger is the fundamental interface for all log operations. Log creates a
 // log event from keyvals, a variadic sequence of alternating keys and values.
 // Implementations must be safe for concurrent use by multiple goroutines. In
 // particular, any implementation of Logger that appends to keyvals or
 // modifies or retains any of its elements must make a copy first.
-type Logger interface {
-	Log(keyvals ...interface{}) error
-}
+type Logger = log.Logger
 
 // ErrMissingValue is appended to keyvals slices with odd length to substitute
 // the missing value.
-var ErrMissingValue = errors.New("(MISSING)")
+var ErrMissingValue = log.ErrMissingValue
 
 // With returns a new contextual logger with keyvals prepended to those passed
 // to calls to Log. If logger is also a contextual logger created by With,
@@ -22,25 +22,7 @@ var ErrMissingValue = errors.New("(MISSING)")
 // The returned Logger replaces all value elements (odd indexes) containing a
 // Valuer with their generated value for each call to its Log method.
 func With(logger Logger, keyvals ...interface{}) Logger {
-	if len(keyvals) == 0 {
-		return logger
-	}
-	l := newContext(logger)
-	kvs := append(l.keyvals, keyvals...)
-	if len(kvs)%2 != 0 {
-		kvs = append(kvs, ErrMissingValue)
-	}
-	return &context{
-		logger: l.logger,
-		// Limiting the capacity of the stored keyvals ensures that a new
-		// backing array is created if the slice must grow in Log or With.
-		// Using the extra capacity without copying risks a data race that
-		// would violate the Logger interface contract.
-		keyvals:    kvs[:len(kvs):len(kvs)],
-		hasValuer:  l.hasValuer || containsValuer(keyvals),
-		sKeyvals:   l.sKeyvals,
-		sHasValuer: l.sHasValuer,
-	}
+	return log.With(logger, keyvals...)
 }
 
 // WithPrefix returns a new contextual logger with keyvals prepended to those
@@ -50,31 +32,7 @@ func With(logger Logger, keyvals ...interface{}) Logger {
 // The returned Logger replaces all value elements (odd indexes) containing a
 // Valuer with their generated value for each call to its Log method.
 func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
-	if len(keyvals) == 0 {
-		return logger
-	}
-	l := newContext(logger)
-	// Limiting the capacity of the stored keyvals ensures that a new
-	// backing array is created if the slice must grow in Log or With.
-	// Using the extra capacity without copying risks a data race that
-	// would violate the Logger interface contract.
-	n := len(l.keyvals) + len(keyvals)
-	if len(keyvals)%2 != 0 {
-		n++
-	}
-	kvs := make([]interface{}, 0, n)
-	kvs = append(kvs, keyvals...)
-	if len(kvs)%2 != 0 {
-		kvs = append(kvs, ErrMissingValue)
-	}
-	kvs = append(kvs, l.keyvals...)
-	return &context{
-		logger:     l.logger,
-		keyvals:    kvs,
-		hasValuer:  l.hasValuer || containsValuer(keyvals),
-		sKeyvals:   l.sKeyvals,
-		sHasValuer: l.sHasValuer,
-	}
+	return log.WithPrefix(logger, keyvals...)
 }
 
 // WithSuffix returns a new contextual logger with keyvals appended to those
@@ -84,96 +42,10 @@ func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
 // The returned Logger replaces all value elements (odd indexes) containing a
 // Valuer with their generated value for each call to its Log method.
 func WithSuffix(logger Logger, keyvals ...interface{}) Logger {
-	if len(keyvals) == 0 {
-		return logger
-	}
-	l := newContext(logger)
-	// Limiting the capacity of the stored keyvals ensures that a new
-	// backing array is created if the slice must grow in Log or With.
-	// Using the extra capacity without copying risks a data race that
-	// would violate the Logger interface contract.
-	n := len(l.sKeyvals) + len(keyvals)
-	if len(keyvals)%2 != 0 {
-		n++
-	}
-	kvs := make([]interface{}, 0, n)
-	kvs = append(kvs, keyvals...)
-	if len(kvs)%2 != 0 {
-		kvs = append(kvs, ErrMissingValue)
-	}
-	kvs = append(l.sKeyvals, kvs...)
-	return &context{
-		logger:     l.logger,
-		keyvals:    l.keyvals,
-		hasValuer:  l.hasValuer,
-		sKeyvals:   kvs,
-		sHasValuer: l.sHasValuer || containsValuer(keyvals),
-	}
-}
-
-// context is the Logger implementation returned by With, WithPrefix, and
-// WithSuffix. It wraps a Logger and holds keyvals that it includes in all
-// log events. Its Log method calls bindValues to generate values for each
-// Valuer in the context keyvals.
-//
-// A context must always have the same number of stack frames between calls to
-// its Log method and the eventual binding of Valuers to their value. This
-// requirement comes from the functional requirement to allow a context to
-// resolve application call site information for a Caller stored in the
-// context. To do this we must be able to predict the number of logging
-// functions on the stack when bindValues is called.
-//
-// Two implementation details provide the needed stack depth consistency.
-//
-//    1. newContext avoids introducing an additional layer when asked to
-//       wrap another context.
-//    2. With, WithPrefix, and WithSuffix avoid introducing an additional
-//       layer by returning a newly constructed context with a merged keyvals
-//       rather than simply wrapping the existing context.
-type context struct {
-	logger     Logger
-	keyvals    []interface{}
-	sKeyvals   []interface{} // suffixes
-	hasValuer  bool
-	sHasValuer bool
-}
-
-func newContext(logger Logger) *context {
-	if c, ok := logger.(*context); ok {
-		return c
-	}
-	return &context{logger: logger}
-}
-
-// Log replaces all value elements (odd indexes) containing a Valuer in the
-// stored context with their generated value, appends keyvals, and passes the
-// result to the wrapped Logger.
-func (l *context) Log(keyvals ...interface{}) error {
-	kvs := append(l.keyvals, keyvals...)
-	if len(kvs)%2 != 0 {
-		kvs = append(kvs, ErrMissingValue)
-	}
-	if l.hasValuer {
-		// If no keyvals were appended above then we must copy l.keyvals so
-		// that future log events will reevaluate the stored Valuers.
-		if len(keyvals) == 0 {
-			kvs = append([]interface{}{}, l.keyvals...)
-		}
-		bindValues(kvs[:(len(l.keyvals))])
-	}
-	kvs = append(kvs, l.sKeyvals...)
-	if l.sHasValuer {
-		bindValues(kvs[len(kvs) - len(l.sKeyvals):])
-	}
-	return l.logger.Log(kvs...)
+	return log.WithSuffix(logger, keyvals...)
 }
 
 // LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
 // f is a function with the appropriate signature, LoggerFunc(f) is a Logger
 // object that calls f.
-type LoggerFunc func(...interface{}) error
-
-// Log implements Logger by calling f(keyvals...).
-func (f LoggerFunc) Log(keyvals ...interface{}) error {
-	return f(keyvals...)
-}
+type LoggerFunc = log.LoggerFunc
diff --git a/log/logfmt_logger.go b/log/logfmt_logger.go
index a003052..51cde2c 100644
--- a/log/logfmt_logger.go
+++ b/log/logfmt_logger.go
@@ -1,62 +1,15 @@
 package log
 
 import (
-	"bytes"
 	"io"
-	"sync"
 
-	"github.com/go-logfmt/logfmt"
+	"github.com/go-kit/log"
 )
 
-type logfmtEncoder struct {
-	*logfmt.Encoder
-	buf bytes.Buffer
-}
-
-func (l *logfmtEncoder) Reset() {
-	l.Encoder.Reset()
-	l.buf.Reset()
-}
-
-var logfmtEncoderPool = sync.Pool{
-	New: func() interface{} {
-		var enc logfmtEncoder
-		enc.Encoder = logfmt.NewEncoder(&enc.buf)
-		return &enc
-	},
-}
-
-type logfmtLogger struct {
-	w io.Writer
-}
-
 // NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
 // logfmt format. Each log event produces no more than one call to w.Write.
 // The passed Writer must be safe for concurrent use by multiple goroutines if
 // the returned Logger will be used concurrently.
 func NewLogfmtLogger(w io.Writer) Logger {
-	return &logfmtLogger{w}
-}
-
-func (l logfmtLogger) Log(keyvals ...interface{}) error {
-	enc := logfmtEncoderPool.Get().(*logfmtEncoder)
-	enc.Reset()
-	defer logfmtEncoderPool.Put(enc)
-
-	if err := enc.EncodeKeyvals(keyvals...); err != nil {
-		return err
-	}
-
-	// Add newline to the end of the buffer
-	if err := enc.EndRecord(); err != nil {
-		return err
-	}
-
-	// The Logger interface requires implementations to be safe for concurrent
-	// use by multiple goroutines. For this implementation that means making
-	// only one call to l.w.Write() for each call to Log.
-	if _, err := l.w.Write(enc.buf.Bytes()); err != nil {
-		return err
-	}
-	return nil
+	return log.NewLogfmtLogger(w)
 }
diff --git a/log/logrus/logrus_logger.go b/log/logrus/logrus_logger.go
index a5dc9ca..dbee0f7 100644
--- a/log/logrus/logrus_logger.go
+++ b/log/logrus/logrus_logger.go
@@ -6,7 +6,7 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 	"github.com/sirupsen/logrus"
 )
 
diff --git a/log/nop_logger.go b/log/nop_logger.go
index 1047d62..b02c686 100644
--- a/log/nop_logger.go
+++ b/log/nop_logger.go
@@ -1,8 +1,8 @@
 package log
 
-type nopLogger struct{}
+import "github.com/go-kit/log"
 
 // NewNopLogger returns a logger that doesn't do anything.
-func NewNopLogger() Logger { return nopLogger{} }
-
-func (nopLogger) Log(...interface{}) error { return nil }
+func NewNopLogger() Logger {
+	return log.NewNopLogger()
+}
diff --git a/log/stdlib.go b/log/stdlib.go
index 0338edb..cb604a7 100644
--- a/log/stdlib.go
+++ b/log/stdlib.go
@@ -1,11 +1,9 @@
 package log
 
 import (
-	"bytes"
 	"io"
-	"log"
-	"regexp"
-	"strings"
+
+	"github.com/go-kit/log"
 )
 
 // StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
@@ -14,42 +12,29 @@ import (
 //
 // If you have any choice in the matter, you shouldn't use this. Prefer to
 // redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
-type StdlibWriter struct{}
-
-// Write implements io.Writer.
-func (w StdlibWriter) Write(p []byte) (int, error) {
-	log.Print(strings.TrimSpace(string(p)))
-	return len(p), nil
-}
+type StdlibWriter = log.StdlibWriter
 
 // StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
 // logger's SetOutput. It will extract date/timestamps, filenames, and
 // messages, and place them under relevant keys.
-type StdlibAdapter struct {
-	Logger
-	timestampKey    string
-	fileKey         string
-	messageKey      string
-	prefix          string
-	joinPrefixToMsg bool
-}
+type StdlibAdapter = log.StdlibAdapter
 
 // StdlibAdapterOption sets a parameter for the StdlibAdapter.
-type StdlibAdapterOption func(*StdlibAdapter)
+type StdlibAdapterOption = log.StdlibAdapterOption
 
 // TimestampKey sets the key for the timestamp field. By default, it's "ts".
 func TimestampKey(key string) StdlibAdapterOption {
-	return func(a *StdlibAdapter) { a.timestampKey = key }
+	return log.TimestampKey(key)
 }
 
 // FileKey sets the key for the file and line field. By default, it's "caller".
 func FileKey(key string) StdlibAdapterOption {
-	return func(a *StdlibAdapter) { a.fileKey = key }
+	return log.FileKey(key)
 }
 
 // MessageKey sets the key for the actual log message. By default, it's "msg".
 func MessageKey(key string) StdlibAdapterOption {
-	return func(a *StdlibAdapter) { a.messageKey = key }
+	return log.MessageKey(key)
 }
 
 // Prefix configures the adapter to parse a prefix from stdlib log events. If
@@ -59,93 +44,11 @@ func MessageKey(key string) StdlibAdapterOption {
 // By default, the prefix isn't included in the msg key. Set joinPrefixToMsg to
 // true if you want to include the parsed prefix in the msg.
 func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
-	return func(a *StdlibAdapter) { a.prefix = prefix; a.joinPrefixToMsg = joinPrefixToMsg }
+	return log.Prefix(prefix, joinPrefixToMsg)
 }
 
 // NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
 // logger. It's designed to be passed to log.SetOutput.
 func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
-	a := StdlibAdapter{
-		Logger:       logger,
-		timestampKey: "ts",
-		fileKey:      "caller",
-		messageKey:   "msg",
-	}
-	for _, option := range options {
-		option(&a)
-	}
-	return a
-}
-
-func (a StdlibAdapter) Write(p []byte) (int, error) {
-	p = a.handlePrefix(p)
-
-	result := subexps(p)
-	keyvals := []interface{}{}
-	var timestamp string
-	if date, ok := result["date"]; ok && date != "" {
-		timestamp = date
-	}
-	if time, ok := result["time"]; ok && time != "" {
-		if timestamp != "" {
-			timestamp += " "
-		}
-		timestamp += time
-	}
-	if timestamp != "" {
-		keyvals = append(keyvals, a.timestampKey, timestamp)
-	}
-	if file, ok := result["file"]; ok && file != "" {
-		keyvals = append(keyvals, a.fileKey, file)
-	}
-	if msg, ok := result["msg"]; ok {
-		msg = a.handleMessagePrefix(msg)
-		keyvals = append(keyvals, a.messageKey, msg)
-	}
-	if err := a.Logger.Log(keyvals...); err != nil {
-		return 0, err
-	}
-	return len(p), nil
-}
-
-func (a StdlibAdapter) handlePrefix(p []byte) []byte {
-	if a.prefix != "" {
-		p = bytes.TrimPrefix(p, []byte(a.prefix))
-	}
-	return p
-}
-
-func (a StdlibAdapter) handleMessagePrefix(msg string) string {
-	if a.prefix == "" {
-		return msg
-	}
-
-	msg = strings.TrimPrefix(msg, a.prefix)
-	if a.joinPrefixToMsg {
-		msg = a.prefix + msg
-	}
-	return msg
-}
-
-const (
-	logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
-	logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
-	logRegexpFile = `(?P<file>.+?:[0-9]+)?`
-	logRegexpMsg  = `(: )?(?P<msg>(?s:.*))`
-)
-
-var (
-	logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
-)
-
-func subexps(line []byte) map[string]string {
-	m := logRegexp.FindSubmatch(line)
-	if len(m) < len(logRegexp.SubexpNames()) {
-		return map[string]string{}
-	}
-	result := map[string]string{}
-	for i, name := range logRegexp.SubexpNames() {
-		result[name] = strings.TrimRight(string(m[i]), "\n")
-	}
-	return result
+	return log.NewStdlibAdapter(logger, options...)
 }
diff --git a/log/sync.go b/log/sync.go
index 58bd3ad..bcfee2b 100644
--- a/log/sync.go
+++ b/log/sync.go
@@ -2,8 +2,8 @@ package log
 
 import (
 	"io"
-	"sync"
-	"sync/atomic"
+
+	"github.com/go-kit/log"
 )
 
 // SwapLogger wraps another logger that may be safely replaced while other
@@ -12,29 +12,7 @@ import (
 //
 // SwapLogger serves well as a package global logger that can be changed by
 // importers.
-type SwapLogger struct {
-	logger atomic.Value
-}
-
-type loggerStruct struct {
-	Logger
-}
-
-// Log implements the Logger interface by forwarding keyvals to the currently
-// wrapped logger. It does not log anything if the wrapped logger is nil.
-func (l *SwapLogger) Log(keyvals ...interface{}) error {
-	s, ok := l.logger.Load().(loggerStruct)
-	if !ok || s.Logger == nil {
-		return nil
-	}
-	return s.Log(keyvals...)
-}
-
-// Swap replaces the currently wrapped logger with logger. Swap may be called
-// concurrently with calls to Log from other goroutines.
-func (l *SwapLogger) Swap(logger Logger) {
-	l.logger.Store(loggerStruct{logger})
-}
+type SwapLogger = log.SwapLogger
 
 // NewSyncWriter returns a new writer that is safe for concurrent use by
 // multiple goroutines. Writes to the returned writer are passed on to w. If
@@ -47,53 +25,7 @@ func (l *SwapLogger) Swap(logger Logger) {
 //        Fd() uintptr
 //    }
 func NewSyncWriter(w io.Writer) io.Writer {
-	switch w := w.(type) {
-	case fdWriter:
-		return &fdSyncWriter{fdWriter: w}
-	default:
-		return &syncWriter{Writer: w}
-	}
-}
-
-// syncWriter synchronizes concurrent writes to an io.Writer.
-type syncWriter struct {
-	sync.Mutex
-	io.Writer
-}
-
-// Write writes p to the underlying io.Writer. If another write is already in
-// progress, the calling goroutine blocks until the syncWriter is available.
-func (w *syncWriter) Write(p []byte) (n int, err error) {
-	w.Lock()
-	defer w.Unlock()
-	return w.Writer.Write(p)
-}
-
-// fdWriter is an io.Writer that also has an Fd method. The most common
-// example of an fdWriter is an *os.File.
-type fdWriter interface {
-	io.Writer
-	Fd() uintptr
-}
-
-// fdSyncWriter synchronizes concurrent writes to an fdWriter.
-type fdSyncWriter struct {
-	sync.Mutex
-	fdWriter
-}
-
-// Write writes p to the underlying io.Writer. If another write is already in
-// progress, the calling goroutine blocks until the fdSyncWriter is available.
-func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
-	w.Lock()
-	defer w.Unlock()
-	return w.fdWriter.Write(p)
-}
-
-// syncLogger provides concurrent safe logging for another Logger.
-type syncLogger struct {
-	mu     sync.Mutex
-	logger Logger
+	return log.NewSyncWriter(w)
 }
 
 // NewSyncLogger returns a logger that synchronizes concurrent use of the
@@ -101,13 +33,5 @@ type syncLogger struct {
 // only one goroutine will be allowed to log to the wrapped logger at a time.
 // The other goroutines will block until the logger is available.
 func NewSyncLogger(logger Logger) Logger {
-	return &syncLogger{logger: logger}
-}
-
-// Log logs keyvals to the underlying Logger. If another log is already in
-// progress, the calling goroutine blocks until the syncLogger is available.
-func (l *syncLogger) Log(keyvals ...interface{}) error {
-	l.mu.Lock()
-	defer l.mu.Unlock()
-	return l.logger.Log(keyvals...)
+	return log.NewSyncLogger(logger)
 }
diff --git a/log/syslog/syslog.go b/log/syslog/syslog.go
index f5b8aa1..6171b8e 100644
--- a/log/syslog/syslog.go
+++ b/log/syslog/syslog.go
@@ -1,147 +1,34 @@
-// +build !windows
-// +build !plan9
-// +build !nacl
+//go:build !windows && !plan9 && !nacl
+// +build !windows,!plan9,!nacl
 
+// Deprecated: Use github.com/go-kit/log/syslog instead.
 package syslog
 
 import (
-	"bytes"
 	"io"
-	"sync"
 
-	gosyslog "log/syslog"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-kit/kit/log/level"
+	"github.com/go-kit/log"
+	"github.com/go-kit/log/syslog"
 )
 
 // SyslogWriter is an interface wrapping stdlib syslog Writer.
-type SyslogWriter interface {
-	Write([]byte) (int, error)
-	Close() error
-	Emerg(string) error
-	Alert(string) error
-	Crit(string) error
-	Err(string) error
-	Warning(string) error
-	Notice(string) error
-	Info(string) error
-	Debug(string) error
-}
+type SyslogWriter = syslog.SyslogWriter
 
 // NewSyslogLogger returns a new Logger which writes to syslog in syslog format.
 // The body of the log message is the formatted output from the Logger returned
 // by newLogger.
 func NewSyslogLogger(w SyslogWriter, newLogger func(io.Writer) log.Logger, options ...Option) log.Logger {
-	l := &syslogLogger{
-		w:                w,
-		newLogger:        newLogger,
-		prioritySelector: defaultPrioritySelector,
-		bufPool: sync.Pool{New: func() interface{} {
-			return &loggerBuf{}
-		}},
-	}
-
-	for _, option := range options {
-		option(l)
-	}
-
-	return l
-}
-
-type syslogLogger struct {
-	w                SyslogWriter
-	newLogger        func(io.Writer) log.Logger
-	prioritySelector PrioritySelector
-	bufPool          sync.Pool
-}
-
-func (l *syslogLogger) Log(keyvals ...interface{}) error {
-	level := l.prioritySelector(keyvals...)
-
-	lb := l.getLoggerBuf()
-	defer l.putLoggerBuf(lb)
-	if err := lb.logger.Log(keyvals...); err != nil {
-		return err
-	}
-
-	switch level {
-	case gosyslog.LOG_EMERG:
-		return l.w.Emerg(lb.buf.String())
-	case gosyslog.LOG_ALERT:
-		return l.w.Alert(lb.buf.String())
-	case gosyslog.LOG_CRIT:
-		return l.w.Crit(lb.buf.String())
-	case gosyslog.LOG_ERR:
-		return l.w.Err(lb.buf.String())
-	case gosyslog.LOG_WARNING:
-		return l.w.Warning(lb.buf.String())
-	case gosyslog.LOG_NOTICE:
-		return l.w.Notice(lb.buf.String())
-	case gosyslog.LOG_INFO:
-		return l.w.Info(lb.buf.String())
-	case gosyslog.LOG_DEBUG:
-		return l.w.Debug(lb.buf.String())
-	default:
-		_, err := l.w.Write(lb.buf.Bytes())
-		return err
-	}
-}
-
-type loggerBuf struct {
-	buf    *bytes.Buffer
-	logger log.Logger
-}
-
-func (l *syslogLogger) getLoggerBuf() *loggerBuf {
-	lb := l.bufPool.Get().(*loggerBuf)
-	if lb.buf == nil {
-		lb.buf = &bytes.Buffer{}
-		lb.logger = l.newLogger(lb.buf)
-	} else {
-		lb.buf.Reset()
-	}
-	return lb
-}
-
-func (l *syslogLogger) putLoggerBuf(lb *loggerBuf) {
-	l.bufPool.Put(lb)
+	return syslog.NewSyslogLogger(w, newLogger, options...)
 }
 
 // Option sets a parameter for syslog loggers.
-type Option func(*syslogLogger)
+type Option = syslog.Option
 
 // PrioritySelector inspects the list of keyvals and selects a syslog priority.
-type PrioritySelector func(keyvals ...interface{}) gosyslog.Priority
+type PrioritySelector = syslog.PrioritySelector
 
 // PrioritySelectorOption sets priority selector function to choose syslog
 // priority.
 func PrioritySelectorOption(selector PrioritySelector) Option {
-	return func(l *syslogLogger) { l.prioritySelector = selector }
-}
-
-func defaultPrioritySelector(keyvals ...interface{}) gosyslog.Priority {
-	l := len(keyvals)
-	for i := 0; i < l; i += 2 {
-		if keyvals[i] == level.Key() {
-			var val interface{}
-			if i+1 < l {
-				val = keyvals[i+1]
-			}
-			if v, ok := val.(level.Value); ok {
-				switch v {
-				case level.DebugValue():
-					return gosyslog.LOG_DEBUG
-				case level.InfoValue():
-					return gosyslog.LOG_INFO
-				case level.WarnValue():
-					return gosyslog.LOG_WARNING
-				case level.ErrorValue():
-					return gosyslog.LOG_ERR
-				}
-			}
-		}
-	}
-
-	return gosyslog.LOG_INFO
+	return syslog.PrioritySelectorOption(selector)
 }
diff --git a/log/term/LICENSE b/log/term/LICENSE
deleted file mode 100644
index f090cb4..0000000
--- a/log/term/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Simon Eskildsen
-
-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.
diff --git a/log/term/colorlogger.go b/log/term/colorlogger.go
index 00376ce..c3bbd6c 100644
--- a/log/term/colorlogger.go
+++ b/log/term/colorlogger.go
@@ -1,144 +1,44 @@
 package term
 
 import (
-	"bytes"
-	"fmt"
 	"io"
-	"sync"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
+	"github.com/go-kit/log/term"
 )
 
 // Color represents an ANSI color. The zero value is Default.
-type Color uint8
+type Color = term.Color
 
 // ANSI colors.
 const (
-	Default = Color(iota)
-
-	Black
-	DarkRed
-	DarkGreen
-	Brown
-	DarkBlue
-	DarkMagenta
-	DarkCyan
-	Gray
-
-	DarkGray
-	Red
-	Green
-	Yellow
-	Blue
-	Magenta
-	Cyan
-	White
-
-	numColors
-)
-
-// For more on ANSI escape codes see
-// https://en.wikipedia.org/wiki/ANSI_escape_code. See in particular
-// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors.
-
-var (
-	resetColorBytes = []byte("\x1b[39;49;22m")
-	fgColorBytes    [][]byte
-	bgColorBytes    [][]byte
+	Default = term.Default
+
+	Black       = term.Black
+	DarkRed     = term.DarkRed
+	DarkGreen   = term.DarkGreen
+	Brown       = term.Brown
+	DarkBlue    = term.DarkBlue
+	DarkMagenta = term.DarkMagenta
+	DarkCyan    = term.DarkCyan
+	Gray        = term.Gray
+
+	DarkGray = term.DarkGray
+	Red      = term.Red
+	Green    = term.Green
+	Yellow   = term.Yellow
+	Blue     = term.Blue
+	Magenta  = term.Magenta
+	Cyan     = term.Cyan
+	White    = term.White
 )
 
-func init() {
-	// Default
-	fgColorBytes = append(fgColorBytes, []byte("\x1b[39m"))
-	bgColorBytes = append(bgColorBytes, []byte("\x1b[49m"))
-
-	// dark colors
-	for color := Black; color < DarkGray; color++ {
-		fgColorBytes = append(fgColorBytes, []byte(fmt.Sprintf("\x1b[%dm", 30+color-Black)))
-		bgColorBytes = append(bgColorBytes, []byte(fmt.Sprintf("\x1b[%dm", 40+color-Black)))
-	}
-
-	// bright colors
-	for color := DarkGray; color < numColors; color++ {
-		fgColorBytes = append(fgColorBytes, []byte(fmt.Sprintf("\x1b[%d;1m", 30+color-DarkGray)))
-		bgColorBytes = append(bgColorBytes, []byte(fmt.Sprintf("\x1b[%d;1m", 40+color-DarkGray)))
-	}
-}
-
 // FgBgColor represents a foreground and background color.
-type FgBgColor struct {
-	Fg, Bg Color
-}
-
-func (c FgBgColor) isZero() bool {
-	return c.Fg == Default && c.Bg == Default
-}
+type FgBgColor = term.FgBgColor
 
 // NewColorLogger returns a Logger which writes colored logs to w. ANSI color
 // codes for the colors returned by color are added to the formatted output
 // from the Logger returned by newLogger and the combined result written to w.
 func NewColorLogger(w io.Writer, newLogger func(io.Writer) log.Logger, color func(keyvals ...interface{}) FgBgColor) log.Logger {
-	if color == nil {
-		panic("color func nil")
-	}
-	return &colorLogger{
-		w:             w,
-		newLogger:     newLogger,
-		color:         color,
-		bufPool:       sync.Pool{New: func() interface{} { return &loggerBuf{} }},
-		noColorLogger: newLogger(w),
-	}
-}
-
-type colorLogger struct {
-	w             io.Writer
-	newLogger     func(io.Writer) log.Logger
-	color         func(keyvals ...interface{}) FgBgColor
-	bufPool       sync.Pool
-	noColorLogger log.Logger
-}
-
-func (l *colorLogger) Log(keyvals ...interface{}) error {
-	color := l.color(keyvals...)
-	if color.isZero() {
-		return l.noColorLogger.Log(keyvals...)
-	}
-
-	lb := l.getLoggerBuf()
-	defer l.putLoggerBuf(lb)
-	if color.Fg != Default {
-		lb.buf.Write(fgColorBytes[color.Fg])
-	}
-	if color.Bg != Default {
-		lb.buf.Write(bgColorBytes[color.Bg])
-	}
-	err := lb.logger.Log(keyvals...)
-	if err != nil {
-		return err
-	}
-	if color.Fg != Default || color.Bg != Default {
-		lb.buf.Write(resetColorBytes)
-	}
-	_, err = io.Copy(l.w, lb.buf)
-	return err
-}
-
-type loggerBuf struct {
-	buf    *bytes.Buffer
-	logger log.Logger
-}
-
-func (l *colorLogger) getLoggerBuf() *loggerBuf {
-	lb := l.bufPool.Get().(*loggerBuf)
-	if lb.buf == nil {
-		lb.buf = &bytes.Buffer{}
-		lb.logger = l.newLogger(lb.buf)
-	} else {
-		lb.buf.Reset()
-	}
-	return lb
-}
-
-func (l *colorLogger) putLoggerBuf(cb *loggerBuf) {
-	l.bufPool.Put(cb)
+	return term.NewColorLogger(w, newLogger, color)
 }
diff --git a/log/term/colorwriter_others.go b/log/term/colorwriter.go
similarity index 74%
rename from log/term/colorwriter_others.go
rename to log/term/colorwriter.go
index cc57102..ddfb6a9 100644
--- a/log/term/colorwriter_others.go
+++ b/log/term/colorwriter.go
@@ -1,12 +1,14 @@
-// +build !windows
-
 package term
 
-import "io"
+import (
+	"io"
+
+	"github.com/go-kit/log/term"
+)
 
 // NewColorWriter returns an io.Writer that writes to w and provides cross
 // platform support for ANSI color codes. If w is not a terminal it is
 // returned unmodified.
 func NewColorWriter(w io.Writer) io.Writer {
-	return w
+	return term.NewColorWriter(w)
 }
diff --git a/log/term/colorwriter_windows.go b/log/term/colorwriter_windows.go
deleted file mode 100644
index b27a036..0000000
--- a/log/term/colorwriter_windows.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// The code in this file is adapted from github.com/mattn/go-colorable.
-
-package term
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"strconv"
-	"strings"
-	"syscall"
-	"unsafe"
-)
-
-type colorWriter struct {
-	out     io.Writer
-	handle  syscall.Handle
-	lastbuf bytes.Buffer
-	oldattr word
-}
-
-// NewColorWriter returns an io.Writer that writes to w and provides cross
-// platform support for ANSI color codes. If w is not a terminal it is
-// returned unmodified.
-func NewColorWriter(w io.Writer) io.Writer {
-	if !IsConsole(w) {
-		return w
-	}
-
-	var csbi consoleScreenBufferInfo
-	handle := syscall.Handle(w.(fder).Fd())
-	procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
-
-	return &colorWriter{
-		out:     w,
-		handle:  handle,
-		oldattr: csbi.attributes,
-	}
-}
-
-func (w *colorWriter) Write(data []byte) (n int, err error) {
-	var csbi consoleScreenBufferInfo
-	procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
-
-	er := bytes.NewBuffer(data)
-loop:
-	for {
-		r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
-		if r1 == 0 {
-			break loop
-		}
-
-		c1, _, err := er.ReadRune()
-		if err != nil {
-			break loop
-		}
-		if c1 != 0x1b {
-			fmt.Fprint(w.out, string(c1))
-			continue
-		}
-		c2, _, err := er.ReadRune()
-		if err != nil {
-			w.lastbuf.WriteRune(c1)
-			break loop
-		}
-		if c2 != 0x5b {
-			w.lastbuf.WriteRune(c1)
-			w.lastbuf.WriteRune(c2)
-			continue
-		}
-
-		var buf bytes.Buffer
-		var m rune
-		for {
-			c, _, err := er.ReadRune()
-			if err != nil {
-				w.lastbuf.WriteRune(c1)
-				w.lastbuf.WriteRune(c2)
-				w.lastbuf.Write(buf.Bytes())
-				break loop
-			}
-			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
-				m = c
-				break
-			}
-			buf.Write([]byte(string(c)))
-		}
-
-		switch m {
-		case 'm':
-			attr := csbi.attributes
-			cs := buf.String()
-			if cs == "" {
-				procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
-				continue
-			}
-			token := strings.Split(cs, ";")
-			intensityMode := word(0)
-			for _, ns := range token {
-				if n, err = strconv.Atoi(ns); err == nil {
-					switch {
-					case n == 0:
-						attr = w.oldattr
-					case n == 1:
-						attr |= intensityMode
-					case 30 <= n && n <= 37:
-						attr = (attr & backgroundMask)
-						if (n-30)&1 != 0 {
-							attr |= foregroundRed
-						}
-						if (n-30)&2 != 0 {
-							attr |= foregroundGreen
-						}
-						if (n-30)&4 != 0 {
-							attr |= foregroundBlue
-						}
-						intensityMode = foregroundIntensity
-					case n == 39: // reset foreground color
-						attr &= backgroundMask
-						attr |= w.oldattr & foregroundMask
-					case 40 <= n && n <= 47:
-						attr = (attr & foregroundMask)
-						if (n-40)&1 != 0 {
-							attr |= backgroundRed
-						}
-						if (n-40)&2 != 0 {
-							attr |= backgroundGreen
-						}
-						if (n-40)&4 != 0 {
-							attr |= backgroundBlue
-						}
-						intensityMode = backgroundIntensity
-					case n == 49: // reset background color
-						attr &= foregroundMask
-						attr |= w.oldattr & backgroundMask
-					}
-					procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
-				}
-			}
-		}
-	}
-	return len(data) - w.lastbuf.Len(), nil
-}
-
-var (
-	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
-	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
-)
-
-const (
-	foregroundBlue      = 0x1
-	foregroundGreen     = 0x2
-	foregroundRed       = 0x4
-	foregroundIntensity = 0x8
-	foregroundMask      = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
-	backgroundBlue      = 0x10
-	backgroundGreen     = 0x20
-	backgroundRed       = 0x40
-	backgroundIntensity = 0x80
-	backgroundMask      = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
-)
-
-type (
-	wchar uint16
-	short int16
-	dword uint32
-	word  uint16
-)
-
-type coord struct {
-	x short
-	y short
-}
-
-type smallRect struct {
-	left   short
-	top    short
-	right  short
-	bottom short
-}
-
-type consoleScreenBufferInfo struct {
-	size              coord
-	cursorPosition    coord
-	attributes        word
-	window            smallRect
-	maximumWindowSize coord
-}
diff --git a/log/term/term.go b/log/term/term.go
index 3965f1c..40a38c8 100644
--- a/log/term/term.go
+++ b/log/term/term.go
@@ -1,22 +1,23 @@
 // Package term provides tools for logging to a terminal.
+//
+// Deprecated: Use github.com/go-kit/log/term instead.
 package term
 
 import (
 	"io"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
+	"github.com/go-kit/log/term"
 )
 
 // NewLogger returns a Logger that takes advantage of terminal features if
 // possible. Log events are formatted by the Logger returned by newLogger. If
 // w is a terminal each log event is colored according to the color function.
 func NewLogger(w io.Writer, newLogger func(io.Writer) log.Logger, color func(keyvals ...interface{}) FgBgColor) log.Logger {
-	if !IsTerminal(w) {
-		return newLogger(w)
-	}
-	return NewColorLogger(NewColorWriter(w), newLogger, color)
+	return term.NewLogger(w, newLogger, color)
 }
 
-type fder interface {
-	Fd() uintptr
+// IsTerminal returns true if w writes to a terminal.
+func IsTerminal(w io.Writer) bool {
+	return term.IsTerminal(w)
 }
diff --git a/log/term/terminal_darwin.go b/log/term/terminal_darwin.go
deleted file mode 100644
index 459cf54..0000000
--- a/log/term/terminal_darwin.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Based on ssh/terminal:
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package term
-
-import "syscall"
-
-const ioctlReadTermios = syscall.TIOCGETA
diff --git a/log/term/terminal_freebsd.go b/log/term/terminal_freebsd.go
deleted file mode 100644
index 791d5c6..0000000
--- a/log/term/terminal_freebsd.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package term
-
-import (
-	"syscall"
-)
-
-const ioctlReadTermios = syscall.TIOCGETA
diff --git a/log/term/terminal_linux.go b/log/term/terminal_linux.go
deleted file mode 100644
index ffeab4d..0000000
--- a/log/term/terminal_linux.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Based on ssh/terminal:
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !appengine
-
-package term
-
-import "syscall"
-
-const ioctlReadTermios = syscall.TCGETS
diff --git a/log/term/terminal_notwindows.go b/log/term/terminal_notwindows.go
deleted file mode 100644
index 9c72558..0000000
--- a/log/term/terminal_notwindows.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Based on ssh/terminal:
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux,!appengine darwin freebsd openbsd
-
-package term
-
-import (
-	"io"
-	"syscall"
-	"unsafe"
-)
-
-// IsTerminal returns true if w writes to a terminal.
-func IsTerminal(w io.Writer) bool {
-	fw, ok := w.(fder)
-	if !ok {
-		return false
-	}
-	var termios syscall.Termios
-	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fw.Fd(), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
-	return err == 0
-}
diff --git a/log/term/terminal_openbsd.go b/log/term/terminal_openbsd.go
deleted file mode 100644
index f993166..0000000
--- a/log/term/terminal_openbsd.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package term
-
-import "syscall"
-
-const ioctlReadTermios = syscall.TIOCGETA
diff --git a/log/term/terminal_stub.go b/log/term/terminal_stub.go
deleted file mode 100644
index 7c3e64b..0000000
--- a/log/term/terminal_stub.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Based on ssh/terminal:
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build appengine js
-
-package term
-
-import "io"
-
-// IsTerminal always returns false on AppEngine.
-func IsTerminal(w io.Writer) bool {
-	return false
-}
diff --git a/log/term/terminal_windows.go b/log/term/terminal_windows.go
deleted file mode 100644
index 753fd12..0000000
--- a/log/term/terminal_windows.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Based on ssh/terminal:
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package term
-
-import (
-	"encoding/binary"
-	"io"
-	"regexp"
-	"syscall"
-	"unsafe"
-)
-
-var kernel32 = syscall.NewLazyDLL("kernel32.dll")
-
-var (
-	procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
-	msysPipeNameRegex                = regexp.MustCompile(`\\(cygwin|msys)-\w+-pty\d?-(to|from)-master`)
-)
-
-const (
-	fileNameInfo = 0x02
-)
-
-// IsTerminal returns true if w writes to a terminal.
-func IsTerminal(w io.Writer) bool {
-	return IsConsole(w) || IsMSYSTerminal(w)
-}
-
-// IsConsole returns true if w writes to a Windows console.
-func IsConsole(w io.Writer) bool {
-	var handle syscall.Handle
-
-	if fw, ok := w.(fder); ok {
-		handle = syscall.Handle(fw.Fd())
-	} else {
-		// The writer has no file-descriptor and so can't be a terminal.
-		return false
-	}
-
-	var st uint32
-	err := syscall.GetConsoleMode(handle, &st)
-
-	// If the handle is attached to a terminal, GetConsoleMode returns a
-	// non-zero value containing the console mode flags. We don't care about
-	// the specifics of flags, just that it is not zero.
-	return (err == nil && st != 0)
-}
-
-// IsMSYSTerminal returns true if w writes to a MSYS/MSYS2 terminal.
-func IsMSYSTerminal(w io.Writer) bool {
-	var handle syscall.Handle
-
-	if fw, ok := w.(fder); ok {
-		handle = syscall.Handle(fw.Fd())
-	} else {
-		// The writer has no file-descriptor and so can't be a terminal.
-		return false
-	}
-
-	// MSYS(2) terminal reports as a pipe for STDIN/STDOUT/STDERR. If it isn't
-	// a pipe, it can't be a MSYS(2) terminal.
-	filetype, err := syscall.GetFileType(handle)
-
-	if filetype != syscall.FILE_TYPE_PIPE || err != nil {
-		return false
-	}
-
-	// MSYS2/Cygwin terminal's name looks like: \msys-dd50a72ab4668b33-pty2-to-master
-	data := make([]byte, 256, 256)
-
-	r, _, e := syscall.Syscall6(
-		procGetFileInformationByHandleEx.Addr(),
-		4,
-		uintptr(handle),
-		uintptr(fileNameInfo),
-		uintptr(unsafe.Pointer(&data[0])),
-		uintptr(len(data)),
-		0,
-		0,
-	)
-
-	if r != 0 && e == 0 {
-		// The first 4 bytes of the buffer are the size of the UTF16 name, in bytes.
-		unameLen := binary.LittleEndian.Uint32(data[:4]) / 2
-		uname := make([]uint16, unameLen, unameLen)
-
-		for i := uint32(0); i < unameLen; i++ {
-			uname[i] = binary.LittleEndian.Uint16(data[i*2+4 : i*2+2+4])
-		}
-
-		name := syscall.UTF16ToString(uname)
-
-		return msysPipeNameRegex.MatchString(name)
-	}
-
-	return false
-}
diff --git a/log/value.go b/log/value.go
index 3ce197f..96d783b 100644
--- a/log/value.go
+++ b/log/value.go
@@ -1,37 +1,15 @@
 package log
 
 import (
-	"runtime"
-	"strconv"
-	"strings"
 	"time"
+
+	"github.com/go-kit/log"
 )
 
 // A Valuer generates a log value. When passed to With, WithPrefix, or
 // WithSuffix in a value element (odd indexes), it represents a dynamic
 // value which is re-evaluated with each log event.
-type Valuer func() interface{}
-
-// bindValues replaces all value elements (odd indexes) containing a Valuer
-// with their generated value.
-func bindValues(keyvals []interface{}) {
-	for i := 1; i < len(keyvals); i += 2 {
-		if v, ok := keyvals[i].(Valuer); ok {
-			keyvals[i] = v()
-		}
-	}
-}
-
-// containsValuer returns true if any of the value elements (odd indexes)
-// contain a Valuer.
-func containsValuer(keyvals []interface{}) bool {
-	for i := 1; i < len(keyvals); i += 2 {
-		if _, ok := keyvals[i].(Valuer); ok {
-			return true
-		}
-	}
-	return false
-}
+type Valuer = log.Valuer
 
 // Timestamp returns a timestamp Valuer. It invokes the t function to get the
 // time; unless you are doing something tricky, pass time.Now.
@@ -39,7 +17,7 @@ func containsValuer(keyvals []interface{}) bool {
 // Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
 // are TimestampFormats that use the RFC3339Nano format.
 func Timestamp(t func() time.Time) Valuer {
-	return func() interface{} { return t() }
+	return log.Timestamp(t)
 }
 
 // TimestampFormat returns a timestamp Valuer with a custom time format. It
@@ -50,61 +28,25 @@ func Timestamp(t func() time.Time) Valuer {
 // Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
 // are TimestampFormats that use the RFC3339Nano format.
 func TimestampFormat(t func() time.Time, layout string) Valuer {
-	return func() interface{} {
-		return timeFormat{
-			time:   t(),
-			layout: layout,
-		}
-	}
-}
-
-// A timeFormat represents an instant in time and a layout used when
-// marshaling to a text format.
-type timeFormat struct {
-	time   time.Time
-	layout string
-}
-
-func (tf timeFormat) String() string {
-	return tf.time.Format(tf.layout)
-}
-
-// MarshalText implements encoding.TextMarshaller.
-func (tf timeFormat) MarshalText() (text []byte, err error) {
-	// The following code adapted from the standard library time.Time.Format
-	// method. Using the same undocumented magic constant to extend the size
-	// of the buffer as seen there.
-	b := make([]byte, 0, len(tf.layout)+10)
-	b = tf.time.AppendFormat(b, tf.layout)
-	return b, nil
+	return log.TimestampFormat(t, layout)
 }
 
 // Caller returns a Valuer that returns a file and line from a specified depth
 // in the callstack. Users will probably want to use DefaultCaller.
 func Caller(depth int) Valuer {
-	return func() interface{} {
-		_, file, line, _ := runtime.Caller(depth)
-		idx := strings.LastIndexByte(file, '/')
-		// using idx+1 below handles both of following cases:
-		// idx == -1 because no "/" was found, or
-		// idx >= 0 and we want to start at the character after the found "/".
-		return file[idx+1:] + ":" + strconv.Itoa(line)
-	}
+	return log.Caller(depth)
 }
 
 var (
 	// DefaultTimestamp is a Valuer that returns the current wallclock time,
 	// respecting time zones, when bound.
-	DefaultTimestamp = TimestampFormat(time.Now, time.RFC3339Nano)
+	DefaultTimestamp = log.DefaultTimestamp
 
 	// DefaultTimestampUTC is a Valuer that returns the current time in UTC
 	// when bound.
-	DefaultTimestampUTC = TimestampFormat(
-		func() time.Time { return time.Now().UTC() },
-		time.RFC3339Nano,
-	)
+	DefaultTimestampUTC = log.DefaultTimestampUTC
 
 	// DefaultCaller is a Valuer that returns the file and line where the Log
 	// method was invoked. It can only be used with log.With.
-	DefaultCaller = Caller(3)
+	DefaultCaller = log.DefaultCaller
 )
diff --git a/log/zap/zap_sugar_logger.go b/log/zap/zap_sugar_logger.go
index 97fe645..10d7468 100644
--- a/log/zap/zap_sugar_logger.go
+++ b/log/zap/zap_sugar_logger.go
@@ -1,7 +1,7 @@
 package zap
 
 import (
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 	"go.uber.org/zap"
 	"go.uber.org/zap/zapcore"
 )
diff --git a/metrics/cloudwatch/cloudwatch.go b/metrics/cloudwatch/cloudwatch.go
index 43121f5..a77c186 100644
--- a/metrics/cloudwatch/cloudwatch.go
+++ b/metrics/cloudwatch/cloudwatch.go
@@ -12,10 +12,10 @@ import (
 	"github.com/aws/aws-sdk-go/service/cloudwatch"
 	"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/generic"
 	"github.com/go-kit/kit/metrics/internal/lv"
+	"github.com/go-kit/log"
 )
 
 const (
diff --git a/metrics/cloudwatch2/cloudwatch2.go b/metrics/cloudwatch2/cloudwatch2.go
index eed6cd6..82ca122 100644
--- a/metrics/cloudwatch2/cloudwatch2.go
+++ b/metrics/cloudwatch2/cloudwatch2.go
@@ -13,10 +13,10 @@ import (
 	"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
 	"golang.org/x/sync/errgroup"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/internal/convert"
 	"github.com/go-kit/kit/metrics/internal/lv"
+	"github.com/go-kit/log"
 )
 
 const (
diff --git a/metrics/dogstatsd/dogstatsd.go b/metrics/dogstatsd/dogstatsd.go
index d9618fd..ac18e61 100644
--- a/metrics/dogstatsd/dogstatsd.go
+++ b/metrics/dogstatsd/dogstatsd.go
@@ -20,12 +20,12 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/generic"
 	"github.com/go-kit/kit/metrics/internal/lv"
 	"github.com/go-kit/kit/metrics/internal/ratemap"
 	"github.com/go-kit/kit/util/conn"
+	"github.com/go-kit/log"
 )
 
 // Dogstatsd receives metrics observations and forwards them to a DogStatsD
diff --git a/metrics/graphite/graphite.go b/metrics/graphite/graphite.go
index ddb05c2..c8237c1 100644
--- a/metrics/graphite/graphite.go
+++ b/metrics/graphite/graphite.go
@@ -14,10 +14,10 @@ import (
 	"sync"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/generic"
 	"github.com/go-kit/kit/util/conn"
+	"github.com/go-kit/log"
 )
 
 // Graphite receives metrics observations and forwards them to a Graphite server.
diff --git a/metrics/influx/influx.go b/metrics/influx/influx.go
index a73ffd7..eda2f22 100644
--- a/metrics/influx/influx.go
+++ b/metrics/influx/influx.go
@@ -9,10 +9,10 @@ import (
 
 	influxdb "github.com/influxdata/influxdb1-client/v2"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/generic"
 	"github.com/go-kit/kit/metrics/internal/lv"
+	"github.com/go-kit/log"
 )
 
 // Influx is a store for metrics that will be emitted to an Influx database.
diff --git a/metrics/influxstatsd/influxstatsd.go b/metrics/influxstatsd/influxstatsd.go
index 2efe068..0904cf4 100644
--- a/metrics/influxstatsd/influxstatsd.go
+++ b/metrics/influxstatsd/influxstatsd.go
@@ -19,12 +19,12 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/generic"
 	"github.com/go-kit/kit/metrics/internal/lv"
 	"github.com/go-kit/kit/metrics/internal/ratemap"
 	"github.com/go-kit/kit/util/conn"
+	"github.com/go-kit/log"
 )
 
 // Influxstatsd receives metrics observations and forwards them to a server.
diff --git a/metrics/statsd/statsd.go b/metrics/statsd/statsd.go
index d2cfbc7..3bfa27c 100644
--- a/metrics/statsd/statsd.go
+++ b/metrics/statsd/statsd.go
@@ -14,11 +14,11 @@ import (
 	"io"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/internal/lv"
 	"github.com/go-kit/kit/metrics/internal/ratemap"
 	"github.com/go-kit/kit/util/conn"
+	"github.com/go-kit/log"
 )
 
 // Statsd receives metrics observations and forwards them to a StatsD server.
diff --git a/sd/consul/instancer.go b/sd/consul/instancer.go
index 75f4fc6..ce267ec 100644
--- a/sd/consul/instancer.go
+++ b/sd/consul/instancer.go
@@ -7,10 +7,10 @@ import (
 
 	consul "github.com/hashicorp/consul/api"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
 	"github.com/go-kit/kit/util/conn"
+	"github.com/go-kit/log"
 )
 
 const defaultIndex = 0
diff --git a/sd/consul/registrar.go b/sd/consul/registrar.go
index bf26bd2..c1bdb95 100644
--- a/sd/consul/registrar.go
+++ b/sd/consul/registrar.go
@@ -5,7 +5,7 @@ import (
 
 	stdconsul "github.com/hashicorp/consul/api"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // Registrar registers service instance liveness information to Consul.
diff --git a/sd/dnssrv/instancer.go b/sd/dnssrv/instancer.go
index 448ff93..e22cc8a 100644
--- a/sd/dnssrv/instancer.go
+++ b/sd/dnssrv/instancer.go
@@ -6,9 +6,9 @@ import (
 	"net"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 // ErrPortZero is returned by the resolve machinery
diff --git a/sd/endpoint_cache.go b/sd/endpoint_cache.go
index 6a4938f..e981f0d 100644
--- a/sd/endpoint_cache.go
+++ b/sd/endpoint_cache.go
@@ -7,7 +7,7 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // endpointCache collects the most recent set of instances from a service discovery
diff --git a/sd/endpointer.go b/sd/endpointer.go
index 5c98fc7..5d225e4 100644
--- a/sd/endpointer.go
+++ b/sd/endpointer.go
@@ -4,7 +4,7 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // Endpointer listens to a service discovery system and yields a set of
diff --git a/sd/etcd/instancer.go b/sd/etcd/instancer.go
index 693fc7a..2c192b4 100644
--- a/sd/etcd/instancer.go
+++ b/sd/etcd/instancer.go
@@ -1,9 +1,9 @@
 package etcd
 
 import (
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 // Instancer yields instances stored in a certain etcd keyspace. Any kind of
diff --git a/sd/etcd/registrar.go b/sd/etcd/registrar.go
index 08b2f8f..aef4d20 100644
--- a/sd/etcd/registrar.go
+++ b/sd/etcd/registrar.go
@@ -6,7 +6,7 @@ import (
 
 	etcd "go.etcd.io/etcd/client/v2"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 const minHeartBeatTime = 500 * time.Millisecond
diff --git a/sd/etcdv3/instancer.go b/sd/etcdv3/instancer.go
index 17442b1..f4d0fb8 100644
--- a/sd/etcdv3/instancer.go
+++ b/sd/etcdv3/instancer.go
@@ -1,9 +1,9 @@
 package etcdv3
 
 import (
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 // Instancer yields instances stored in a certain etcd keyspace. Any kind of
diff --git a/sd/etcdv3/registrar.go b/sd/etcdv3/registrar.go
index 27f7a6b..e0f065c 100644
--- a/sd/etcdv3/registrar.go
+++ b/sd/etcdv3/registrar.go
@@ -4,7 +4,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 const minHeartBeatTime = 500 * time.Millisecond
diff --git a/sd/eureka/instancer.go b/sd/eureka/instancer.go
index d00b98c..2849cf4 100644
--- a/sd/eureka/instancer.go
+++ b/sd/eureka/instancer.go
@@ -5,9 +5,9 @@ import (
 
 	"github.com/hudl/fargo"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 // Instancer yields instances stored in the Eureka registry for the given app.
diff --git a/sd/eureka/registrar.go b/sd/eureka/registrar.go
index 7af7836..2d84a7c 100644
--- a/sd/eureka/registrar.go
+++ b/sd/eureka/registrar.go
@@ -8,8 +8,8 @@ import (
 
 	"github.com/hudl/fargo"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 // Matches official Netflix Java client default.
diff --git a/sd/zk/client.go b/sd/zk/client.go
index b88ad14..4fb6a31 100644
--- a/sd/zk/client.go
+++ b/sd/zk/client.go
@@ -8,7 +8,7 @@ import (
 
 	"github.com/go-zookeeper/zk"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // DefaultACL is the default ACL to use for creating znodes.
diff --git a/sd/zk/instancer.go b/sd/zk/instancer.go
index de50eae..b578f75 100644
--- a/sd/zk/instancer.go
+++ b/sd/zk/instancer.go
@@ -3,9 +3,9 @@ package zk
 import (
 	"github.com/go-zookeeper/zk"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 // Instancer yield instances stored in a certain ZooKeeper path. Any kind of
diff --git a/sd/zk/logwrapper.go b/sd/zk/logwrapper.go
index ab7d309..a5ccca3 100644
--- a/sd/zk/logwrapper.go
+++ b/sd/zk/logwrapper.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/go-zookeeper/zk"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // wrapLogger wraps a Go kit logger so we can use it as the logging service for
diff --git a/sd/zk/registrar.go b/sd/zk/registrar.go
index 379a4a5..d130687 100644
--- a/sd/zk/registrar.go
+++ b/sd/zk/registrar.go
@@ -1,6 +1,6 @@
 package zk
 
-import "github.com/go-kit/kit/log"
+import "github.com/go-kit/log"
 
 // Registrar registers service instance liveness information to ZooKeeper.
 type Registrar struct {
diff --git a/tracing/opentracing/grpc.go b/tracing/opentracing/grpc.go
index 2257bec..3b0a65d 100644
--- a/tracing/opentracing/grpc.go
+++ b/tracing/opentracing/grpc.go
@@ -9,7 +9,7 @@ import (
 	"github.com/opentracing/opentracing-go/ext"
 	"google.golang.org/grpc/metadata"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // ContextToGRPC returns a grpc RequestFunc that injects an OpenTracing Span
diff --git a/tracing/opentracing/http.go b/tracing/opentracing/http.go
index 23c71de..29f0442 100644
--- a/tracing/opentracing/http.go
+++ b/tracing/opentracing/http.go
@@ -9,8 +9,8 @@ import (
 	opentracing "github.com/opentracing/opentracing-go"
 	"github.com/opentracing/opentracing-go/ext"
 
-	"github.com/go-kit/kit/log"
 	kithttp "github.com/go-kit/kit/transport/http"
+	"github.com/go-kit/log"
 )
 
 // ContextToHTTP returns an http RequestFunc that injects an OpenTracing Span
diff --git a/tracing/zipkin/grpc.go b/tracing/zipkin/grpc.go
index 6572f4f..82666e2 100644
--- a/tracing/zipkin/grpc.go
+++ b/tracing/zipkin/grpc.go
@@ -10,8 +10,8 @@ import (
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/status"
 
-	"github.com/go-kit/kit/log"
 	kitgrpc "github.com/go-kit/kit/transport/grpc"
+	"github.com/go-kit/log"
 )
 
 // GRPCClientTrace enables native Zipkin tracing of a Go kit gRPC transport
diff --git a/tracing/zipkin/http.go b/tracing/zipkin/http.go
index 4b0bd02..5236b6e 100644
--- a/tracing/zipkin/http.go
+++ b/tracing/zipkin/http.go
@@ -9,8 +9,8 @@ import (
 	"github.com/openzipkin/zipkin-go/model"
 	"github.com/openzipkin/zipkin-go/propagation/b3"
 
-	"github.com/go-kit/kit/log"
 	kithttp "github.com/go-kit/kit/transport/http"
+	"github.com/go-kit/log"
 )
 
 // HTTPClientTrace enables native Zipkin tracing of a Go kit HTTP transport
diff --git a/tracing/zipkin/options.go b/tracing/zipkin/options.go
index 8d54801..873a05e 100644
--- a/tracing/zipkin/options.go
+++ b/tracing/zipkin/options.go
@@ -3,7 +3,7 @@ package zipkin
 import (
 	"net/http"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // TracerOption allows for functional options to our Zipkin tracing middleware.
diff --git a/transport/amqp/subscriber.go b/transport/amqp/subscriber.go
index 2e76c5e..188fb9f 100644
--- a/transport/amqp/subscriber.go
+++ b/transport/amqp/subscriber.go
@@ -6,8 +6,8 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 	"github.com/streadway/amqp"
 )
 
diff --git a/transport/awslambda/handler.go b/transport/awslambda/handler.go
index e03e600..5495fd2 100644
--- a/transport/awslambda/handler.go
+++ b/transport/awslambda/handler.go
@@ -4,8 +4,8 @@ import (
 	"context"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 )
 
 // Handler wraps an endpoint.
diff --git a/transport/error_handler.go b/transport/error_handler.go
index 9f25596..2456df1 100644
--- a/transport/error_handler.go
+++ b/transport/error_handler.go
@@ -3,7 +3,7 @@ package transport
 import (
 	"context"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // ErrorHandler receives a transport error to be processed for diagnostic purposes.
diff --git a/transport/grpc/server.go b/transport/grpc/server.go
index 8fa6298..e83aeac 100644
--- a/transport/grpc/server.go
+++ b/transport/grpc/server.go
@@ -7,8 +7,8 @@ import (
 	"google.golang.org/grpc/metadata"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 )
 
 // Handler which should be called from the gRPC binding of the service
diff --git a/transport/http/jsonrpc/server.go b/transport/http/jsonrpc/server.go
index 3250275..f35caef 100644
--- a/transport/http/jsonrpc/server.go
+++ b/transport/http/jsonrpc/server.go
@@ -7,8 +7,8 @@ import (
 	"io"
 	"net/http"
 
-	"github.com/go-kit/kit/log"
 	httptransport "github.com/go-kit/kit/transport/http"
+	"github.com/go-kit/log"
 )
 
 type requestIDKeyType struct{}
diff --git a/transport/http/server.go b/transport/http/server.go
index 34912d0..dfd1ff3 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -6,8 +6,8 @@ import (
 	"net/http"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 )
 
 // Server wraps an endpoint and implements http.Handler.
diff --git a/transport/nats/subscriber.go b/transport/nats/subscriber.go
index 33f4a15..4accab8 100644
--- a/transport/nats/subscriber.go
+++ b/transport/nats/subscriber.go
@@ -5,8 +5,8 @@ import (
 	"encoding/json"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 
 	"github.com/nats-io/nats.go"
 )
diff --git a/util/conn/manager.go b/util/conn/manager.go
index b1e16c8..f99b932 100644
--- a/util/conn/manager.go
+++ b/util/conn/manager.go
@@ -6,7 +6,7 @@ import (
 	"net"
 	"time"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // Dialer imitates net.Dial. Dialer is assumed to yield connections that are


Test patch:
diff --git a/log/benchmark_test.go b/log/benchmark_test.go
deleted file mode 100644
index 126bfa5..0000000
--- a/log/benchmark_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package log_test
-
-import (
-	"testing"
-
-	"github.com/go-kit/kit/log"
-)
-
-func benchmarkRunner(b *testing.B, logger log.Logger, f func(log.Logger)) {
-	lc := log.With(logger, "common_key", "common_value")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		f(lc)
-	}
-}
-
-var (
-	baseMessage = func(logger log.Logger) { logger.Log("foo_key", "foo_value") }
-	withMessage = func(logger log.Logger) { log.With(logger, "a", "b").Log("c", "d") }
-)
diff --git a/log/concurrency_test.go b/log/concurrency_test.go
deleted file mode 100644
index 95a749e..0000000
--- a/log/concurrency_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package log_test
-
-import (
-	"math"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-)
-
-// These test are designed to be run with the race detector.
-
-func testConcurrency(t *testing.T, logger log.Logger, total int) {
-	n := int(math.Sqrt(float64(total)))
-	share := total / n
-
-	errC := make(chan error, n)
-
-	for i := 0; i < n; i++ {
-		go func() {
-			errC <- spam(logger, share)
-		}()
-	}
-
-	for i := 0; i < n; i++ {
-		err := <-errC
-		if err != nil {
-			t.Fatalf("concurrent logging error: %v", err)
-		}
-	}
-}
-
-func spam(logger log.Logger, count int) error {
-	for i := 0; i < count; i++ {
-		err := logger.Log("key", i)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/log/deprecated_levels/levels_test.go b/log/deprecated_levels/levels_test.go
index 8d4a7f5..57854ea 100644
--- a/log/deprecated_levels/levels_test.go
+++ b/log/deprecated_levels/levels_test.go
@@ -5,8 +5,8 @@ import (
 	"os"
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	levels "github.com/go-kit/kit/log/deprecated_levels"
+	"github.com/go-kit/log"
 )
 
 func TestDefaultLevels(t *testing.T) {
diff --git a/log/json_logger_test.go b/log/json_logger_test.go
deleted file mode 100644
index 6432fc8..0000000
--- a/log/json_logger_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package log_test
-
-import (
-	"bytes"
-	"errors"
-	"io/ioutil"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-)
-
-func TestJSONLoggerCaller(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	logger = log.With(logger, "caller", log.DefaultCaller)
-
-	if err := logger.Log(); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"caller":"json_logger_test.go:18"}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func TestJSONLogger(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	if err := logger.Log("err", errors.New("err"), "m", map[string]int{"0": 0}, "a", []int{1, 2, 3}); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"a":[1,2,3],"err":"err","m":{"0":0}}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func TestJSONLoggerMissingValue(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	if err := logger.Log("k"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"k":"(MISSING)"}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func TestJSONLoggerNilStringerKey(t *testing.T) {
-	t.Parallel()
-
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	if err := logger.Log((*stringer)(nil), "v"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"NULL":"v"}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func TestJSONLoggerNilErrorValue(t *testing.T) {
-	t.Parallel()
-
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	if err := logger.Log("err", (*stringError)(nil)); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"err":null}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func TestJSONLoggerNoHTMLEscape(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewJSONLogger(buf)
-	if err := logger.Log("k", "<&>"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := `{"k":"<&>"}`+"\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave%#v", want, have)
-	}
-}
-
-// aller implements json.Marshaler, encoding.TextMarshaler, and fmt.Stringer.
-type aller struct{}
-
-func (aller) MarshalJSON() ([]byte, error) {
-	return []byte("\"json\""), nil
-}
-
-func (aller) MarshalText() ([]byte, error) {
-	return []byte("text"), nil
-}
-
-func (aller) String() string {
-	return "string"
-}
-
-func (aller) Error() string {
-	return "error"
-}
-
-// textstringer implements encoding.TextMarshaler and fmt.Stringer.
-type textstringer struct{}
-
-func (textstringer) MarshalText() ([]byte, error) {
-	return []byte("text"), nil
-}
-
-func (textstringer) String() string {
-	return "string"
-}
-
-func TestJSONLoggerStringValue(t *testing.T) {
-	t.Parallel()
-	tests := []struct {
-		v        interface{}
-		expected string
-	}{
-		{
-			v:        aller{},
-			expected: `{"v":"json"}`,
-		},
-		{
-			v:        textstringer{},
-			expected: `{"v":"text"}`,
-		},
-		{
-			v:        stringer("string"),
-			expected: `{"v":"string"}`,
-		},
-	}
-
-	for _, test := range tests {
-		buf := &bytes.Buffer{}
-		logger := log.NewJSONLogger(buf)
-		if err := logger.Log("v", test.v); err != nil {
-			t.Fatal(err)
-		}
-
-		if want, have := test.expected+"\n", buf.String(); want != have {
-			t.Errorf("\nwant %#v\nhave %#v", want, have)
-		}
-	}
-}
-
-type stringer string
-
-func (s stringer) String() string {
-	return string(s)
-}
-
-type stringError string
-
-func (s stringError) Error() string {
-	return string(s)
-}
-
-func BenchmarkJSONLoggerSimple(b *testing.B) {
-	benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), baseMessage)
-}
-
-func BenchmarkJSONLoggerContextual(b *testing.B) {
-	benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), withMessage)
-}
-
-func TestJSONLoggerConcurrency(t *testing.T) {
-	t.Parallel()
-	testConcurrency(t, log.NewJSONLogger(ioutil.Discard), 10000)
-}
diff --git a/log/level/benchmark_test.go b/log/level/benchmark_test.go
deleted file mode 100644
index 4fca6f0..0000000
--- a/log/level/benchmark_test.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package level_test
-
-import (
-	"io/ioutil"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-kit/kit/log/level"
-)
-
-func Benchmark(b *testing.B) {
-	contexts := []struct {
-		name    string
-		context func(log.Logger) log.Logger
-	}{
-		{"NoContext", func(l log.Logger) log.Logger {
-			return l
-		}},
-		{"TimeContext", func(l log.Logger) log.Logger {
-			return log.With(l, "time", log.DefaultTimestampUTC)
-		}},
-		{"CallerContext", func(l log.Logger) log.Logger {
-			return log.With(l, "caller", log.DefaultCaller)
-		}},
-		{"TimeCallerReqIDContext", func(l log.Logger) log.Logger {
-			return log.With(l, "time", log.DefaultTimestampUTC, "caller", log.DefaultCaller, "reqID", 29)
-		}},
-	}
-
-	loggers := []struct {
-		name   string
-		logger log.Logger
-	}{
-		{"Nop", log.NewNopLogger()},
-		{"Logfmt", log.NewLogfmtLogger(ioutil.Discard)},
-		{"JSON", log.NewJSONLogger(ioutil.Discard)},
-	}
-
-	filters := []struct {
-		name   string
-		filter func(log.Logger) log.Logger
-	}{
-		{"Baseline", func(l log.Logger) log.Logger {
-			return l
-		}},
-		{"DisallowedLevel", func(l log.Logger) log.Logger {
-			return level.NewFilter(l, level.AllowInfo())
-		}},
-		{"AllowedLevel", func(l log.Logger) log.Logger {
-			return level.NewFilter(l, level.AllowAll())
-		}},
-	}
-
-	for _, c := range contexts {
-		b.Run(c.name, func(b *testing.B) {
-			for _, f := range filters {
-				b.Run(f.name, func(b *testing.B) {
-					for _, l := range loggers {
-						b.Run(l.name, func(b *testing.B) {
-							logger := c.context(f.filter(l.logger))
-							b.ResetTimer()
-							b.ReportAllocs()
-							for i := 0; i < b.N; i++ {
-								level.Debug(logger).Log("foo", "bar")
-							}
-						})
-					}
-				})
-			}
-		})
-	}
-}
diff --git a/log/level/level_test.go b/log/level/level_test.go
deleted file mode 100644
index e362eff..0000000
--- a/log/level/level_test.go
+++ /dev/null
@@ -1,235 +0,0 @@
-package level_test
-
-import (
-	"bytes"
-	"errors"
-	"io"
-	"strings"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-kit/kit/log/level"
-)
-
-func TestVariousLevels(t *testing.T) {
-	testCases := []struct {
-		name    string
-		allowed level.Option
-		want    string
-	}{
-		{
-			"AllowAll",
-			level.AllowAll(),
-			strings.Join([]string{
-				`{"level":"debug","this is":"debug log"}`,
-				`{"level":"info","this is":"info log"}`,
-				`{"level":"warn","this is":"warn log"}`,
-				`{"level":"error","this is":"error log"}`,
-			}, "\n"),
-		},
-		{
-			"AllowDebug",
-			level.AllowDebug(),
-			strings.Join([]string{
-				`{"level":"debug","this is":"debug log"}`,
-				`{"level":"info","this is":"info log"}`,
-				`{"level":"warn","this is":"warn log"}`,
-				`{"level":"error","this is":"error log"}`,
-			}, "\n"),
-		},
-		{
-			"AllowInfo",
-			level.AllowInfo(),
-			strings.Join([]string{
-				`{"level":"info","this is":"info log"}`,
-				`{"level":"warn","this is":"warn log"}`,
-				`{"level":"error","this is":"error log"}`,
-			}, "\n"),
-		},
-		{
-			"AllowWarn",
-			level.AllowWarn(),
-			strings.Join([]string{
-				`{"level":"warn","this is":"warn log"}`,
-				`{"level":"error","this is":"error log"}`,
-			}, "\n"),
-		},
-		{
-			"AllowError",
-			level.AllowError(),
-			strings.Join([]string{
-				`{"level":"error","this is":"error log"}`,
-			}, "\n"),
-		},
-		{
-			"AllowNone",
-			level.AllowNone(),
-			``,
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			var buf bytes.Buffer
-			logger := level.NewFilter(log.NewJSONLogger(&buf), tc.allowed)
-
-			level.Debug(logger).Log("this is", "debug log")
-			level.Info(logger).Log("this is", "info log")
-			level.Warn(logger).Log("this is", "warn log")
-			level.Error(logger).Log("this is", "error log")
-
-			if want, have := tc.want, strings.TrimSpace(buf.String()); want != have {
-				t.Errorf("\nwant:\n%s\nhave:\n%s", want, have)
-			}
-		})
-	}
-}
-
-func TestErrNotAllowed(t *testing.T) {
-	myError := errors.New("squelched!")
-	opts := []level.Option{
-		level.AllowWarn(),
-		level.ErrNotAllowed(myError),
-	}
-	logger := level.NewFilter(log.NewNopLogger(), opts...)
-
-	if want, have := myError, level.Info(logger).Log("foo", "bar"); want != have {
-		t.Errorf("want %#+v, have %#+v", want, have)
-	}
-
-	if want, have := error(nil), level.Warn(logger).Log("foo", "bar"); want != have {
-		t.Errorf("want %#+v, have %#+v", want, have)
-	}
-}
-
-func TestErrNoLevel(t *testing.T) {
-	myError := errors.New("no level specified")
-
-	var buf bytes.Buffer
-	opts := []level.Option{
-		level.SquelchNoLevel(true),
-		level.ErrNoLevel(myError),
-	}
-	logger := level.NewFilter(log.NewJSONLogger(&buf), opts...)
-
-	if want, have := myError, logger.Log("foo", "bar"); want != have {
-		t.Errorf("want %v, have %v", want, have)
-	}
-	if want, have := ``, strings.TrimSpace(buf.String()); want != have {
-		t.Errorf("\nwant '%s'\nhave '%s'", want, have)
-	}
-}
-
-func TestAllowNoLevel(t *testing.T) {
-	var buf bytes.Buffer
-	opts := []level.Option{
-		level.SquelchNoLevel(false),
-		level.ErrNoLevel(errors.New("I should never be returned!")),
-	}
-	logger := level.NewFilter(log.NewJSONLogger(&buf), opts...)
-
-	if want, have := error(nil), logger.Log("foo", "bar"); want != have {
-		t.Errorf("want %v, have %v", want, have)
-	}
-	if want, have := `{"foo":"bar"}`, strings.TrimSpace(buf.String()); want != have {
-		t.Errorf("\nwant '%s'\nhave '%s'", want, have)
-	}
-}
-
-func TestLevelContext(t *testing.T) {
-	var buf bytes.Buffer
-
-	// Wrapping the level logger with a context allows users to use
-	// log.DefaultCaller as per normal.
-	var logger log.Logger
-	logger = log.NewLogfmtLogger(&buf)
-	logger = level.NewFilter(logger, level.AllowAll())
-	logger = log.With(logger, "caller", log.DefaultCaller)
-
-	level.Info(logger).Log("foo", "bar")
-	if want, have := `level=info caller=level_test.go:149 foo=bar`, strings.TrimSpace(buf.String()); want != have {
-		t.Errorf("\nwant '%s'\nhave '%s'", want, have)
-	}
-}
-
-func TestContextLevel(t *testing.T) {
-	var buf bytes.Buffer
-
-	// Wrapping a context with the level logger still works, but requires users
-	// to specify a higher callstack depth value.
-	var logger log.Logger
-	logger = log.NewLogfmtLogger(&buf)
-	logger = log.With(logger, "caller", log.Caller(5))
-	logger = level.NewFilter(logger, level.AllowAll())
-
-	level.Info(logger).Log("foo", "bar")
-	if want, have := `caller=level_test.go:165 level=info foo=bar`, strings.TrimSpace(buf.String()); want != have {
-		t.Errorf("\nwant '%s'\nhave '%s'", want, have)
-	}
-}
-
-func TestLevelFormatting(t *testing.T) {
-	testCases := []struct {
-		name   string
-		format func(io.Writer) log.Logger
-		output string
-	}{
-		{
-			name:   "logfmt",
-			format: log.NewLogfmtLogger,
-			output: `level=info foo=bar`,
-		},
-		{
-			name:   "JSON",
-			format: log.NewJSONLogger,
-			output: `{"foo":"bar","level":"info"}`,
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			var buf bytes.Buffer
-
-			logger := tc.format(&buf)
-			level.Info(logger).Log("foo", "bar")
-			if want, have := tc.output, strings.TrimSpace(buf.String()); want != have {
-				t.Errorf("\nwant: '%s'\nhave '%s'", want, have)
-			}
-		})
-	}
-}
-
-func TestInjector(t *testing.T) {
-	var (
-		output []interface{}
-		logger log.Logger
-	)
-
-	logger = log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	})
-	logger = level.NewInjector(logger, level.InfoValue())
-
-	logger.Log("foo", "bar")
-	if got, want := len(output), 4; got != want {
-		t.Errorf("missing level not injected: got len==%d, want len==%d", got, want)
-	}
-	if got, want := output[0], level.Key(); got != want {
-		t.Errorf("wrong level key: got %#v, want %#v", got, want)
-	}
-	if got, want := output[1], level.InfoValue(); got != want {
-		t.Errorf("wrong level value: got %#v, want %#v", got, want)
-	}
-
-	level.Error(logger).Log("foo", "bar")
-	if got, want := len(output), 4; got != want {
-		t.Errorf("leveled record modified: got len==%d, want len==%d", got, want)
-	}
-	if got, want := output[0], level.Key(); got != want {
-		t.Errorf("wrong level key: got %#v, want %#v", got, want)
-	}
-	if got, want := output[1], level.ErrorValue(); got != want {
-		t.Errorf("wrong level value: got %#v, want %#v", got, want)
-	}
-}
diff --git a/log/log_test.go b/log/log_test.go
deleted file mode 100644
index 39c4a8b..0000000
--- a/log/log_test.go
+++ /dev/null
@@ -1,349 +0,0 @@
-package log_test
-
-import (
-	"bytes"
-	"fmt"
-	"sync"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-stack/stack"
-)
-
-func TestContext(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewLogfmtLogger(buf)
-
-	kvs := []interface{}{"a", 123}
-	lc := log.With(logger, kvs...)
-	kvs[1] = 0 // With should copy its key values
-
-	lc = log.With(lc, "b", "c") // With should stack
-	if err := lc.Log("msg", "message"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "a=123 b=c msg=message\n", buf.String(); want != have {
-		t.Errorf("\nwant: %shave: %s", want, have)
-	}
-
-	buf.Reset()
-	lc = log.WithPrefix(lc, "p", "first")
-	if err := lc.Log("msg", "message"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "p=first a=123 b=c msg=message\n", buf.String(); want != have {
-		t.Errorf("\nwant: %shave: %s", want, have)
-	}
-}
-
-func TestContextMissingValue(t *testing.T) {
-	t.Parallel()
-	var output []interface{}
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	log.WithPrefix(log.With(logger, "k1"), "k0").Log("k2")
-	if want, have := 6, len(output); want != have {
-		t.Errorf("want len(output) == %v, have %v", want, have)
-	}
-	for i := 1; i < 6; i += 2 {
-		if want, have := log.ErrMissingValue, output[i]; want != have {
-			t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
-		}
-	}
-}
-
-func TestWithPrefixAndSuffix(t *testing.T) {
-	t.Parallel()
-	var output []interface{}
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	lc := log.WithPrefix(logger, "a", "first")
-	lc = log.WithSuffix(lc, "z", "last")
-	if err := lc.Log("msg", "message"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := 6, len(output); want != have {
-		t.Errorf("want len(output) == %v, have %v", want, have)
-	}
-	want := []string{"a", "first", "msg", "message", "z", "last"}
-	for i := 0; i < 6; i++ {
-		if want, have := want[i], output[i]; want != have {
-			t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
-		}
-	}
-
-	lc = log.With(logger, "b", "second")
-	lc = log.WithPrefix(lc, "a", "first")
-	lc = log.With(lc, "c", "third")
-	lc = log.WithSuffix(lc, "z", "last")
-	lc = log.WithSuffix(lc, "aa", "sequel")
-	if err := lc.Log("msg", "message"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := 12, len(output); want != have {
-		t.Errorf("want len(output) == %v, have %v", want, have)
-	}
-	want = []string{
-		"a", "first",
-		"b", "second",
-		"c", "third",
-		"msg", "message",
-		"z", "last",
-		"aa", "sequel",
-	}
-	for i := 0; i < 12; i++ {
-		if want, have := want[i], output[i]; want != have {
-			t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
-		}
-	}
-}
-
-// Test that context.Log has a consistent function stack depth when binding
-// Valuers, regardless of how many times With has been called.
-func TestContextStackDepth(t *testing.T) {
-	t.Parallel()
-	fn := fmt.Sprintf("%n", stack.Caller(0))
-
-	var output []interface{}
-
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	stackValuer := log.Valuer(func() interface{} {
-		for i, c := range stack.Trace() {
-			if fmt.Sprintf("%n", c) == fn {
-				return i
-			}
-		}
-		t.Fatal("Test function not found in stack trace.")
-		return nil
-	})
-
-	logger = log.With(logger, "stack", stackValuer)
-
-	// Call through interface to get baseline.
-	logger.Log("k", "v")
-	want := output[1].(int)
-
-	for len(output) < 10 {
-		logger.Log("k", "v")
-		if have := output[1]; have != want {
-			t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want)
-		}
-
-		wrapped := log.With(logger)
-		wrapped.Log("k", "v")
-		if have := output[1]; have != want {
-			t.Errorf("%d Withs: have %v, want %v", len(output)/2-1, have, want)
-		}
-
-		logger = log.With(logger, "k", "v")
-	}
-}
-
-// Test that With returns a Logger safe for concurrent use. This test
-// validates that the stored logging context does not get corrupted when
-// multiple clients concurrently log additional keyvals.
-//
-// This test must be run with go test -cpu 2 (or more) to achieve its goal.
-func TestWithConcurrent(t *testing.T) {
-	// Create some buckets to count how many events each goroutine logs.
-	const goroutines = 8
-	counts := [goroutines]int{}
-
-	// This logger extracts a goroutine id from the last value field and
-	// increments the referenced bucket.
-	logger := log.LoggerFunc(func(kv ...interface{}) error {
-		goroutine := kv[len(kv)-1].(int)
-		counts[goroutine]++
-		return nil
-	})
-
-	// With must be careful about handling slices that can grow without
-	// copying the underlying array, so give it a challenge.
-	l := log.With(logger, make([]interface{}, 0, 2)...)
-
-	// Start logging concurrently. Each goroutine logs its id so the logger
-	// can bucket the event counts.
-	var wg sync.WaitGroup
-	wg.Add(goroutines)
-	const n = 10000
-	for i := 0; i < goroutines; i++ {
-		go func(idx int) {
-			defer wg.Done()
-			for j := 0; j < n; j++ {
-				l.Log("goroutineIdx", idx)
-			}
-		}(i)
-	}
-	wg.Wait()
-
-	for bucket, have := range counts {
-		if want := n; want != have {
-			t.Errorf("bucket %d: want %d, have %d", bucket, want, have) // note Errorf
-		}
-	}
-}
-
-func TestLogCopiesValuers(t *testing.T) {
-	t.Parallel()
-	var output []interface{}
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	valuerCallCount := 0
-	counterValuer := log.Valuer(func() interface{} {
-		valuerCallCount++
-		return valuerCallCount
-	})
-	lc := log.WithPrefix(logger, "a", counterValuer)
-	lc = log.WithSuffix(lc, "z", counterValuer)
-
-	if err := lc.Log(); err != nil {
-		t.Fatal(err)
-	}
-	want := []interface{}{"a", 1, "z", 2}
-	for i := 0; i < 4; i++ {
-		if want, have := want[i], output[i]; want != have {
-			t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
-		}
-	}
-
-	if err := lc.Log(); err != nil {
-		t.Fatal(err)
-	}
-	want = []interface{}{"a", 3, "z", 4}
-	for i := 0; i < 4; i++ {
-		if want, have := want[i], output[i]; want != have {
-			t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
-		}
-	}
-}
-
-func BenchmarkDiscard(b *testing.B) {
-	logger := log.NewNopLogger()
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		logger.Log("k", "v")
-	}
-}
-
-func BenchmarkOneWith(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.With(logger, "k", "v")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkTwoWith(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.With(logger, "k", "v")
-	for i := 1; i < 2; i++ {
-		lc = log.With(lc, "k", "v")
-	}
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkTenWith(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.With(logger, "k", "v")
-	for i := 1; i < 10; i++ {
-		lc = log.With(lc, "k", "v")
-	}
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkOneWithPrefix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithPrefix(logger, "a", "first")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkTenWithPrefix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithPrefix(logger, "a", "first")
-	for i := 1; i < 10; i++ {
-		lc = log.WithPrefix(lc, "a", "first")
-	}
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkOneWithSuffix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithSuffix(logger, "z", "last")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkTenWithSuffix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithSuffix(logger, "z", "last")
-	for i := 1; i < 10; i++ {
-		lc = log.WithSuffix(lc, "z", "last")
-	}
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkOneWithPrefixSuffix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithSuffix(logger, "a", "first")
-	lc = log.WithSuffix(lc, "z", "last")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkTenWithPrefixSuffix(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.WithPrefix(logger, "a", "first")
-	lc = log.WithSuffix(lc, "z", "last")
-	for i := 1; i < 10; i++ {
-		lc = log.WithPrefix(lc, "a", "first")
-		lc = log.WithSuffix(lc, "z", "last")
-	}
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
diff --git a/log/logfmt_logger_test.go b/log/logfmt_logger_test.go
deleted file mode 100644
index 91bbca1..0000000
--- a/log/logfmt_logger_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package log_test
-
-import (
-	"bytes"
-	"errors"
-	"io/ioutil"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-logfmt/logfmt"
-)
-
-func TestLogfmtLogger(t *testing.T) {
-	t.Parallel()
-	buf := &bytes.Buffer{}
-	logger := log.NewLogfmtLogger(buf)
-
-	if err := logger.Log("hello", "world"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "hello=world\n", buf.String(); want != have {
-		t.Errorf("want %#v, have %#v", want, have)
-	}
-
-	buf.Reset()
-	if err := logger.Log("a", 1, "err", errors.New("error")); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "a=1 err=error\n", buf.String(); want != have {
-		t.Errorf("want %#v, have %#v", want, have)
-	}
-
-	buf.Reset()
-	if err := logger.Log("std_map", map[int]int{1: 2}, "my_map", mymap{0: 0}); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "std_map=\""+logfmt.ErrUnsupportedValueType.Error()+"\" my_map=special_behavior\n", buf.String(); want != have {
-		t.Errorf("want %#v, have %#v", want, have)
-	}
-}
-
-func BenchmarkLogfmtLoggerSimple(b *testing.B) {
-	benchmarkRunner(b, log.NewLogfmtLogger(ioutil.Discard), baseMessage)
-}
-
-func BenchmarkLogfmtLoggerContextual(b *testing.B) {
-	benchmarkRunner(b, log.NewLogfmtLogger(ioutil.Discard), withMessage)
-}
-
-func TestLogfmtLoggerConcurrency(t *testing.T) {
-	t.Parallel()
-	testConcurrency(t, log.NewLogfmtLogger(ioutil.Discard), 10000)
-}
-
-type mymap map[int]int
-
-func (m mymap) String() string { return "special_behavior" }
diff --git a/log/nop_logger_test.go b/log/nop_logger_test.go
deleted file mode 100644
index 908ddd8..0000000
--- a/log/nop_logger_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package log_test
-
-import (
-	"testing"
-
-	"github.com/go-kit/kit/log"
-)
-
-func TestNopLogger(t *testing.T) {
-	t.Parallel()
-	logger := log.NewNopLogger()
-	if err := logger.Log("abc", 123); err != nil {
-		t.Error(err)
-	}
-	if err := log.With(logger, "def", "ghi").Log(); err != nil {
-		t.Error(err)
-	}
-}
-
-func BenchmarkNopLoggerSimple(b *testing.B) {
-	benchmarkRunner(b, log.NewNopLogger(), baseMessage)
-}
-
-func BenchmarkNopLoggerContextual(b *testing.B) {
-	benchmarkRunner(b, log.NewNopLogger(), withMessage)
-}
diff --git a/log/stdlib_test.go b/log/stdlib_test.go
deleted file mode 100644
index 2f958b7..0000000
--- a/log/stdlib_test.go
+++ /dev/null
@@ -1,261 +0,0 @@
-package log
-
-import (
-	"bytes"
-	"fmt"
-	"log"
-	"testing"
-	"time"
-)
-
-func TestStdlibWriter(t *testing.T) {
-	buf := &bytes.Buffer{}
-	log.SetOutput(buf)
-	log.SetFlags(log.LstdFlags)
-	logger := NewLogfmtLogger(StdlibWriter{})
-	logger.Log("key", "val")
-	timestamp := time.Now().Format("2006/01/02 15:04:05")
-	if want, have := timestamp+" key=val\n", buf.String(); want != have {
-		t.Errorf("want %q, have %q", want, have)
-	}
-}
-
-func TestStdlibAdapterUsage(t *testing.T) {
-	buf := &bytes.Buffer{}
-	logger := NewLogfmtLogger(buf)
-	writer := NewStdlibAdapter(logger)
-	stdlog := log.New(writer, "", 0)
-
-	now := time.Now()
-	date := now.Format("2006/01/02")
-	time := now.Format("15:04:05")
-
-	for flag, want := range map[int]string{
-		0:                                      "msg=hello\n",
-		log.Ldate:                              "ts=" + date + " msg=hello\n",
-		log.Ltime:                              "ts=" + time + " msg=hello\n",
-		log.Ldate | log.Ltime:                  "ts=\"" + date + " " + time + "\" msg=hello\n",
-		log.Lshortfile:                         "caller=stdlib_test.go:44 msg=hello\n",
-		log.Lshortfile | log.Ldate:             "ts=" + date + " caller=stdlib_test.go:44 msg=hello\n",
-		log.Lshortfile | log.Ldate | log.Ltime: "ts=\"" + date + " " + time + "\" caller=stdlib_test.go:44 msg=hello\n",
-	} {
-		buf.Reset()
-		stdlog.SetFlags(flag)
-		stdlog.Print("hello")
-		if have := buf.String(); want != have {
-			t.Errorf("flag=%d: want %#v, have %#v", flag, want, have)
-		}
-	}
-}
-
-func TestStdLibAdapterExtraction(t *testing.T) {
-	buf := &bytes.Buffer{}
-	logger := NewLogfmtLogger(buf)
-	writer := NewStdlibAdapter(logger)
-	for input, want := range map[string]string{
-		"hello":                                            "msg=hello\n",
-		"2009/01/23: hello":                                "ts=2009/01/23 msg=hello\n",
-		"2009/01/23 01:23:23: hello":                       "ts=\"2009/01/23 01:23:23\" msg=hello\n",
-		"01:23:23: hello":                                  "ts=01:23:23 msg=hello\n",
-		"2009/01/23 01:23:23.123123: hello":                "ts=\"2009/01/23 01:23:23.123123\" msg=hello\n",
-		"2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23.123123\" caller=/a/b/c/d.go:23 msg=hello\n",
-		"01:23:23.123123 /a/b/c/d.go:23: hello":            "ts=01:23:23.123123 caller=/a/b/c/d.go:23 msg=hello\n",
-		"2009/01/23 01:23:23 /a/b/c/d.go:23: hello":        "ts=\"2009/01/23 01:23:23\" caller=/a/b/c/d.go:23 msg=hello\n",
-		"2009/01/23 /a/b/c/d.go:23: hello":                 "ts=2009/01/23 caller=/a/b/c/d.go:23 msg=hello\n",
-		"/a/b/c/d.go:23: hello":                            "caller=/a/b/c/d.go:23 msg=hello\n",
-	} {
-		buf.Reset()
-		fmt.Fprint(writer, input)
-		if have := buf.String(); want != have {
-			t.Errorf("%q: want %#v, have %#v", input, want, have)
-		}
-	}
-}
-
-func TestStdLibAdapterPrefixedExtraction(t *testing.T) {
-	buf := &bytes.Buffer{}
-	logger := NewLogfmtLogger(buf)
-	writer := NewStdlibAdapter(logger, Prefix("some prefix ", false))
-	for input, want := range map[string]string{
-		"some prefix hello":                                            "msg=hello\n",
-		"some prefix 2009/01/23: hello":                                "ts=2009/01/23 msg=hello\n",
-		"some prefix 2009/01/23 01:23:23: hello":                       "ts=\"2009/01/23 01:23:23\" msg=hello\n",
-		"some prefix 01:23:23: hello":                                  "ts=01:23:23 msg=hello\n",
-		"some prefix 2009/01/23 01:23:23.123123: hello":                "ts=\"2009/01/23 01:23:23.123123\" msg=hello\n",
-		"some prefix 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23.123123\" caller=/a/b/c/d.go:23 msg=hello\n",
-		"some prefix 01:23:23.123123 /a/b/c/d.go:23: hello":            "ts=01:23:23.123123 caller=/a/b/c/d.go:23 msg=hello\n",
-		"some prefix 2009/01/23 01:23:23 /a/b/c/d.go:23: hello":        "ts=\"2009/01/23 01:23:23\" caller=/a/b/c/d.go:23 msg=hello\n",
-		"some prefix 2009/01/23 /a/b/c/d.go:23: hello":                 "ts=2009/01/23 caller=/a/b/c/d.go:23 msg=hello\n",
-		"some prefix /a/b/c/d.go:23: hello":                            "caller=/a/b/c/d.go:23 msg=hello\n",
-		"/a/b/c/d.go:23: some prefix hello":                            "caller=/a/b/c/d.go:23 msg=hello\n",
-	} {
-		buf.Reset()
-		fmt.Fprint(writer, input)
-		if have := buf.String(); want != have {
-			t.Errorf("%q: want %#v, have %#v", input, want, have)
-		}
-	}
-}
-
-func TestStdLibAdapterPrefixedExtractionWithJoinToMessage(t *testing.T) {
-	buf := &bytes.Buffer{}
-	logger := NewLogfmtLogger(buf)
-	writer := NewStdlibAdapter(logger, Prefix("some prefix ", true))
-	for input, want := range map[string]string{
-		"some prefix hello":                                            "msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23: hello":                                "ts=2009/01/23 msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23 01:23:23: hello":                       "ts=\"2009/01/23 01:23:23\" msg=\"some prefix hello\"\n",
-		"some prefix 01:23:23: hello":                                  "ts=01:23:23 msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23 01:23:23.123123: hello":                "ts=\"2009/01/23 01:23:23.123123\" msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23.123123\" caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-		"some prefix 01:23:23.123123 /a/b/c/d.go:23: hello":            "ts=01:23:23.123123 caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23 01:23:23 /a/b/c/d.go:23: hello":        "ts=\"2009/01/23 01:23:23\" caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-		"some prefix 2009/01/23 /a/b/c/d.go:23: hello":                 "ts=2009/01/23 caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-		"some prefix /a/b/c/d.go:23: hello":                            "caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-		"/a/b/c/d.go:23: some prefix hello":                            "caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
-	} {
-		buf.Reset()
-		fmt.Fprint(writer, input)
-		if have := buf.String(); want != have {
-			t.Errorf("%q: want %#v, have %#v", input, want, have)
-		}
-	}
-}
-
-func TestStdlibAdapterSubexps(t *testing.T) {
-	for input, wantMap := range map[string]map[string]string{
-		"hello world": {
-			"date": "",
-			"time": "",
-			"file": "",
-			"msg":  "hello world",
-		},
-		"hello\nworld": {
-			"date": "",
-			"time": "",
-			"file": "",
-			"msg":  "hello\nworld",
-		},
-		"2009/01/23: hello world": {
-			"date": "2009/01/23",
-			"time": "",
-			"file": "",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23",
-			"file": "",
-			"msg":  "hello world",
-		},
-		"01:23:23: hello world": {
-			"date": "",
-			"time": "01:23:23",
-			"file": "",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23.123123: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23.123123",
-			"file": "",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23.123123",
-			"file": "/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"01:23:23.123123 /a/b/c/d.go:23: hello world": {
-			"date": "",
-			"time": "01:23:23.123123",
-			"file": "/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23 /a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23",
-			"file": "/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 /a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "",
-			"file": "/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"/a/b/c/d.go:23: hello world": {
-			"date": "",
-			"time": "",
-			"file": "/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23.123123 C:/a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23.123123",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"01:23:23.123123 C:/a/b/c/d.go:23: hello world": {
-			"date": "",
-			"time": "01:23:23.123123",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23 C:/a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "01:23:23",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 C:/a/b/c/d.go:23: hello world": {
-			"date": "2009/01/23",
-			"time": "",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"C:/a/b/c/d.go:23: hello world": {
-			"date": "",
-			"time": "",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  "hello world",
-		},
-		"2009/01/23 01:23:23.123123 C:/a/b/c/d.go:23: :.;<>_#{[]}\"\\": {
-			"date": "2009/01/23",
-			"time": "01:23:23.123123",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  ":.;<>_#{[]}\"\\",
-		},
-		"01:23:23.123123 C:/a/b/c/d.go:23: :.;<>_#{[]}\"\\": {
-			"date": "",
-			"time": "01:23:23.123123",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  ":.;<>_#{[]}\"\\",
-		},
-		"2009/01/23 01:23:23 C:/a/b/c/d.go:23: :.;<>_#{[]}\"\\": {
-			"date": "2009/01/23",
-			"time": "01:23:23",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  ":.;<>_#{[]}\"\\",
-		},
-		"2009/01/23 C:/a/b/c/d.go:23: :.;<>_#{[]}\"\\": {
-			"date": "2009/01/23",
-			"time": "",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  ":.;<>_#{[]}\"\\",
-		},
-		"C:/a/b/c/d.go:23: :.;<>_#{[]}\"\\": {
-			"date": "",
-			"time": "",
-			"file": "C:/a/b/c/d.go:23",
-			"msg":  ":.;<>_#{[]}\"\\",
-		},
-	} {
-		haveMap := subexps([]byte(input))
-		for key, want := range wantMap {
-			if have := haveMap[key]; want != have {
-				t.Errorf("%q: %q: want %q, have %q", input, key, want, have)
-			}
-		}
-	}
-}
diff --git a/log/sync_test.go b/log/sync_test.go
deleted file mode 100644
index 253f256..0000000
--- a/log/sync_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package log_test
-
-import (
-	"bytes"
-	"io"
-	"os"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-)
-
-func TestSwapLogger(t *testing.T) {
-	t.Parallel()
-	var logger log.SwapLogger
-
-	// Zero value does not panic or error.
-	err := logger.Log("k", "v")
-	if got, want := err, error(nil); got != want {
-		t.Errorf("got %v, want %v", got, want)
-	}
-
-	buf := &bytes.Buffer{}
-	json := log.NewJSONLogger(buf)
-	logger.Swap(json)
-
-	if err := logger.Log("k", "v"); err != nil {
-		t.Error(err)
-	}
-	if got, want := buf.String(), `{"k":"v"}`+"\n"; got != want {
-		t.Errorf("got %v, want %v", got, want)
-	}
-
-	buf.Reset()
-	prefix := log.NewLogfmtLogger(buf)
-	logger.Swap(prefix)
-
-	if err := logger.Log("k", "v"); err != nil {
-		t.Error(err)
-	}
-	if got, want := buf.String(), "k=v\n"; got != want {
-		t.Errorf("got %v, want %v", got, want)
-	}
-
-	buf.Reset()
-	logger.Swap(nil)
-
-	if err := logger.Log("k", "v"); err != nil {
-		t.Error(err)
-	}
-	if got, want := buf.String(), ""; got != want {
-		t.Errorf("got %v, want %v", got, want)
-	}
-}
-
-func TestSwapLoggerConcurrency(t *testing.T) {
-	t.Parallel()
-	testConcurrency(t, &log.SwapLogger{}, 10000)
-}
-
-func TestSyncLoggerConcurrency(t *testing.T) {
-	var w io.Writer
-	w = &bytes.Buffer{}
-	logger := log.NewLogfmtLogger(w)
-	logger = log.NewSyncLogger(logger)
-	testConcurrency(t, logger, 10000)
-}
-
-func TestSyncWriterConcurrency(t *testing.T) {
-	var w io.Writer
-	w = &bytes.Buffer{}
-	w = log.NewSyncWriter(w)
-	testConcurrency(t, log.NewLogfmtLogger(w), 10000)
-}
-
-func TestSyncWriterFd(t *testing.T) {
-	_, ok := log.NewSyncWriter(os.Stdout).(interface {
-		Fd() uintptr
-	})
-
-	if !ok {
-		t.Error("NewSyncWriter does not pass through Fd method")
-	}
-}
-
-func TestSyncLoggerPanic(t *testing.T) {
-	var logger log.Logger
-	logger = log.LoggerFunc(func(...interface{}) error { panic("!") })
-	logger = log.NewSyncLogger(logger)
-
-	f := func() {
-		defer func() {
-			if x := recover(); x != nil {
-				t.Log(x)
-			}
-		}()
-		logger.Log("hello", "world")
-	}
-
-	f()
-	f() // without defer Unlock, this one can deadlock
-}
diff --git a/log/syslog/syslog_test.go b/log/syslog/syslog_test.go
deleted file mode 100644
index be77dfe..0000000
--- a/log/syslog/syslog_test.go
+++ /dev/null
@@ -1,170 +0,0 @@
-// +build !windows
-// +build !plan9
-// +build !nacl
-
-package syslog
-
-import (
-	"fmt"
-	"reflect"
-	"testing"
-
-	gosyslog "log/syslog"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-kit/kit/log/level"
-)
-
-func TestSyslogLoggerDefaultPrioritySelector(t *testing.T) {
-	w := &testSyslogWriter{}
-	l := NewSyslogLogger(w, log.NewLogfmtLogger)
-
-	l.Log("level", level.WarnValue(), "msg", "one")
-	l.Log("level", "undefined", "msg", "two")
-	l.Log("level", level.InfoValue(), "msg", "three")
-	l.Log("level", level.ErrorValue(), "msg", "four")
-	l.Log("level", level.DebugValue(), "msg", "five")
-
-	l.Log("msg", "six", "level", level.ErrorValue())
-	l.Log("msg", "seven", "level", level.DebugValue())
-	l.Log("msg", "eight", "level", level.InfoValue())
-	l.Log("msg", "nine", "level", "undefined")
-	l.Log("msg", "ten", "level", level.WarnValue())
-
-	l.Log("level", level.ErrorValue(), "msg")
-	l.Log("msg", "eleven", "level")
-
-	want := []string{
-		"warning: level=warn msg=one\n",
-		"info: level=undefined msg=two\n",
-		"info: level=info msg=three\n",
-		"err: level=error msg=four\n",
-		"debug: level=debug msg=five\n",
-
-		"err: msg=six level=error\n",
-		"debug: msg=seven level=debug\n",
-		"info: msg=eight level=info\n",
-		"info: msg=nine level=undefined\n",
-		"warning: msg=ten level=warn\n",
-
-		"err: level=error msg=null\n",
-		"info: msg=eleven level=null\n",
-	}
-	have := w.writes
-	if !reflect.DeepEqual(want, have) {
-		t.Errorf("wrong writes: want %s, have %s", want, have)
-	}
-}
-
-func TestSyslogLoggerExhaustivePrioritySelector(t *testing.T) {
-	w := &testSyslogWriter{}
-	selector := func(keyvals ...interface{}) gosyslog.Priority {
-		for i := 0; i < len(keyvals); i += 2 {
-			if keyvals[i] == level.Key() {
-				if v, ok := keyvals[i+1].(string); ok {
-					switch v {
-					case "emergency":
-						return gosyslog.LOG_EMERG
-					case "alert":
-						return gosyslog.LOG_ALERT
-					case "critical":
-						return gosyslog.LOG_CRIT
-					case "error":
-						return gosyslog.LOG_ERR
-					case "warning":
-						return gosyslog.LOG_WARNING
-					case "notice":
-						return gosyslog.LOG_NOTICE
-					case "info":
-						return gosyslog.LOG_INFO
-					case "debug":
-						return gosyslog.LOG_DEBUG
-					}
-					return gosyslog.LOG_LOCAL0
-				}
-			}
-		}
-		return gosyslog.LOG_LOCAL0
-	}
-	l := NewSyslogLogger(w, log.NewLogfmtLogger, PrioritySelectorOption(selector))
-
-	l.Log("level", "warning", "msg", "one")
-	l.Log("level", "error", "msg", "two")
-	l.Log("level", "critical", "msg", "three")
-	l.Log("level", "debug", "msg", "four")
-	l.Log("level", "info", "msg", "five")
-	l.Log("level", "alert", "msg", "six")
-	l.Log("level", "emergency", "msg", "seven")
-	l.Log("level", "notice", "msg", "eight")
-	l.Log("level", "unknown", "msg", "nine")
-
-	want := []string{
-		"warning: level=warning msg=one\n",
-		"err: level=error msg=two\n",
-		"crit: level=critical msg=three\n",
-		"debug: level=debug msg=four\n",
-		"info: level=info msg=five\n",
-		"alert: level=alert msg=six\n",
-		"emerg: level=emergency msg=seven\n",
-		"notice: level=notice msg=eight\n",
-		"write: level=unknown msg=nine\n",
-	}
-	have := w.writes
-	if !reflect.DeepEqual(want, have) {
-		t.Errorf("wrong writes: want %s, have %s", want, have)
-	}
-}
-
-type testSyslogWriter struct {
-	writes []string
-}
-
-func (w *testSyslogWriter) Write(b []byte) (int, error) {
-	msg := string(b)
-	w.writes = append(w.writes, fmt.Sprintf("write: %s", msg))
-	return len(msg), nil
-}
-
-func (w *testSyslogWriter) Close() error {
-	return nil
-}
-
-func (w *testSyslogWriter) Emerg(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("emerg: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Alert(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("alert: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Crit(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("crit: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Err(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("err: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Warning(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("warning: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Notice(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("notice: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Info(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("info: %s", msg))
-	return nil
-}
-
-func (w *testSyslogWriter) Debug(msg string) error {
-	w.writes = append(w.writes, fmt.Sprintf("debug: %s", msg))
-	return nil
-}
diff --git a/log/term/colorlogger_test.go b/log/term/colorlogger_test.go
deleted file mode 100644
index c27ac59..0000000
--- a/log/term/colorlogger_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package term_test
-
-import (
-	"bytes"
-	"io"
-	"io/ioutil"
-	"strconv"
-	"sync"
-	"testing"
-
-	"github.com/go-kit/kit/log"
-	"github.com/go-kit/kit/log/term"
-)
-
-func TestColorLogger(t *testing.T) {
-	var buf bytes.Buffer
-	logger := newColorLogger(&buf)
-
-	if err := logger.Log("hello", "world"); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "hello=world\n", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-
-	buf.Reset()
-	if err := logger.Log("a", 1); err != nil {
-		t.Fatal(err)
-	}
-	if want, have := "\x1b[32;1m\x1b[47;1ma=1\n\x1b[39;49;22m", buf.String(); want != have {
-		t.Errorf("\nwant %#v\nhave %#v", want, have)
-	}
-}
-
-func newColorLogger(w io.Writer) log.Logger {
-	return term.NewColorLogger(w, log.NewLogfmtLogger,
-		func(keyvals ...interface{}) term.FgBgColor {
-			if keyvals[0] == "a" {
-				return term.FgBgColor{Fg: term.Green, Bg: term.White}
-			}
-			return term.FgBgColor{}
-		})
-}
-
-func BenchmarkColorLoggerSimple(b *testing.B) {
-	benchmarkRunner(b, newColorLogger(ioutil.Discard), baseMessage)
-}
-
-func BenchmarkColorLoggerContextual(b *testing.B) {
-	benchmarkRunner(b, newColorLogger(ioutil.Discard), withMessage)
-}
-
-func TestColorLoggerConcurrency(t *testing.T) {
-	testConcurrency(t, newColorLogger(ioutil.Discard))
-}
-
-// copied from log/benchmark_test.go
-func benchmarkRunner(b *testing.B, logger log.Logger, f func(log.Logger)) {
-	lc := log.With(logger, "common_key", "common_value")
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		f(lc)
-	}
-}
-
-var (
-	baseMessage = func(logger log.Logger) { logger.Log("foo_key", "foo_value") }
-	withMessage = func(logger log.Logger) { log.With(logger, "a", "b").Log("c", "d") }
-)
-
-// copied from log/concurrency_test.go
-func testConcurrency(t *testing.T, logger log.Logger) {
-	for _, n := range []int{10, 100, 500} {
-		wg := sync.WaitGroup{}
-		wg.Add(n)
-		for i := 0; i < n; i++ {
-			go func() { spam(logger); wg.Done() }()
-		}
-		wg.Wait()
-	}
-}
-
-func spam(logger log.Logger) {
-	for i := 0; i < 100; i++ {
-		logger.Log("a", strconv.FormatInt(int64(i), 10))
-	}
-}
diff --git a/log/term/terminal_windows_test.go b/log/term/terminal_windows_test.go
deleted file mode 100644
index 789cc28..0000000
--- a/log/term/terminal_windows_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package term
-
-import (
-	"fmt"
-	"syscall"
-	"testing"
-)
-
-type myWriter struct {
-	fd uintptr
-}
-
-func (w *myWriter) Write(p []byte) (int, error) {
-	return 0, fmt.Errorf("not implemented")
-}
-
-func (w *myWriter) Fd() uintptr {
-	return w.fd
-}
-
-var procGetStdHandle = kernel32.NewProc("GetStdHandle")
-
-const stdOutputHandle = ^uintptr(0) - 11 + 1
-
-func getConsoleHandle() syscall.Handle {
-	ptr, err := syscall.UTF16PtrFromString("CONOUT$")
-
-	if err != nil {
-		panic(err)
-	}
-
-	handle, err := syscall.CreateFile(ptr, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, 0, 0)
-
-	if err != nil {
-		panic(err)
-	}
-
-	return handle
-}
-
-func TestIsTerminal(t *testing.T) {
-	// This is necessary because depending on whether `go test` is called with
-	// the `-v` option, stdout will or will not be bound, changing the behavior
-	// of the test. So we refer to it directly to avoid flakyness.
-	handle := getConsoleHandle()
-
-	writer := &myWriter{
-		fd: uintptr(handle),
-	}
-
-	if !IsTerminal(writer) {
-		t.Errorf("output is supposed to be a terminal")
-	}
-}
-
-func TestIsConsole(t *testing.T) {
-	// This is necessary because depending on whether `go test` is called with
-	// the `-v` option, stdout will or will not be bound, changing the behavior
-	// of the test. So we refer to it directly to avoid flakyness.
-	handle := getConsoleHandle()
-
-	writer := &myWriter{
-		fd: uintptr(handle),
-	}
-
-	if !IsConsole(writer) {
-		t.Errorf("output is supposed to be a console")
-	}
-}
diff --git a/log/value_test.go b/log/value_test.go
deleted file mode 100644
index 3a0c835..0000000
--- a/log/value_test.go
+++ /dev/null
@@ -1,150 +0,0 @@
-package log_test
-
-import (
-	"encoding"
-	"fmt"
-	"reflect"
-	"testing"
-	"time"
-
-	"github.com/go-kit/kit/log"
-)
-
-func TestValueBinding(t *testing.T) {
-	t.Parallel()
-	var output []interface{}
-
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	start := time.Date(2015, time.April, 25, 0, 0, 0, 0, time.UTC)
-	now := start
-	mocktime := func() time.Time {
-		now = now.Add(time.Second)
-		return now
-	}
-
-	lc := log.With(logger, "ts", log.Timestamp(mocktime), "caller", log.DefaultCaller)
-
-	lc.Log("foo", "bar")
-	timestamp, ok := output[1].(time.Time)
-	if !ok {
-		t.Fatalf("want time.Time, have %T", output[1])
-	}
-	if want, have := start.Add(time.Second), timestamp; want != have {
-		t.Errorf("output[1]: want %v, have %v", want, have)
-	}
-	if want, have := "value_test.go:31", fmt.Sprint(output[3]); want != have {
-		t.Errorf("output[3]: want %s, have %s", want, have)
-	}
-
-	// A second attempt to confirm the bindings are truly dynamic.
-	lc.Log("foo", "bar")
-	timestamp, ok = output[1].(time.Time)
-	if !ok {
-		t.Fatalf("want time.Time, have %T", output[1])
-	}
-	if want, have := start.Add(2*time.Second), timestamp; want != have {
-		t.Errorf("output[1]: want %v, have %v", want, have)
-	}
-	if want, have := "value_test.go:44", fmt.Sprint(output[3]); want != have {
-		t.Errorf("output[3]: want %s, have %s", want, have)
-	}
-}
-
-func TestValueBinding_loggingZeroKeyvals(t *testing.T) {
-	t.Parallel()
-	var output []interface{}
-
-	logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
-		output = keyvals
-		return nil
-	}))
-
-	start := time.Date(2015, time.April, 25, 0, 0, 0, 0, time.UTC)
-	now := start
-	mocktime := func() time.Time {
-		now = now.Add(time.Second)
-		return now
-	}
-
-	logger = log.With(logger, "ts", log.Timestamp(mocktime))
-
-	logger.Log()
-	timestamp, ok := output[1].(time.Time)
-	if !ok {
-		t.Fatalf("want time.Time, have %T", output[1])
-	}
-	if want, have := start.Add(time.Second), timestamp; want != have {
-		t.Errorf("output[1]: want %v, have %v", want, have)
-	}
-
-	// A second attempt to confirm the bindings are truly dynamic.
-	logger.Log()
-	timestamp, ok = output[1].(time.Time)
-	if !ok {
-		t.Fatalf("want time.Time, have %T", output[1])
-	}
-	if want, have := start.Add(2*time.Second), timestamp; want != have {
-		t.Errorf("output[1]: want %v, have %v", want, have)
-	}
-}
-
-func TestTimestampFormat(t *testing.T) {
-	t.Parallel()
-
-	start := time.Date(2015, time.April, 25, 0, 0, 0, 0, time.UTC)
-	now := start
-	mocktime := func() time.Time {
-		now = now.Add(time.Second)
-		return now
-	}
-
-	tv := log.TimestampFormat(mocktime, time.RFC822)
-
-	if want, have := now.Add(time.Second).Format(time.RFC822), fmt.Sprint(tv()); want != have {
-		t.Errorf("wrong time format: want %v, have %v", want, have)
-	}
-
-	if want, have := now.Add(2*time.Second).Format(time.RFC822), fmt.Sprint(tv()); want != have {
-		t.Errorf("wrong time format: want %v, have %v", want, have)
-	}
-
-	mustMarshal := func(v interface{}) []byte {
-		b, err := v.(encoding.TextMarshaler).MarshalText()
-		if err != nil {
-			t.Fatal("error marshaling text:", err)
-		}
-		return b
-	}
-
-	if want, have := now.Add(3*time.Second).AppendFormat(nil, time.RFC822), mustMarshal(tv()); !reflect.DeepEqual(want, have) {
-		t.Errorf("wrong time format: want %s, have %s", want, have)
-	}
-
-	if want, have := now.Add(4*time.Second).AppendFormat(nil, time.RFC822), mustMarshal(tv()); !reflect.DeepEqual(want, have) {
-		t.Errorf("wrong time format: want %s, have %s", want, have)
-	}
-}
-
-func BenchmarkValueBindingTimestamp(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.With(logger, "ts", log.DefaultTimestamp)
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
-
-func BenchmarkValueBindingCaller(b *testing.B) {
-	logger := log.NewNopLogger()
-	lc := log.With(logger, "caller", log.DefaultCaller)
-	b.ReportAllocs()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		lc.Log("k", "v")
-	}
-}
diff --git a/metrics/cloudwatch/cloudwatch_test.go b/metrics/cloudwatch/cloudwatch_test.go
index e825635..f938749 100644
--- a/metrics/cloudwatch/cloudwatch_test.go
+++ b/metrics/cloudwatch/cloudwatch_test.go
@@ -10,9 +10,9 @@ import (
 	"github.com/aws/aws-sdk-go/service/cloudwatch"
 	"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 const metricNameToGenerateError = "metric_name_used_to_throw_an_error"
diff --git a/metrics/dogstatsd/dogstatsd_test.go b/metrics/dogstatsd/dogstatsd_test.go
index ef6a5a4..7053dd2 100644
--- a/metrics/dogstatsd/dogstatsd_test.go
+++ b/metrics/dogstatsd/dogstatsd_test.go
@@ -3,8 +3,8 @@ package dogstatsd
 import (
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 func TestCounter(t *testing.T) {
diff --git a/metrics/graphite/graphite_test.go b/metrics/graphite/graphite_test.go
index 6474e20..5b8f052 100644
--- a/metrics/graphite/graphite_test.go
+++ b/metrics/graphite/graphite_test.go
@@ -6,8 +6,8 @@ import (
 	"strconv"
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 func TestCounter(t *testing.T) {
diff --git a/metrics/influx/example_test.go b/metrics/influx/example_test.go
index 526f0f9..5addef4 100644
--- a/metrics/influx/example_test.go
+++ b/metrics/influx/example_test.go
@@ -6,7 +6,7 @@ import (
 
 	influxdb "github.com/influxdata/influxdb1-client/v2"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func ExampleCounter() {
diff --git a/metrics/influx/influx_test.go b/metrics/influx/influx_test.go
index 62f867a..141a3ae 100644
--- a/metrics/influx/influx_test.go
+++ b/metrics/influx/influx_test.go
@@ -10,8 +10,8 @@ import (
 
 	influxdb "github.com/influxdata/influxdb1-client/v2"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 func TestCounter(t *testing.T) {
diff --git a/metrics/influxstatsd/influxstatsd_test.go b/metrics/influxstatsd/influxstatsd_test.go
index d553cf4..289c98f 100644
--- a/metrics/influxstatsd/influxstatsd_test.go
+++ b/metrics/influxstatsd/influxstatsd_test.go
@@ -3,8 +3,8 @@ package influxstatsd
 import (
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 func TestCounter(t *testing.T) {
diff --git a/metrics/statsd/statsd_test.go b/metrics/statsd/statsd_test.go
index c82c813..2f4c62d 100644
--- a/metrics/statsd/statsd_test.go
+++ b/metrics/statsd/statsd_test.go
@@ -3,8 +3,8 @@ package statsd
 import (
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/metrics/teststat"
+	"github.com/go-kit/log"
 )
 
 func TestCounter(t *testing.T) {
diff --git a/sd/benchmark_test.go b/sd/benchmark_test.go
index b548e1a..c73c89f 100644
--- a/sd/benchmark_test.go
+++ b/sd/benchmark_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func BenchmarkEndpoints(b *testing.B) {
diff --git a/sd/consul/instancer_test.go b/sd/consul/instancer_test.go
index 52b0559..03aa181 100644
--- a/sd/consul/instancer_test.go
+++ b/sd/consul/instancer_test.go
@@ -2,13 +2,14 @@ package consul
 
 import (
 	"context"
-	consul "github.com/hashicorp/consul/api"
 	"io"
 	"testing"
 	"time"
 
-	"github.com/go-kit/kit/log"
+	consul "github.com/hashicorp/consul/api"
+
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var _ sd.Instancer = (*Instancer)(nil) // API check
diff --git a/sd/consul/integration_test.go b/sd/consul/integration_test.go
index 5961547..a2d14ec 100644
--- a/sd/consul/integration_test.go
+++ b/sd/consul/integration_test.go
@@ -1,3 +1,4 @@
+//go:build integration
 // +build integration
 
 package consul
@@ -9,8 +10,8 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 	stdconsul "github.com/hashicorp/consul/api"
 )
 
diff --git a/sd/consul/registrar_test.go b/sd/consul/registrar_test.go
index edc7723..7f4a380 100644
--- a/sd/consul/registrar_test.go
+++ b/sd/consul/registrar_test.go
@@ -5,7 +5,7 @@ import (
 
 	stdconsul "github.com/hashicorp/consul/api"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func TestRegistrar(t *testing.T) {
diff --git a/sd/dnssrv/instancer_test.go b/sd/dnssrv/instancer_test.go
index fdf1e33..13e5e68 100644
--- a/sd/dnssrv/instancer_test.go
+++ b/sd/dnssrv/instancer_test.go
@@ -6,8 +6,8 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var _ sd.Instancer = (*Instancer)(nil) // API check
diff --git a/sd/endpoint_cache_test.go b/sd/endpoint_cache_test.go
index 91eb5be..616a441 100644
--- a/sd/endpoint_cache_test.go
+++ b/sd/endpoint_cache_test.go
@@ -7,7 +7,7 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func TestEndpointCache(t *testing.T) {
diff --git a/sd/endpointer_test.go b/sd/endpointer_test.go
index 671178f..0799479 100644
--- a/sd/endpointer_test.go
+++ b/sd/endpointer_test.go
@@ -6,9 +6,9 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/internal/instance"
+	"github.com/go-kit/log"
 )
 
 func TestDefaultEndpointer(t *testing.T) {
diff --git a/sd/etcd/example_test.go b/sd/etcd/example_test.go
index 66db15b..72a68e6 100644
--- a/sd/etcd/example_test.go
+++ b/sd/etcd/example_test.go
@@ -6,9 +6,9 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/lb"
+	"github.com/go-kit/log"
 )
 
 func Example() {
diff --git a/sd/etcd/instancer_test.go b/sd/etcd/instancer_test.go
index 2e0bb56..09e49ff 100644
--- a/sd/etcd/instancer_test.go
+++ b/sd/etcd/instancer_test.go
@@ -6,8 +6,8 @@ import (
 
 	stdetcd "go.etcd.io/etcd/client/v2"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var _ sd.Instancer = (*Instancer)(nil) // API check
diff --git a/sd/etcd/integration_test.go b/sd/etcd/integration_test.go
index 70fe85b..ed1b960 100644
--- a/sd/etcd/integration_test.go
+++ b/sd/etcd/integration_test.go
@@ -1,3 +1,4 @@
+//go:build flaky_integration
 // +build flaky_integration
 
 package etcd
@@ -10,8 +11,8 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 // Package sd/etcd provides a wrapper around the etcd key/value store. This
diff --git a/sd/etcd/registrar_test.go b/sd/etcd/registrar_test.go
index 9426f0b..8a30e52 100644
--- a/sd/etcd/registrar_test.go
+++ b/sd/etcd/registrar_test.go
@@ -5,7 +5,7 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // testClient is a basic implementation of Client
diff --git a/sd/etcdv3/example_test.go b/sd/etcdv3/example_test.go
index 8acf1d3..535d9f3 100644
--- a/sd/etcdv3/example_test.go
+++ b/sd/etcdv3/example_test.go
@@ -6,9 +6,9 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
 	"github.com/go-kit/kit/sd/lb"
+	"github.com/go-kit/log"
 	"google.golang.org/grpc"
 )
 
diff --git a/sd/etcdv3/instancer_test.go b/sd/etcdv3/instancer_test.go
index ecedf8c..816e419 100644
--- a/sd/etcdv3/instancer_test.go
+++ b/sd/etcdv3/instancer_test.go
@@ -4,8 +4,8 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var _ sd.Instancer = (*Instancer)(nil) // API check
diff --git a/sd/etcdv3/integration_test.go b/sd/etcdv3/integration_test.go
index 3864946..360ce8e 100644
--- a/sd/etcdv3/integration_test.go
+++ b/sd/etcdv3/integration_test.go
@@ -1,3 +1,4 @@
+//go:build flaky_integration
 // +build flaky_integration
 
 package etcdv3
@@ -10,8 +11,8 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 func runIntegration(settings integrationSettings, client Client, service Service, t *testing.T) {
diff --git a/sd/etcdv3/registrar_test.go b/sd/etcdv3/registrar_test.go
index 052506f..5b1fdae 100644
--- a/sd/etcdv3/registrar_test.go
+++ b/sd/etcdv3/registrar_test.go
@@ -5,7 +5,7 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // testClient is a basic implementation of Client
diff --git a/sd/eureka/integration_test.go b/sd/eureka/integration_test.go
index 210882b..5a96e27 100644
--- a/sd/eureka/integration_test.go
+++ b/sd/eureka/integration_test.go
@@ -1,3 +1,4 @@
+//go:build integration
 // +build integration
 
 package eureka
@@ -9,7 +10,7 @@ import (
 
 	"github.com/hudl/fargo"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 // Package sd/eureka provides a wrapper around the Netflix Eureka service
diff --git a/sd/eureka/util_test.go b/sd/eureka/util_test.go
index 494179a..469d574 100644
--- a/sd/eureka/util_test.go
+++ b/sd/eureka/util_test.go
@@ -7,7 +7,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 	"github.com/hudl/fargo"
 )
 
diff --git a/sd/internal/instance/cache_test.go b/sd/internal/instance/cache_test.go
index d1135b4..09bba28 100644
--- a/sd/internal/instance/cache_test.go
+++ b/sd/internal/instance/cache_test.go
@@ -9,8 +9,8 @@ import (
 	"time"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var _ sd.Instancer = (*Cache)(nil) // API check
diff --git a/sd/zk/client_test.go b/sd/zk/client_test.go
index 05ede2e..96b25cc 100644
--- a/sd/zk/client_test.go
+++ b/sd/zk/client_test.go
@@ -7,7 +7,7 @@ import (
 
 	stdzk "github.com/go-zookeeper/zk"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func TestNewClient(t *testing.T) {
diff --git a/sd/zk/util_test.go b/sd/zk/util_test.go
index a041cc9..240b786 100644
--- a/sd/zk/util_test.go
+++ b/sd/zk/util_test.go
@@ -11,8 +11,8 @@ import (
 	"github.com/go-zookeeper/zk"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/sd"
+	"github.com/go-kit/log"
 )
 
 var (
diff --git a/tracing/opentracing/grpc_test.go b/tracing/opentracing/grpc_test.go
index a36fa15..2762f6b 100644
--- a/tracing/opentracing/grpc_test.go
+++ b/tracing/opentracing/grpc_test.go
@@ -8,8 +8,8 @@ import (
 	"github.com/opentracing/opentracing-go/mocktracer"
 	"google.golang.org/grpc/metadata"
 
-	"github.com/go-kit/kit/log"
 	kitot "github.com/go-kit/kit/tracing/opentracing"
+	"github.com/go-kit/log"
 )
 
 func TestTraceGRPCRequestRoundtrip(t *testing.T) {
diff --git a/tracing/opentracing/http_test.go b/tracing/opentracing/http_test.go
index 7d5571e..c72e975 100644
--- a/tracing/opentracing/http_test.go
+++ b/tracing/opentracing/http_test.go
@@ -10,8 +10,8 @@ import (
 	"github.com/opentracing/opentracing-go/ext"
 	"github.com/opentracing/opentracing-go/mocktracer"
 
-	"github.com/go-kit/kit/log"
 	kitot "github.com/go-kit/kit/tracing/opentracing"
+	"github.com/go-kit/log"
 )
 
 func TestTraceHTTPRequestRoundtrip(t *testing.T) {
diff --git a/transport/awslambda/handler_test.go b/transport/awslambda/handler_test.go
index cc927a2..06ee04a 100644
--- a/transport/awslambda/handler_test.go
+++ b/transport/awslambda/handler_test.go
@@ -7,8 +7,8 @@ import (
 	"testing"
 
 	"github.com/go-kit/kit/endpoint"
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 )
 
 type key int
diff --git a/transport/error_handler_test.go b/transport/error_handler_test.go
index 48399a3..6ffabdf 100644
--- a/transport/error_handler_test.go
+++ b/transport/error_handler_test.go
@@ -5,8 +5,8 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/go-kit/kit/log"
 	"github.com/go-kit/kit/transport"
+	"github.com/go-kit/log"
 )
 
 func TestLogErrorHandler(t *testing.T) {
diff --git a/util/conn/manager_test.go b/util/conn/manager_test.go
index c91b706..1017312 100644
--- a/util/conn/manager_test.go
+++ b/util/conn/manager_test.go
@@ -7,7 +7,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kit/kit/log"
+	"github.com/go-kit/log"
 )
 
 func TestManager(t *testing.T) {