commit
						da9d49d186
					
				| 
						 | 
				
			
			@ -31,3 +31,7 @@ bin/*
 | 
			
		|||
 | 
			
		||||
# Cover profiles
 | 
			
		||||
*.out
 | 
			
		||||
 | 
			
		||||
# Editor/IDE specific files.
 | 
			
		||||
*.sublime-project
 | 
			
		||||
*.sublime-workspace
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -224,7 +224,7 @@ func configureLogging(ctx context.Context, config *configuration.Configuration)
 | 
			
		|||
			fields = append(fields, k)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ctx = withMapContext(ctx, config.Log.Fields)
 | 
			
		||||
		ctx = ctxu.WithValues(ctx, config.Log.Fields)
 | 
			
		||||
		ctx = ctxu.WithLogger(ctx, ctxu.GetLogger(ctx, fields...))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -241,36 +241,6 @@ func logLevel(level configuration.Loglevel) log.Level {
 | 
			
		|||
	return l
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stringMapContext is a simple context implementation that checks a map for a
 | 
			
		||||
// key, falling back to a parent if not present.
 | 
			
		||||
type stringMapContext struct {
 | 
			
		||||
	context.Context
 | 
			
		||||
	m map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// withMapContext returns a context that proxies lookups through a map.
 | 
			
		||||
func withMapContext(ctx context.Context, m map[string]string) context.Context {
 | 
			
		||||
	mo := make(map[string]string, len(m)) // make our own copy.
 | 
			
		||||
	for k, v := range m {
 | 
			
		||||
		mo[k] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return stringMapContext{
 | 
			
		||||
		Context: ctx,
 | 
			
		||||
		m:       mo,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (smc stringMapContext) Value(key interface{}) interface{} {
 | 
			
		||||
	if ks, ok := key.(string); ok {
 | 
			
		||||
		if v, ok := smc.m[ks]; ok {
 | 
			
		||||
			return v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return smc.Context.Value(key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// debugServer starts the debug server with pprof, expvar among other
 | 
			
		||||
// endpoints. The addr should not be exposed externally. For most of these to
 | 
			
		||||
// work, tls cannot be enabled on the endpoint, so it is generally separate.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ type Configuration struct {
 | 
			
		|||
 | 
			
		||||
		// Fields allows users to specify static string fields to include in
 | 
			
		||||
		// the logger context.
 | 
			
		||||
		Fields map[string]string `yaml:"fields"`
 | 
			
		||||
		Fields map[string]interface{} `yaml:"fields"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Loglevel is the level at which registry operations are logged. This is
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,11 @@ func Test(t *testing.T) { TestingT(t) }
 | 
			
		|||
var configStruct = Configuration{
 | 
			
		||||
	Version: "0.1",
 | 
			
		||||
	Log: struct {
 | 
			
		||||
		Level     Loglevel          `yaml:"level"`
 | 
			
		||||
		Formatter string            `yaml:"formatter"`
 | 
			
		||||
		Fields    map[string]string `yaml:"fields"`
 | 
			
		||||
		Level     Loglevel               `yaml:"level"`
 | 
			
		||||
		Formatter string                 `yaml:"formatter"`
 | 
			
		||||
		Fields    map[string]interface{} `yaml:"fields"`
 | 
			
		||||
	}{
 | 
			
		||||
		Fields: map[string]string{"environment": "test"},
 | 
			
		||||
		Fields: map[string]interface{}{"environment": "test"},
 | 
			
		||||
	},
 | 
			
		||||
	Loglevel: "info",
 | 
			
		||||
	Storage: Storage{
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +340,7 @@ func copyConfig(config Configuration) *Configuration {
 | 
			
		|||
	configCopy.Version = MajorMinorVersion(config.Version.Major(), config.Version.Minor())
 | 
			
		||||
	configCopy.Loglevel = config.Loglevel
 | 
			
		||||
	configCopy.Log = config.Log
 | 
			
		||||
	configCopy.Log.Fields = make(map[string]string, len(config.Log.Fields))
 | 
			
		||||
	configCopy.Log.Fields = make(map[string]interface{}, len(config.Log.Fields))
 | 
			
		||||
	for k, v := range config.Log.Fields {
 | 
			
		||||
		configCopy.Log.Fields[k] = v
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
package context
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Context is a copy of Context from the golang.org/x/net/context package.
 | 
			
		||||
type Context interface {
 | 
			
		||||
	context.Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Background returns a non-nil, empty Context.
 | 
			
		||||
func Background() Context {
 | 
			
		||||
	return context.Background()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithValue returns a copy of parent in which the value associated with key is
 | 
			
		||||
// val. Use context Values only for request-scoped data that transits processes
 | 
			
		||||
// and APIs, not for passing optional parameters to functions.
 | 
			
		||||
func WithValue(parent Context, key, val interface{}) Context {
 | 
			
		||||
	return context.WithValue(parent, key, val)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stringMapContext is a simple context implementation that checks a map for a
 | 
			
		||||
// key, falling back to a parent if not present.
 | 
			
		||||
type stringMapContext struct {
 | 
			
		||||
	context.Context
 | 
			
		||||
	m map[string]interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithValues returns a context that proxies lookups through a map. Only
 | 
			
		||||
// supports string keys.
 | 
			
		||||
func WithValues(ctx context.Context, m map[string]interface{}) context.Context {
 | 
			
		||||
	mo := make(map[string]interface{}, len(m)) // make our own copy.
 | 
			
		||||
	for k, v := range m {
 | 
			
		||||
		mo[k] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return stringMapContext{
 | 
			
		||||
		Context: ctx,
 | 
			
		||||
		m:       mo,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (smc stringMapContext) Value(key interface{}) interface{} {
 | 
			
		||||
	if ks, ok := key.(string); ok {
 | 
			
		||||
		if v, ok := smc.m[ks]; ok {
 | 
			
		||||
			return v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return smc.Context.Value(key)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,6 @@ import (
 | 
			
		|||
	"code.google.com/p/go-uuid/uuid"
 | 
			
		||||
	log "github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Common errors used with this package.
 | 
			
		||||
| 
						 | 
				
			
			@ -50,12 +49,25 @@ func RemoteAddr(r *http.Request) string {
 | 
			
		|||
	return r.RemoteAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteIP extracts the remote IP of the request, taking into
 | 
			
		||||
// account proxy headers.
 | 
			
		||||
func RemoteIP(r *http.Request) string {
 | 
			
		||||
	addr := RemoteAddr(r)
 | 
			
		||||
 | 
			
		||||
	// Try parsing it as "IP:port"
 | 
			
		||||
	if ip, _, err := net.SplitHostPort(addr); err == nil {
 | 
			
		||||
		return ip
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithRequest places the request on the context. The context of the request
 | 
			
		||||
// is assigned a unique id, available at "http.request.id". The request itself
 | 
			
		||||
// is available at "http.request". Other common attributes are available under
 | 
			
		||||
// the prefix "http.request.". If a request is already present on the context,
 | 
			
		||||
// this method will panic.
 | 
			
		||||
func WithRequest(ctx context.Context, r *http.Request) context.Context {
 | 
			
		||||
func WithRequest(ctx Context, r *http.Request) Context {
 | 
			
		||||
	if ctx.Value("http.request") != nil {
 | 
			
		||||
		// NOTE(stevvooe): This needs to be considered a programming error. It
 | 
			
		||||
		// is unlikely that we'd want to have more than one request in
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +86,7 @@ func WithRequest(ctx context.Context, r *http.Request) context.Context {
 | 
			
		|||
// GetRequest returns the http request in the given context. Returns
 | 
			
		||||
// ErrNoRequestContext if the context does not have an http request associated
 | 
			
		||||
// with it.
 | 
			
		||||
func GetRequest(ctx context.Context) (*http.Request, error) {
 | 
			
		||||
func GetRequest(ctx Context) (*http.Request, error) {
 | 
			
		||||
	if r, ok := ctx.Value("http.request").(*http.Request); r != nil && ok {
 | 
			
		||||
		return r, nil
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,13 +95,13 @@ func GetRequest(ctx context.Context) (*http.Request, error) {
 | 
			
		|||
 | 
			
		||||
// GetRequestID attempts to resolve the current request id, if possible. An
 | 
			
		||||
// error is return if it is not available on the context.
 | 
			
		||||
func GetRequestID(ctx context.Context) string {
 | 
			
		||||
func GetRequestID(ctx Context) string {
 | 
			
		||||
	return GetStringValue(ctx, "http.request.id")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithResponseWriter returns a new context and response writer that makes
 | 
			
		||||
// interesting response statistics available within the context.
 | 
			
		||||
func WithResponseWriter(ctx context.Context, w http.ResponseWriter) (context.Context, http.ResponseWriter) {
 | 
			
		||||
func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.ResponseWriter) {
 | 
			
		||||
	irw := &instrumentedResponseWriter{
 | 
			
		||||
		ResponseWriter: w,
 | 
			
		||||
		Context:        ctx,
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +119,7 @@ var getVarsFromRequest = mux.Vars
 | 
			
		|||
// example, if looking for the variable "name", it can be accessed as
 | 
			
		||||
// "vars.name". Implementations that are accessing values need not know that
 | 
			
		||||
// the underlying context is implemented with gorilla/mux vars.
 | 
			
		||||
func WithVars(ctx context.Context, r *http.Request) context.Context {
 | 
			
		||||
func WithVars(ctx Context, r *http.Request) Context {
 | 
			
		||||
	return &muxVarsContext{
 | 
			
		||||
		Context: ctx,
 | 
			
		||||
		vars:    getVarsFromRequest(r),
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +129,7 @@ func WithVars(ctx context.Context, r *http.Request) context.Context {
 | 
			
		|||
// GetRequestLogger returns a logger that contains fields from the request in
 | 
			
		||||
// the current context. If the request is not available in the context, no
 | 
			
		||||
// fields will display. Request loggers can safely be pushed onto the context.
 | 
			
		||||
func GetRequestLogger(ctx context.Context) Logger {
 | 
			
		||||
func GetRequestLogger(ctx Context) Logger {
 | 
			
		||||
	return GetLogger(ctx,
 | 
			
		||||
		"http.request.id",
 | 
			
		||||
		"http.request.method",
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +145,7 @@ func GetRequestLogger(ctx context.Context) Logger {
 | 
			
		|||
// Because the values are read at call time, pushing a logger returned from
 | 
			
		||||
// this function on the context will lead to missing or invalid data. Only
 | 
			
		||||
// call this at the end of a request, after the response has been written.
 | 
			
		||||
func GetResponseLogger(ctx context.Context) Logger {
 | 
			
		||||
func GetResponseLogger(ctx Context) Logger {
 | 
			
		||||
	l := getLogrusLogger(ctx,
 | 
			
		||||
		"http.response.written",
 | 
			
		||||
		"http.response.status",
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +154,7 @@ func GetResponseLogger(ctx context.Context) Logger {
 | 
			
		|||
	duration := Since(ctx, "http.request.startedat")
 | 
			
		||||
 | 
			
		||||
	if duration > 0 {
 | 
			
		||||
		l = l.WithField("http.response.duration", duration)
 | 
			
		||||
		l = l.WithField("http.response.duration", duration.String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return l
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +162,7 @@ func GetResponseLogger(ctx context.Context) Logger {
 | 
			
		|||
 | 
			
		||||
// httpRequestContext makes information about a request available to context.
 | 
			
		||||
type httpRequestContext struct {
 | 
			
		||||
	context.Context
 | 
			
		||||
	Context
 | 
			
		||||
 | 
			
		||||
	startedAt time.Time
 | 
			
		||||
	id        string
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +221,7 @@ fallback:
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type muxVarsContext struct {
 | 
			
		||||
	context.Context
 | 
			
		||||
	Context
 | 
			
		||||
	vars map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +247,7 @@ func (ctx *muxVarsContext) Value(key interface{}) interface{} {
 | 
			
		|||
// context.
 | 
			
		||||
type instrumentedResponseWriter struct {
 | 
			
		||||
	http.ResponseWriter
 | 
			
		||||
	context.Context
 | 
			
		||||
	Context
 | 
			
		||||
 | 
			
		||||
	mu      sync.Mutex
 | 
			
		||||
	status  int
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,8 +8,6 @@ import (
 | 
			
		|||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestWithRequest(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +21,7 @@ func TestWithRequest(t *testing.T) {
 | 
			
		|||
	req.Header.Set("Referer", "foo.com/referer")
 | 
			
		||||
	req.Header.Set("User-Agent", "test/0.1")
 | 
			
		||||
 | 
			
		||||
	ctx := WithRequest(context.Background(), &req)
 | 
			
		||||
	ctx := WithRequest(Background(), &req)
 | 
			
		||||
	for _, testcase := range []struct {
 | 
			
		||||
		key      string
 | 
			
		||||
		expected interface{}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +130,7 @@ func (trw *testResponseWriter) Flush() {
 | 
			
		|||
 | 
			
		||||
func TestWithResponseWriter(t *testing.T) {
 | 
			
		||||
	trw := testResponseWriter{}
 | 
			
		||||
	ctx, rw := WithResponseWriter(context.Background(), &trw)
 | 
			
		||||
	ctx, rw := WithResponseWriter(Background(), &trw)
 | 
			
		||||
 | 
			
		||||
	if ctx.Value("http.response") != &trw {
 | 
			
		||||
		t.Fatalf("response not available in context: %v != %v", ctx.Value("http.response"), &trw)
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +181,7 @@ func TestWithVars(t *testing.T) {
 | 
			
		|||
		return vars
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx := WithVars(context.Background(), &req)
 | 
			
		||||
	ctx := WithVars(Background(), &req)
 | 
			
		||||
	for _, testcase := range []struct {
 | 
			
		||||
		key      string
 | 
			
		||||
		expected interface{}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Logger provides a leveled-logging interface.
 | 
			
		||||
| 
						 | 
				
			
			@ -41,8 +40,8 @@ type Logger interface {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// WithLogger creates a new context with provided logger.
 | 
			
		||||
func WithLogger(ctx context.Context, logger Logger) context.Context {
 | 
			
		||||
	return context.WithValue(ctx, "logger", logger)
 | 
			
		||||
func WithLogger(ctx Context, logger Logger) Context {
 | 
			
		||||
	return WithValue(ctx, "logger", logger)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLogger returns the logger from the current context, if present. If one
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +50,7 @@ func WithLogger(ctx context.Context, logger Logger) context.Context {
 | 
			
		|||
// argument passed to GetLogger will be passed to fmt.Sprint when expanded as
 | 
			
		||||
// a logging key field. If context keys are integer constants, for example,
 | 
			
		||||
// its recommended that a String method is implemented.
 | 
			
		||||
func GetLogger(ctx context.Context, keys ...interface{}) Logger {
 | 
			
		||||
func GetLogger(ctx Context, keys ...interface{}) Logger {
 | 
			
		||||
	return getLogrusLogger(ctx, keys...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +58,7 @@ func GetLogger(ctx context.Context, keys ...interface{}) Logger {
 | 
			
		|||
// are provided, they will be resolved on the context and included in the
 | 
			
		||||
// logger. Only use this function if specific logrus functionality is
 | 
			
		||||
// required.
 | 
			
		||||
func getLogrusLogger(ctx context.Context, keys ...interface{}) *logrus.Entry {
 | 
			
		||||
func getLogrusLogger(ctx Context, keys ...interface{}) *logrus.Entry {
 | 
			
		||||
	var logger *logrus.Entry
 | 
			
		||||
 | 
			
		||||
	// Get a logger, if it is present.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,12 @@ package context
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Since looks up key, which should be a time.Time, and returns the duration
 | 
			
		||||
// since that time. If the key is not found, the value returned will be zero.
 | 
			
		||||
// This is helpful when inferring metrics related to context execution times.
 | 
			
		||||
func Since(ctx context.Context, key interface{}) time.Duration {
 | 
			
		||||
func Since(ctx Context, key interface{}) time.Duration {
 | 
			
		||||
	startedAtI := ctx.Value(key)
 | 
			
		||||
	if startedAtI != nil {
 | 
			
		||||
		if startedAt, ok := startedAtI.(time.Time); ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +20,7 @@ func Since(ctx context.Context, key interface{}) time.Duration {
 | 
			
		|||
 | 
			
		||||
// GetStringValue returns a string value from the context. The empty string
 | 
			
		||||
// will be returned if not found.
 | 
			
		||||
func GetStringValue(ctx context.Context, key string) (value string) {
 | 
			
		||||
func GetStringValue(ctx Context, key string) (value string) {
 | 
			
		||||
	stringi := ctx.Value(key)
 | 
			
		||||
	if stringi != nil {
 | 
			
		||||
		if valuev, ok := stringi.(string); ok {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue