|
| 1 | +# Logging |
| 2 | + |
| 3 | +This code uses the [zap](https://pkg.go.dev/go.uber.org/zap) logging framework. |
| 4 | + |
| 5 | +Zap is a production quality logging library that is performant and highly configurable. |
| 6 | +Zap produces structured logging that can be easily machine-parsed, |
| 7 | +so that people can easily use tooling to filter through logs, |
| 8 | +or logs can easily be sent to log aggregation tooling. |
| 9 | + |
| 10 | +## Conventions |
| 11 | + |
| 12 | +### Instantiation |
| 13 | + |
| 14 | +Structs should hold a reference to their own `*zap.Logger` instance, as an unexported field named `log`. |
| 15 | +Callers should provide the logger instance as the first argument to a `NewFoo` method, setting any extra fields with the `With` method externally. |
| 16 | +For example: |
| 17 | + |
| 18 | +```go |
| 19 | +path := "/tmp/foo" |
| 20 | +foo := NewFoo(log.With(zap.String("path", path)), path) |
| 21 | +``` |
| 22 | + |
| 23 | +### Usage |
| 24 | + |
| 25 | +Log messages should begin with an uppercase letter and should not end with any punctuation. |
| 26 | +Log messages should be constant string literals; dynamic content is to be set as log fields. |
| 27 | +Names of log fields should be all lowercase `snake_case` format. |
| 28 | + |
| 29 | +```go |
| 30 | +// Do this: |
| 31 | +x.log.Debug("Updated height", zap.Int64("height", height)) |
| 32 | + |
| 33 | +// Don't do this: |
| 34 | +x.log.Debug(fmt.Sprintf("Updated height to %d.", height)) |
| 35 | +``` |
| 36 | + |
| 37 | +Errors are intended to be logged with `zap.Error(err)`. |
| 38 | +Error values should only be logged when they are not returned. |
| 39 | + |
| 40 | +```go |
| 41 | +// Do this: |
| 42 | +for _, x := range xs { |
| 43 | + if err := x.Validate(); err != nil { |
| 44 | + y.log.Info("Skipping x that failed validation", zap.String("id", x.ID), zap.Error(err)) |
| 45 | + continue |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +// Don't do this: |
| 50 | +if err := x.Validate(); err != nil { |
| 51 | + y.log.Info("X failed validation", zap.String("id", x.ID), zap.Error(err)) |
| 52 | + return err // Bad! |
| 53 | + // Returning an error that has already been logged may cause the same error |
| 54 | + // to be logged many times. |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +#### Log levels |
| 59 | + |
| 60 | +Debug level messages are off by default. |
| 61 | +Debug messages should be used sparingly; |
| 62 | +they are typically only intended for consumption by developers when actively debugging an issue. |
| 63 | + |
| 64 | +Info level messages and higher are on by default. |
| 65 | +They may contain any general information useful to an operator. |
| 66 | +It should be safe to discard all info level messages if an operator so desires. |
| 67 | + |
| 68 | +Warn level messages should be used to indicate a problem that may worsen without operator intervention. |
| 69 | + |
| 70 | +Error level messages should only be used to indicate a serious problem that cannot automatically recover. |
| 71 | +Error level messages should be reserved for events that are worthy of paging an engineer. |
| 72 | + |
| 73 | +Do not use Fatal or Panic level messages. |
0 commit comments