// Package dcontext provides several utilities for working with // Go's context in http requests. Primarily, the focus is on logging relevant // request information but this package is not limited to that purpose. // // The easiest way to get started is to get the background context: // // ctx := dcontext.Background() // // The returned context should be passed around your application and be the // root of all other context instances. If the application has a version, this // line should be called before anything else: // // ctx := dcontext.WithVersion(dcontext.Background(), version) // // The above will store the version in the context and will be available to // the logger. // // # Logging // // The most useful aspect of this package is GetLogger. This function takes // any context.Context interface and returns the current logger from the // context. Canonical usage looks like this: // // GetLogger(ctx).Infof("something interesting happened") // // GetLogger also takes optional key arguments. The keys will be looked up in // the context and reported with the logger. The following example would // return a logger that prints the version with each log message: // // ctx := context.WithValue(dcontext.Background(), "version", version) // GetLogger(ctx, "version").Infof("this log message has a version field") // // The above would print out a log message like this: // // INFO[0000] this log message has a version field version=v2.0.0-alpha.2.m // // When used with WithLogger, we gain the ability to decorate the context with // loggers that have information from disparate parts of the call stack. // Following from the version example, we can build a new context with the // configured logger such that we always print the version field: // // ctx = WithLogger(ctx, GetLogger(ctx, "version")) // // Since the logger has been pushed to the context, we can now get the version // field for free with our log messages. Future calls to GetLogger on the new // context will have the version field: // // GetLogger(ctx).Infof("this log message has a version field") // // This becomes more powerful when we start stacking loggers. Let's say we // have the version logger from above but also want a request id. Using the // context above, in our request scoped function, we place another logger in // the context: // // ctx = context.WithValue(ctx, "http.request.id", "unique id") // called when building request context // ctx = WithLogger(ctx, GetLogger(ctx, "http.request.id")) // // When GetLogger is called on the new context, "http.request.id" will be // included as a logger field, along with the original "version" field: // // INFO[0000] this log message has a version field http.request.id=unique id version=v2.0.0-alpha.2.m // // Note that this only affects the new context, the previous context, with the // version field, can be used independently. Put another way, the new logger, // added to the request context, is unique to that context and can have // request scoped variables. // // # HTTP Requests // // This package also contains several methods for working with http requests. // The concepts are very similar to those described above. We simply place the // request in the context using WithRequest. This makes the request variables // available. GetRequestLogger can then be called to get request specific // variables in a log line: // // ctx = WithRequest(ctx, req) // GetRequestLogger(ctx).Infof("request variables") // // Like above, if we want to include the request data in all log messages in // the context, we push the logger to a new context and use that one: // // ctx = WithLogger(ctx, GetRequestLogger(ctx)) // // The concept is fairly powerful and ensures that calls throughout the stack // can be traced in log messages. Using the fields like "http.request.id", one // can analyze call flow for a particular request with a simple grep of the // logs. package dcontext