Logrus-stackdriver-formatter provides:
- logrus formatter for Stackdriver.
- go-kit log adapter for the above.
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 (
stackdriver "github.com/StevenACoffman/logrus-stackdriver-formatter"
"github.com/sirupsen/logrus"
)
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": {
"file": "github.com/StevenACoffman/logrus-stackdriver-formatter/example_test.go",
"line": 21,
"function": "ExampleLogError"
}
}
}
If you'd like to add additional context like 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")
}
Go-kit log is wrapped to encode conventions, enforce type-safety, provide leveled logging, and so on. It can be used for both typical application log events, and log-structured data streams.
import (
"os"
logadapter "github.com/StevenACoffman/logrus-stackdriver-formatter"
kitlog "github.com/go-kit/kit/log"
)
func main() {
w := kitlog.NewSyncWriter(os.Stderr)
logger := logadapter.InitLogrusGoKitLogger(w)
logger.Log("question", "what is the meaning of life?", "answer", 42)
// Output:
// question="what is the meaning of life?" answer=42
}
import (
"os"
logadapter "github.com/StevenACoffman/logrus-stackdriver-formatter"
kitlog "github.com/go-kit/kit/log"
)
func main() {
logger := logadapter.InitLogrusGoKitLogger(kitlog.NewSyncWriter(os.Stderr))
logger = kitlog.With(logger, "instance_id", 123)
logger.Log("msg", "starting")
NewWorker(kitlog.With(logger, "component", "worker")).Run()
NewSlacker(kitlog.With(logger, "component", "slacker")).Run()
}
// Output:
// instance_id=123 msg=starting
// instance_id=123 component=worker msg=running
// instance_id=123 component=slacker msg=running
go-kit's package log
is centered on the one-method Logger interface.
type Logger interface {
Log(keyvals ...interface{}) error
}
This interface, and its supporting code like is the product of much iteration and evaluation. For more details on the evolution of the Logger interface, see The Hunt for a Logger Interface, a talk by Chris Hines. Also, please see #63, #76, #131, #157, #164, and #252 to review historical conversations about package log and the Logger interface.
Value-add packages and suggestions, like improvements to the leveled logger, are of course welcome. Good proposals should
- Be composable with contextual loggers,
- Not break the behavior of log.Caller in any wrapped contextual loggers, and
- Be friendly to packages that accept only an unadorned log.Logger. ber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log
- Both go-kit log and logr both provide to developers clean, minimal surface area for sending log messages. However, neither has direct, first-class stackdriver support.
- Uber's Zap is very performant, but it's SugaredLogger API is unfamiliar to me.
So one choice could be logr -> zapr -> zap -> zap-stackdriver or zapdriver but zapr still uses dep, didn't have go module support.
I could also have gone with go-kit log -> zap -> zap-stackdriver or zapdriver.
Instead, I pulled a bunch of people's forks together into this piece of mad science because it seemed like it would work. ¯\_(ツ)_/¯