1. 6
  1.  

  2. 6

    I wish this included some explanation of why these are useful or explanations of why they are. Like, why use zerolog over logrus/zap/whatever? Why use gorilla/mux over gin or go-chi or the standard library? Why have that overly-complex unique code thing to determine where a logged error is thrown instead of making sure your errors have stack traces?

    1. 4

      I’m not the author of the post, but I can try to answer some questions:

      Like, why use zerolog over logrus/zap/whatever?

      zerolog and zap is what the author of logrus admit he would write if he wrote logrus/v2. zerolog claims to be a “better” version of zap (there are claims of performance improvement on other people’s computers)

      Why use gorilla/mux over gin or go-chi or the standard library?

      gorilla/mux is much lightweight as opposed to gin which has renderers, etc… Also, there are claims of very high performance on other people’s computers. With gorlla/mux you can plug your own json de-/serialization library which is faster than gin’s.

      Why have that overly-complex unique code thing to determine where a logged error is thrown instead of making sure your errors have stack traces?

      ¯\(ツ)/¯ No idea… The unique code approach feels very hacky and brittle to me.

      1. 3

        I would even suggest “httprouter” as a more lightweight alternative to gorilla/mux.

        1. 2

          Most “higher level” Go routers are probably based on it anyways.

        2. 1

          We use unique logging codes for our logs, and it makes it easier to locate a particular statement in either the logs, or the source code. Now, we generate the unique code by hand, but it’s not a horrendous issue for us (we have a separate document that records each logging statement).

        3. 1

          I’d be curious to know the best practices for annotating errors with stack traces. Any good library suggestions?

          1. 3

            github.com/pkg/errors has some nice helpers, as described in its documentation. The issue is that it requires changing your code to using errors.Errorf() instead of fmt.Errorf().

            Go2 will do it differently, but natively

            1. 3

              Also, errors.Wrapf is very useful when handling errors from packages which don’t use errors.

              1. 2

                You can wrap errors using fmt.Errorf() and the %w verb, and then later deal with them using errors.Is() or errors.As() and friends.

                1. 1

                  That doesn’t give you stack traces though, correct?

              2. 2

                YES. This is probably my biggest issue with supporting production Go code. Errors are still too hard to locate.

                1. 1

                  I personally use this to manage all that. If you use the errors.Wrap() function to wrap errors, it’ll add stack traces. And if you want to make a new error, the errors.New() function will also add a stack track where it was called. Then when you’re logging the error make sure it’s being logged in a way that will not just print the message. Most loggers should have a way to do that (I know zerolog and logrus do).

                  1. 1

                    Shameless plug for my errors library: https://pkg.go.dev/github.com/zeebo/errs/v2

                    • captures stack traces, but only once even if wrapped multiple times
                    • plays nicely with standard library errors package with errors.Is and errors.As
                    • has a “tag” feature to let you associate and query tags with errors
                    • helper to keep track of groups of errors
                2. 5

                  It’s always nice to see recommendations for structured logging over random string messages, but for new projects I’d rather lean on opentelemetry tracing/spans instead.