bradleyfalzon / gopherci

GopherCI was a project to help you maintain high-quality Go projects, by checking each GitHub Pull Request, for backward incompatible changes, and a suite of other third party static analysis tools.
https://gopherci.io
BSD 2-Clause "Simplified" License
102 stars 13 forks source link

WIP: Structured and Levelled Logging #117

Closed bradleyfalzon closed 7 years ago

bradleyfalzon commented 7 years ago

One thing production GopherCI doesn't have is structured logging.

My logging experience is mostly just with github.com/sirupsen/logrus, I'll use this because I know it, but there may be other libraries more appropriate (ideally smaller).

For email notifications, the logger will likely be aware of the 3rd party service, this is to ensure stack traces can be generated. Generally, loggers shouldn't be aware of these services, the application should just output logs to stdout, and different tools can watch these logs and behave as desired. Having the logger aware of these services means we don't need to log the full stacktrace, and can just send it directly. This is my current thinking, I'm not certain about this just yet.

bradleyfalzon commented 7 years ago

These are rough thoughts.

https://github.com/bketelsen/logr/blob/master/logr.go

I like this because context logging returns itself and accepts basic types WithField(name string, value interface{}) Logger, there's no WithFields, which is usually where other interfaces require custom structs.

https://godoc.org/github.com/sirupsen/logrus#FieldLogger

This is larger than I need, and contains defined type Fields (which is just map[string]interface{}), but returns the *Entry type.

https://godoc.org/github.com/go-kit/kit/log

go-kit's logger is probably the better so far, but the consumers are tied to it if they want levelled logging, but we could abstract that away I think.

bradleyfalzon commented 7 years ago

OK I'm leaning towards the following, provided by ./internal/logger and a func New(...) Logger which provides a logger wrapping logrus and sentry.

// Logger is a service to write structured, levelled logs with context.
type Logger interface {
    // Debug level for developer concerned debugging, not visible in production.
    Debug(args ...interface{})
    Debugf(format string, args ...interface{})

    // Info logs general events.
    Info(args ...interface{})
    Infof(format string, args ...interface{})

    // Error logs, errors. An error should only be logged once.
    Error(args ...interface{})
    Errorf(format string, args ...interface{})

    // Fatal logs an error and then immediately terminates execution.
    Fatal(args ...interface{})
    Fatalf(format string, args ...interface{})

    // With adds context to a logger.
    With(name string, value interface{}) Logger
}
bradleyfalzon commented 7 years ago

Closed via #122.