Skip to content

Commit

Permalink
Merge pull request #2360 from stevvooe/remove-context-type
Browse files Browse the repository at this point in the history
context: remove definition of Context
  • Loading branch information
stevvooe authored Aug 11, 2017
2 parents 7a8efe7 + 9c88801 commit 06fa77a
Show file tree
Hide file tree
Showing 90 changed files with 396 additions and 373 deletions.
2 changes: 1 addition & 1 deletion blobs.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package distribution

import (
"context"
"errors"
"fmt"
"io"
"net/http"
"time"

"github.com/docker/distribution/context"
"github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
)
Expand Down
18 changes: 3 additions & 15 deletions context/context.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
package context

import (
"context"
"sync"

"github.com/docker/distribution/uuid"
"golang.org/x/net/context"
)

// Context is a copy of Context from the golang.org/x/net/context package.
type Context interface {
context.Context
}

// instanceContext is a context that provides only an instance id. It is
// provided as the main background context.
type instanceContext struct {
Context
context.Context
id string // id of context, logged as "instance.id"
once sync.Once // once protect generation of the id
}
Expand All @@ -42,17 +37,10 @@ var background = &instanceContext{
// Background returns a non-nil, empty Context. The background context
// provides a single key, "instance.id" that is globally unique to the
// process.
func Background() Context {
func Background() context.Context {
return 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 {
Expand Down
23 changes: 12 additions & 11 deletions context/http.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package context

import (
"context"
"errors"
"net"
"net/http"
Expand Down Expand Up @@ -68,7 +69,7 @@ func RemoteIP(r *http.Request) string {
// 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, r *http.Request) Context {
func WithRequest(ctx context.Context, r *http.Request) context.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
Expand All @@ -87,7 +88,7 @@ func WithRequest(ctx Context, r *http.Request) 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) (*http.Request, error) {
func GetRequest(ctx context.Context) (*http.Request, error) {
if r, ok := ctx.Value("http.request").(*http.Request); r != nil && ok {
return r, nil
}
Expand All @@ -96,13 +97,13 @@ func GetRequest(ctx 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) string {
func GetRequestID(ctx context.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, w http.ResponseWriter) (Context, http.ResponseWriter) {
func WithResponseWriter(ctx context.Context, w http.ResponseWriter) (context.Context, http.ResponseWriter) {
if closeNotifier, ok := w.(http.CloseNotifier); ok {
irwCN := &instrumentedResponseWriterCN{
instrumentedResponseWriter: instrumentedResponseWriter{
Expand All @@ -125,7 +126,7 @@ func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.Respo
// GetResponseWriter returns the http.ResponseWriter from the provided
// context. If not present, ErrNoResponseWriterContext is returned. The
// returned instance provides instrumentation in the context.
func GetResponseWriter(ctx Context) (http.ResponseWriter, error) {
func GetResponseWriter(ctx context.Context) (http.ResponseWriter, error) {
v := ctx.Value("http.response")

rw, ok := v.(http.ResponseWriter)
Expand All @@ -145,7 +146,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, r *http.Request) Context {
func WithVars(ctx context.Context, r *http.Request) context.Context {
return &muxVarsContext{
Context: ctx,
vars: getVarsFromRequest(r),
Expand All @@ -155,7 +156,7 @@ func WithVars(ctx Context, r *http.Request) 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) Logger {
func GetRequestLogger(ctx context.Context) Logger {
return GetLogger(ctx,
"http.request.id",
"http.request.method",
Expand All @@ -171,7 +172,7 @@ func GetRequestLogger(ctx 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) Logger {
func GetResponseLogger(ctx context.Context) Logger {
l := getLogrusLogger(ctx,
"http.response.written",
"http.response.status",
Expand All @@ -188,7 +189,7 @@ func GetResponseLogger(ctx Context) Logger {

// httpRequestContext makes information about a request available to context.
type httpRequestContext struct {
Context
context.Context

startedAt time.Time
id string
Expand Down Expand Up @@ -247,7 +248,7 @@ fallback:
}

type muxVarsContext struct {
Context
context.Context
vars map[string]string
}

Expand Down Expand Up @@ -282,7 +283,7 @@ type instrumentedResponseWriterCN struct {
// implemented by the parent ResponseWriter.
type instrumentedResponseWriter struct {
http.ResponseWriter
Context
context.Context

mu sync.Mutex
status int
Expand Down
19 changes: 11 additions & 8 deletions context/logger.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package context

import (
"context"
"fmt"
"runtime"

"github.com/sirupsen/logrus"
"runtime"
)

// Logger provides a leveled-logging interface.
Expand Down Expand Up @@ -40,22 +41,24 @@ type Logger interface {
Warnln(args ...interface{})
}

type loggerKey struct{}

// WithLogger creates a new context with provided logger.
func WithLogger(ctx Context, logger Logger) Context {
return WithValue(ctx, "logger", logger)
func WithLogger(ctx context.Context, logger Logger) context.Context {
return context.WithValue(ctx, loggerKey{}, logger)
}

// GetLoggerWithField returns a logger instance with the specified field key
// and value without affecting the context. Extra specified keys will be
// resolved from the context.
func GetLoggerWithField(ctx Context, key, value interface{}, keys ...interface{}) Logger {
func GetLoggerWithField(ctx context.Context, key, value interface{}, keys ...interface{}) Logger {
return getLogrusLogger(ctx, keys...).WithField(fmt.Sprint(key), value)
}

// GetLoggerWithFields returns a logger instance with the specified fields
// without affecting the context. Extra specified keys will be resolved from
// the context.
func GetLoggerWithFields(ctx Context, fields map[interface{}]interface{}, keys ...interface{}) Logger {
func GetLoggerWithFields(ctx context.Context, fields map[interface{}]interface{}, keys ...interface{}) Logger {
// must convert from interface{} -> interface{} to string -> interface{} for logrus.
lfields := make(logrus.Fields, len(fields))
for key, value := range fields {
Expand All @@ -71,19 +74,19 @@ func GetLoggerWithFields(ctx Context, fields map[interface{}]interface{}, keys .
// 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, keys ...interface{}) Logger {
func GetLogger(ctx context.Context, keys ...interface{}) Logger {
return getLogrusLogger(ctx, keys...)
}

// GetLogrusLogger returns the logrus logger for the context. If one more keys
// 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, keys ...interface{}) *logrus.Entry {
func getLogrusLogger(ctx context.Context, keys ...interface{}) *logrus.Entry {
var logger *logrus.Entry

// Get a logger, if it is present.
loggerInterface := ctx.Value("logger")
loggerInterface := ctx.Value(loggerKey{})
if loggerInterface != nil {
if lgr, ok := loggerInterface.(*logrus.Entry); ok {
logger = lgr
Expand Down
5 changes: 3 additions & 2 deletions context/trace.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package context

import (
"context"
"runtime"
"time"

Expand Down Expand Up @@ -36,7 +37,7 @@ import (
//
// Notice that the function name is automatically resolved, along with the
// package and a trace id is emitted that can be linked with parent ids.
func WithTrace(ctx Context) (Context, func(format string, a ...interface{})) {
func WithTrace(ctx context.Context) (context.Context, func(format string, a ...interface{})) {
if ctx == nil {
ctx = Background()
}
Expand Down Expand Up @@ -69,7 +70,7 @@ func WithTrace(ctx Context) (Context, func(format string, a ...interface{})) {
// also provides fast lookup for the various attributes that are available on
// the trace.
type traced struct {
Context
context.Context
id string
parent string
start time.Time
Expand Down
8 changes: 4 additions & 4 deletions context/trace_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package context

import (
"context"
"runtime"
"testing"
"time"
Expand Down Expand Up @@ -35,7 +36,7 @@ func TestWithTrace(t *testing.T) {
ctx, done := WithTrace(Background())
defer done("this will be emitted at end of test")

checkContextForValues(t, ctx, append(base, valueTestCase{
checkContextForValues(ctx, t, append(base, valueTestCase{
key: "trace.func",
expected: f.Name(),
}))
Expand All @@ -48,7 +49,7 @@ func TestWithTrace(t *testing.T) {
ctx, done := WithTrace(ctx)
defer done("this should be subordinate to the other trace")
time.Sleep(time.Second)
checkContextForValues(t, ctx, append(base, valueTestCase{
checkContextForValues(ctx, t, append(base, valueTestCase{
key: "trace.func",
expected: f.Name(),
}, valueTestCase{
Expand All @@ -67,8 +68,7 @@ type valueTestCase struct {
notnilorempty bool // just check not empty/not nil
}

func checkContextForValues(t *testing.T, ctx Context, values []valueTestCase) {

func checkContextForValues(ctx context.Context, t *testing.T, values []valueTestCase) {
for _, testcase := range values {
v := ctx.Value(testcase.key)
if testcase.notnilorempty {
Expand Down
5 changes: 3 additions & 2 deletions context/util.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package context

import (
"context"
"time"
)

// 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, key interface{}) time.Duration {
func Since(ctx context.Context, key interface{}) time.Duration {
if startedAt, ok := ctx.Value(key).(time.Time); ok {
return time.Since(startedAt)
}
Expand All @@ -16,7 +17,7 @@ func Since(ctx 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, key interface{}) (value string) {
func GetStringValue(ctx context.Context, key interface{}) (value string) {
if valuev, ok := ctx.Value(key).(string); ok {
value = valuev
}
Expand Down
16 changes: 11 additions & 5 deletions context/version.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package context

import "context"

type versionKey struct{}

func (versionKey) String() string { return "version" }

// WithVersion stores the application version in the context. The new context
// gets a logger to ensure log messages are marked with the application
// version.
func WithVersion(ctx Context, version string) Context {
ctx = WithValue(ctx, "version", version)
func WithVersion(ctx context.Context, version string) context.Context {
ctx = context.WithValue(ctx, versionKey{}, version)
// push a new logger onto the stack
return WithLogger(ctx, GetLogger(ctx, "version"))
return WithLogger(ctx, GetLogger(ctx, versionKey{}))
}

// GetVersion returns the application version from the context. An empty
// string may returned if the version was not set on the context.
func GetVersion(ctx Context) string {
return GetStringValue(ctx, "version")
func GetVersion(ctx context.Context) string {
return GetStringValue(ctx, versionKey{})
}
Loading

0 comments on commit 06fa77a

Please sign in to comment.