Go - Logging
fmt
has the most important debug functionality, printing.
package main
import "fmt"
func main() {
fmt.Print("Hello World!\n")
fmt.Println(fmt.Sprintf("Hi %s %s.", "Ruksi", "Laine")) // Hi Ruksi Laine.
// %s => string representation
fmt.Printf("Hi %s!\n", "Ruksi") // Hi Ruksi!
// %.2f => float point to certain precision
fmt.Printf("Hi %.2f!\n", 123.4567) // 123.45
// %v => default value representation
fmt.Printf("Hi %v!\n", "Ruksi") // Hi Ruksi!
// %#v => Go syntax like representation
fmt.Printf("Hi %#v!\n", "Ruksi") // Hi "Ruksi"!
// %T => Go syntax like representation
fmt.Printf("Hi %T!\n", "Ruksi") // Hi string!
// Writing to io.Writer interface.
//fmt.Fprintln(w, "Hi,", name)
}
log
package is worth a look. Especially nice as messages are returned with timestamps.
package main
import "log"
func main() {
log.Fatalln("main: log entry") // 2009/11/10 23:00:00 main: log entry
log.Panicln("main: log entry") // not printed, would print same and stack trace
log.Println("main: log entry") // not printed
}
Loggers are dependencies! Loggers should be dependencies, like any other library. Testing the log output of components that use the fixed global logger is annoying.
// Bad
func (f *foo) process() {
fmt.Fprintf(f.Output, "start\n")
result := f.Bar.compute()
log.Printf("bar: %v", result) // Whoops!
}
// Good
func (f *foo) process() {
fmt.Fprintf(f.Output, "start\n")
result := f.Bar.compute()
f.Logger.Printf("bar: %v", result) // Better.
}
// Still, add sensible default
func newFoo(..., cfg fooConfig) *foo {
if cfg.Logger == nil {
cfg.Logger = log.NewLogger(ioutil.Discard, ...)
}
}
Use structured logging. Pretty easy to read by humans, but also searchable by machines.
import log "github.com/Sirupsen/logrus"
func main() {
log.SetFormatter(&log.JSONFormatter{})
log.WithFields(log.Fields{
"userId": 1,
"server": "www.google.com",
}).Info("Redirecting user")
}
Don't log too much. Log only actionable information, which will be read by a human or a machine. Avoid too fine-grained log levels — info and debug are probably enough. Consider using structured logging: https://github.com/go-kit/kit/tree/master/log
Add monitoring. At least record what percent of requests get an error response and what is the 99th percentile response time.
Sources
- Go Documentation
- Go Concurrency
- Application Develpoment in Go
- Go 1.1 Function Calls by Russ Cox
- Package names
- Go Object Oriented Design
- Slices Usage and Internals
- Understanding Slices
- go-wiki - Errors
- Label Breaks In Go
- CodeReviewComments
- Gotchas and Common Mistakes in Go
- What's in a name?
- How to Ship Production Grade Go