Thursday, October 8, 2015

Save yourself and pass the context by

One of extending packages of Go is golang.org/x/net/context package. The idea comes form task oriented programming. You get a task to execute but want to attach some data to it. It appears to be useful when programing a RPC or web server solutions. In such cases your listener creates a context object and pass it to handlers. The handlers keep it and use it when appropriate.

This idea guided most Google App Engine APIs for Go. Now they’ve introduced a Managed VM’s which are something between App Engine and Compute Engine. The refactored libraries can be found here: google.golang.org/appengine.

The standard way of logging in App Engine was to get a context and call methods:

func SomeHandler(w http.ResponseWriter, req *http.Request) {
    ctx := appengine.NewContext(req)    
    ctx.Infof("got request!")
}

Whereas the new way:

func SomeHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
    log.Infof(ctx, "got request!")
}

The new way has one huge advantage, it allows you to pass any context which implements interface context.Context. It also requires to replace all appengine/log imports by a new package google.golang.org/appengine/log

The Go’ standard log library doesn’t have a concept of context at all.

Reasoning

I guess I should explain the advantage of using a context based log instead of standard one. In a case of task oriented application it allows the programmer to group all log messages related to given task. It’s a common practice to group messages by the place of the log function callback (the file and line where the log message is written). More sophisticated grouping includes process id and it may be a task id (or context in our case). Just imagine how much time it saves during debugging. It also allows much more sophisticated analysis of the server event flow without running in debugging mode.

I’ve created a tiny wrapper around both github.com/golang/glog library and google.golang.org/appengine/log: github.com/orian/utils/net/log. It should allow you to log both at App Engine and stand alone processes. Enjoy.

A real in depth explanation can be found in Go blog' article: Go Concurrency Patterns: Context

No comments:

Post a Comment