A Go wrapper for Logrus, Errors, Mongo and Facebook Workplace giving you extremely detailed log reports. This package is designed to be used with github.com/ainsleyclark/errors for error reporting with codes, messages and more.
- ✅ Log a wide variety of log levels.
- ✅ Logs with custom errors featuring codes, messages and lifelines.
- ✅ Beautiful middleware and formatters for entries (see screenshots below).
- ✅ Facebook Workplace integration, any error marked as
INTERNAL
will be sent to WP. - ✅ Mongo integration, if specified log entries will be sent to a Mongo collection.
Detailed and verbose logging is important to any application or API. This package aims to make it easy for APIs to log errors to a central location, using a Logrus Hook.
go get -u github.com/ainsleyclark/logger
Get started with the Logger by calling logger.New()
and creating new options. The service is required, this is the
name of your currently running app.
func QuickStart() error {
err := logger.New(context.TODO(), logger.NewOptions().Service("service"))
if err != nil {
return err
}
logger.Trace("Trace Entry")
logger.Debug("Debug Entry")
logger.Info("Info Entry")
logger.Warn("Warn Entry")
logger.Error("Error Entry")
logger.WithError(errors.NewInternal(errors.New("error"), "message", "op")).Error()
logger.Fatal("Fatal Entry")
return nil
}
Outputs:
Fields allow you to log out key value pairs to the logger that will appear under data. The simplest way to use the logger is simply the package-level exported logger.
func Fields() {
logger.WithFields(types.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
This package is designed to work with [github.com/ainsleyclark/errors][https://github.com/ainsleyclark/errors] as such
the WithError
function can be used to log deatiled and rich error data.
func WithError() {
logger.WithError(errors.NewInternal(errors.New("error"), "message", "op")).Error()
}
Middleware is provided out of the box in the form of a fire hook. Upon receiving a request from the API,
calling logger.Fire
will send the log entry to stdout with detailed request information and meta.
func Middleware(r *http.Request) {
logger.Fire(logger.FireHook{
Request: r,
Status: http.StatusOK,
Message: "Message from API",
Data: map[string]any{},
RequestTime: time.Now(),
ResponseTime: time.Now(),
Latency: 100,
})
}
Creates a simple logger with stdout.
func Simple() error {
opts := logger.NewOptions().
Service("service").
Prefix("prefix").
DefaultStatus("status")
err := logger.New(context.Background(), opts)
if err != nil {
return err
}
logger.Info("Hello from Logger!")
return nil
}
Create a logger with Facebook Workplace integration. A token and a thread are required to send any error code that has
been marked as errors.INTERNAL
to thread ID passed.
func WithWorkplace() error {
opts := logger.NewOptions().
Service("api").
WithWorkplaceNotifier("token", "thread", nil, nil)
err := logger.New(context.Background(), opts)
if err != nil {
return err
}
logger.Info("Hello from Logger!")
return nil
}
You can pass a function to WithWorkplaceNotifier
as the second argument which is a callback function to determine if
the log entry should be sent to a thread, an example is below:
func WithWorkplaceReport() {
// Don't send the message to Workplace if there is no error.
workplaceCallBack := func(entry types.Entry) bool {
if !entry.HasError() {
return false
}
return true
}
_ = logger.NewOptions().
Service("api").
WithWorkplaceNotifier("token", "thread", workplaceCallBack, nil)
// etc
}
You can pass a function to WithWorkplaceNotifier
as the third argument which is a callback function to write the
message to Workplace. This is where you can customise the message easily and return a formatted string.
func WithWorkplaceReport() {
// Format the message with the supplied arguments.
workplaceCallBack := func(entry types.Entry) bool {
if !entry.HasError() {
return false
}
return true
}
_ = logger.NewOptions().
Service("api").
WithWorkplaceNotifier("token", "thread", workplaceCallBack, nil)
// etc
}
Create a logger with Facebook Slack integration. A token and a channel are required to send any error code that has
been marked as errors.INTERNAL
to thread ID passed.
Note All formatting and callbacks are available with Slack. See above for more details.
func WithSlack() error {
opts := logger.NewOptions().
Service("api").
WithSlackNotifier("token", "#channel", nil, nil)
err := logger.New(context.Background(), opts)
if err != nil {
return err
}
logger.Info("Hello from Logger!")
return nil
}
Create a logger with Mongo integration. All logs are sent to the collection passed using github.com/ainsleyclark/mogurs.
func WithMongo() error {
clientOptions := options.Client().
ApplyURI(os.Getenv("MONGO_CONNECTION")).
SetServerAPIOptions(options.ServerAPI(options.ServerAPIVersion1))
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatalln(err)
}
opts := logger.NewOptions().
Service("api").
WithMongoCollection(client.Database("logs").Collection("col"))
err = logger.New(context.Background(), opts)
if err != nil {
return err
}
logger.Info("Hello from Logger!")
return nil
}
You can pass a function to WithWorkplaceNotifier
as the second argument which is a callback function to determine if
the log entry should be stored within Mongo, an example is below:
func WithMongoReport() {
// Don't send the message to Mongo if there is no error.
mongoCallBack := func(entry types.Entry) bool {
if !entry.HasError() {
return false
}
return true
}
client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(os.Getenv("MONGO_CONNECTION")))
if err != nil {
log.Fatalln(err)
}
_ = logger.NewOptions().
Service("api").
WithMongoCollection(client.Database("logs").Collection("col"), mongoCallBack)
// etc
}
Boostrap all Log integrations.
func KitchenSink() error {
clientOptions := options.Client().
ApplyURI(os.Getenv("MONGO_CONNECTION")).
SetServerAPIOptions(options.ServerAPI(options.ServerAPIVersion1))
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
log.Fatalln(err)
}
opts := logger.NewOptions().
Service("service").
Prefix("prefix").
DefaultStatus("status").
WithWorkplaceNotifier("token", "thread").
WithSlackNotifier("token", "#channel").
WithMongoCollection(client.Database("logs").Collection("col"))
err = logger.New(context.Background(), opts)
if err != nil {
return err
}
logger.Info("Hello from Logger!")
return nil
}
Please feel free to make a pull request if you think something should be added to this package!
Shout out to the incredible Maria Letta for her excellent Gopher illustrations.
Code Copyright 2022 Errors. Code released under the MIT Licence.