✏️ Logger
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.
Overview
- ✅ 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.
Why?
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.
Installation
go get -u github.com/ainsleyclark/logger
Quick Start
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
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")
}
Errors
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
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,
})
}
Recipes
Simple
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
}
WithWorkplace
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
}
Workplace CallBack
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
}
WithSlack
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
}
WithMongo
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
}
Mongo CallBack
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
}
KitchenSink
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
}
Contributing
Please feel free to make a pull request if you think something should be added to this package!
Credits
Shout out to the incredible Maria Letta for her excellent Gopher illustrations.
Licence
Code Copyright 2022 Errors. Code released under the MIT Licence.