Home

Awesome

slog-bugsnag

tag Go Version GoDoc Build Status Go report Coverage Contributors License

Golang structured logging (slog) handler middleware for Bugsnag. Automatically send all Error level logs to Bugsnag, along with all attributes and context. Never forget to snag another bug again.

Other Great SLOG Utilities

Install

go get github.com/veqryn/slog-bugsnag

import (
	slogbugsnag "github.com/veqryn/slog-bugsnag"
)

Usage

package main

import (
	"context"
	"log/slog"
	"net/http"
	"os"

	"github.com/bugsnag/bugsnag-go/v2"
	"github.com/pkg/errors"
	slogbugsnag "github.com/veqryn/slog-bugsnag"
)

func main() {
	// Configure bugsnag
	bugsnag.Configure(bugsnag.Configuration{
		APIKey:     os.Getenv("BUGSNAG_API_KEY"),
		AppVersion: "0.1.0",
	})

	// Setup slog handlers
	h := slogbugsnag.NewHandler(slog.NewJSONHandler(os.Stdout, nil), nil)
	slog.SetDefault(slog.New(h))

	// Optional: closing the handler will flush all bugs in the queue to bugsnag
	defer h.Close()

	slog.Info("starting up...") // Not sent to bugsnag

	err := errors.New("my horrible error")
	slog.Error("oh no...", "err", err) // Sent to bugsnag, with original err's stack trace

	// Can be used with context too
	ctx := bugsnag.StartSession(context.Background())
	defer bugsnag.AutoNotify()

	// Bugsnag can capture basic http.Request data, if added to the ctx
	req, _ := http.NewRequest("GET", "https://www.github.com/veqryn/slog-bugsnag", nil)
	ctx = bugsnag.AttachRequestData(ctx, req)

	// User information can be sent as a bugsnag.User
	user := bugsnag.User{Id: "1234", Name: "joe", Email: "none"}

	// Or using these string types, added to the log as attribute values (any key is fine)
	id := slogbugsnag.ID("1234")
	name := slogbugsnag.Name("joe")
	email := slogbugsnag.Email("none")

	// Tabs will be created in bugsnag for each group,
	// with the root level attributes going into a "log" tab.
	log := slog.With(slog.Any("id", id), slog.Any("name", name), slog.Any("email", email))
	log = log.WithGroup("MyTab")

	// If no "error" type is found among log attribute values,
	// then an error will be created using the log message, with a stack trace at the log call.
	log.ErrorContext(ctx, "more bad things", slog.Any("user", user), slog.String("foo", "bar"))

	// All of the above will log out 3 lines and send 2 bugs reports to bugsnag.
	// The second bug will have tabs for Stacktrace, App, Device, Request, User, Log, and MyTab,
	// containing all the data in the log record.
}

slog-multi Middleware

This library has a convenience method that allow it to interoperate with github.com/samber/slog-multi, in order to easily setup slog workflows such as pipelines, fanout, routing, failover, etc.

notifiers := slogbugsnag.NewNotifierWorkers(&slogbugsnag.NotifierOptions{})
defer notifiers.Close()

slog.SetDefault(slog.New(slogmulti.
	Pipe(slogcontext.NewMiddleware(&slogcontext.HandlerOptions{})).
	Pipe(slogdedup.NewOverwriteMiddleware(&slogdedup.OverwriteHandlerOptions{})).
	Pipe(slogbugsnag.NewMiddleware(&slogbugsnag.HandlerOptions{Notifiers: notifiers})).
	Handler(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{})),
))