logrus formatter for Stackdriver.
In addition to supporting level-based logging to Stackdriver, for Error, Fatal and Panic levels it will append error context for Error Reporting.
go get -u github.com/TV4/logrus-stackdriver-formatter
package main
import (
"github.com/sirupsen/logrus"
stackdriver "github.com/TV4/logrus-stackdriver-formatter"
)
var log = logrus.New()
func init() {
log.Formatter = stackdriver.NewFormatter(
stackdriver.WithService("your-service"),
stackdriver.WithVersion("v0.1.0"),
)
log.Level = logrus.DebugLevel
log.Info("ready to log!")
}
Here's a sample entry (prettified) from the example:
{
"serviceContext": {
"service": "test-service",
"version": "v0.1.0"
},
"message": "unable to parse integer: strconv.ParseInt: parsing \"text\": invalid syntax",
"severity": "ERROR",
"context": {
"reportLocation": {
"filePath": "github.com/TV4/logrus-stackdriver-formatter/example_test.go",
"lineNumber": 21,
"functionName": "ExampleLogError"
}
}
}
There are a few fields that can be set to provide extra context for errors which are surfaced in the Error Reporting UI to aid in debugging:
Logrus Field Name | Expected Go Type | Format/Schema |
---|---|---|
httpRequest |
map[string]interface{} |
HttpRequestContext |
user |
string |
unrestricted |
stack_trace |
string |
result of runtime.Stack() |
If you'd like to add additional context, for example the httpRequest
, here's a convenience function for creating a HTTP logger:
func httpLogger(logger *logrus.Logger, r *http.Request) *logrus.Entry {
return logger.WithFields(logrus.Fields{
"httpRequest": map[string]interface{}{
"method": r.Method,
"url": r.URL.String(),
"userAgent": r.Header.Get("User-Agent"),
"referrer": r.Header.Get("Referer"),
},
})
}
Then, in your HTTP handler, create a new context logger and all your log entries will have the HTTP request context appended to them:
func handler(w http.ResponseWriter, r *http.Request) {
httplog := httpLogger(log, r)
// ...
httplog.Infof("Logging with HTTP request context")
}
Adding stack traces for errors looks like:
import "runtime/debug"
err := doAThing()
if (err != nil) {
log.
WithField("stack_trace", string(debug.Stack())).
WithError(err).
Error("doing a thing failed")
}