On 8/15/17 7:14 AM, Chris Hines wrote:
I would be curious what you think of github.com/go-kit/kit/log (and related "sub"-packages). See my talk about it's design here:

Video: https://youtu.be/ojhFQNgyZO4?list=FLcxNiie7-UD8znndwDn7PFw
Slides: https://speakerdeck.com/chrishines/go-kit-log-package

I can see what you're going for with that, and in a way it's demonstrating some sugar issues in go. For some reason, folk expect to be able to write logging statements without an awful lot of unsightly brackets and constructors :-).

To quickly round them up, this module uses what I consider to be Perl 5-esque "slurpy hashes":

// Unstructured
log.Printf("HTTP server listening on %s", addr)

// Structured
logger.Log("transport","HTTP","addr", 
addr,"msg","listening")<https://github.com/go-kit/kit/tree/master/log#usage>

Whereas logrus steers you towards a map[string]interface{}:

func  main() {
  log.WithFields(log.Fields{
    "animal":"walrus",
  }).Info("A walrus appears")
}

And zap uses type-safe individual field constructors:

logger.Info("failed to fetch URL",
  // Structured context as strongly typed Field values.
  zap.String("url", url),
  zap.Int("attempt",3),
  zap.Duration("backoff", time.Second),
)

Of these, I lean towards the zap style because it's not significantly more verbose (IMHO), it's more type safe, and faster.

However, the syntax sugar issue has meant that zap now also have a similar interface to kit:

sugar  :=  logger.Sugar()
sugar.Infow("failed to fetch URL",
  // Structured context as loosely typed key-value pairs.
  "url", url,
  "attempt",3,
  "backoff", time.Second,
)


One common element is the ability to create a logger with tags pre-built:

// kit  
logger = log.With(logger,"instance_id",123)

// logrus
logger = logrus.WithFields(logrus.Fields{"instance_id": 123})

// zap
logger = logger.With(zap.Int("instance_id", 123))


IMHO appropriate use of this feature is critical to sane log analysis as soon as your app gets non-trivial: distributed, sharded, microservices, async, etc - non-linear, multiuser and multicore: it can simply save you down the track if you tag the request ID, customer ID, and particularly the value of a loop variable for log statements inside inner loops.

So I guess, what I found was that once I did that using zap, I really don't care that much about the syntax sugar. I would write things like:

for i, v := range arr {
   logger := logger.With(zap.Int("itemIdx", i))

   if err := v.Process(); err != nil {
       logger.Error("failed to process", zap.Object("error", err))
   }
}

And so the individual log statements don't go over the magic length at which blub programmers scoff, turn up their noses and say, "see, this is why go is so much worse than blub". It's also a good abstraction. And did I mention it's fast? I really like the way that it never combines the log line into something heavy like a map[string]interface{}, and that it just logs its fields in the order they were passed - so it's more like a traditional log line, just with JSON boundaries.

So anyway, yeah that's where I stand on that API - I can see how you got there, and I watched a structured logging talk at GopherCon 2016 which set me down this path, but after investigation I just couldn't trade performance, memory efficiency and a good abstraction for a little syntax sugar.

I'm not quite sure what the language or stdlib could do to make this better, other than shipping something like zap in stdlib. It's never really appropriate to use anything other than stdlib logging to log with in a library, and that's the nub of the problem: it means libraries will pretty much always have unstructured logging. The best you can do is to log each "printf" argument to its own field, but that's not a very good answer especially with the "message" is "%s: %s %s" or something.

Sam

--
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to