7

How can I achieve MDC Logging (Java) in GoLang?

I need to add UUIDs in all server logs in order to be able to trace concurrent requests.

Gabe
  • 5,997
  • 5
  • 46
  • 92

1 Answers1

12

Java MDC relies on thread local storage, something Go does not have.

The closest thing is to thread a Context through your stack.

This is what more and more libraries are doing in Go.

A somewhat typical way is to do this via a middleware package that adds a request id to the context of a web request, like:

req = req.WithContext(context.WithValue(req.Context(),"requestId",ID))

Then, assuming you pass the context around, you pull it out with ctx.Value("requestId") and use it wherever it makes sense.

Possibly making your own custom logger function like:

func logStuff(ctx context.Context, msg string) {
    log.Println(ctx.Value("requestId"),msg) // call stdlib logger
}

There's a bunch of ways you may want to handle this, but that's a fairly simple form.

David Budworth
  • 11,248
  • 1
  • 36
  • 45
  • 4
    Go never ceases to amaze in the stupid design decisions that have all be solved in many other langauges and ecosystems – devshorts Nov 15 '18 at 16:32
  • 2
    Sure, there are some places where one might say, hmm, weird. I don't think this is one of them. Threadlocals are a great source of bugs in languages that have them. Folks use the as a crutch for poor application design and, especially in a RPC type system, often forget to clean values out, mixing data from one request to the next. – David Budworth Nov 26 '18 at 12:10
  • 2
    Don't use a string as the key. Use instead a value of a private type to avoid any conflict. `type requestIdKey struct{}` `req = req.WithContext(context.WithValue(req.Context(),requestIdKey{},ID))` – dolmen Oct 22 '19 at 09:17