Reporting handled errors

In order to quickly understand and fix some errors, it is often helpful to send additional diagnostic data which is specific to that error.

The bugsnag.Notify() function expects one instance of either an error or an errors.Error. Using an errors.Error object captures the stack trace at the call site instead of when Notify() is called, and supports skipping stack frames.

// send an error object directly
bugsnag.Notify(err)

// construct an Error with a format string
bugsnag.Notify(errors.Errorf("broken pipe: %d", code))

// wrap an error object, trimming 0 stack frames (more info below)
bugsnag.Notify(errors.New(err, 0))

Using a logging wrapper

If you have your own logging wrapper all of your errors will appear to originate from inside it, resulting in unrelated events grouping together on the Bugsnag dashboard. You can avoid this problem by constructing an Error object using errors.New() and trimming the logging function from the stack trace:

import (
    "github.com/bugsnag/bugsnag-go/v2"
    "github.com/bugsnag/bugsnag-go/v2/errors"
)

func LogError(e error) {
    // 1 removes one line from the stack trace, so the caller of LogError
    // will be at the top.
    bugsnag.Notify(errors.New(e, 1))
}

Appending diagnostic data

In addition to the error object, Notify accepts several options for customization.

Modifier function

The bugsnag.Notify() function accepts a function as an argument to allow complex customization of the Event created from an error. See the bugsnag.Event object for a list of modifiable properties.

bugsnag.Notify(err, func(event *Event) {
    event.Context = "mail router"

    // Remove a custom logging function
    if event.Stacktrace[0].File = "mylogger.go" {
        event.Stacktrace = event.Stacktrace[1:]
    }

    // Count the event in stability score
    event.Unhandled = true
})

context.Context

To track information per session (e.g. per HTTP request) the Go team advocates the context idiom.

For most of the frameworks we support including bugsnag.Handler and bugsnag.HandlerFunc Bugsnag will automatically attach a context.Context to the request, which can be retrieved through r.Context().

If you’re outside the context of a HTTP request, e.g. inside a goroutine, you can call ctx = bugsnag.StartSession(ctx) to let Bugsnag track your session.

go func() {
    ctx := bugsnag.StartSession(context.Background())
    defer bugsnag.AutoNotify(ctx)
    // goroutine logic...
    if err != nil {
        bugsnag.Notify(err, ctx)
    }
}()

If you wish to share the session between two goroutines you should pass the context to your goroutine function:

go func(ctx context) {
    defer bugsnag.AutoNotify(ctx)
    // goroutine logic...
    if err != nil {
        bugsnag.Notify(err, ctx)
    }
}(ctx)

bugsnag.Context

Note: This has no relation to the context.Context mentioned above.

The context shows up prominently in your Bugsnag inbox so that you can get an idea of where a problem occurred. You can set it by passing a bugsnag.Context object as rawData.

bugsnag.Notify(err, ctx, bugsnag.Context{String: "backgroundJob"})

See this reference to learn more about the ctx argument and the advantages of using it.

bugsnag.ErrorClass

Errors in your Bugsnag dashboard are grouped by their “error class” and by line number. You can override the error class by passing a bugsnag.ErrorClass object as rawData.

bugsnag.Notify(err, ctx, bugsnag.ErrorClass{Name: "I/O Timeout"})

See this reference to learn more about the ctx argument and the advantages of using it.

bugsnag.HandledState

The handled state object determines the handled-ness of events reported on your Bugsnag dashboard. By default, all invocations of Notify() are reported as “handled” while any panics or errors automatically detected in web framework middleware are unhandled. You can override the handled-ness of an event by passing in a bugsnag.HandledState object as rawData:

bugsnag.Notify(err, ctx, bugsnag.HandledState{
    SeverityReason:   bugsnag.SeverityReasonUnhandledError,
    OriginalSeverity: bugsnag.SeverityError,
    Unhandled:      true,
})

See this reference to learn more about the ctx argument and the advantages of using it.

bugsnag.MetaData

Custom metaData appears as tabs on Bugsnag.com. You can set it by passing a bugsnag.MetaData object as rawData.

bugsnag.Notify(err, ctx,
    bugsnag.MetaData{
        "Account": {
            "Name": Account.Name,
            "Paying": Account.Plan.Premium,
        },
    })

See this reference to learn more about the ctx argument and the advantages of using it.

bugsnag.Severity

Bugsnag supports three severities, SeverityError, SeverityWarning, and SeverityInfo. You can set the severity of an error by passing one of these objects as rawData.

bugsnag.Notify(err, ctx, bugsnag.SeverityInfo)

See this reference to learn more about the ctx argument and the advantages of using it.

bugsnag.User

User data is searchable, and the Id powers the count of users affected. You can identify which user an error affects by passing a bugsnag.User object as rawData.

bugsnag.Notify(err, ctx, bugsnag.User{
    Id: "1234", Name: "Conrad", Email: "me@example.com"})

See this reference to learn more about the ctx argument and the advantages of using it.

http.Request

Bugsnag can extract interesting data from *http.Request objects. If you are using bugsnag.Handler, bugsnag.HandlerFunc or any of the supported frameworks you can pass the context of a *http.Request to bugsnag.Notify() to see request data in the dashboard.

func (w http.ResponseWriter, r *http.Request) {
    // ...
    bugsnag.Notify(err, r.Context())
}

These are automatically passed in when handling panics.

If you are using another framework that exposes *http.Request objects, you can pass these directly to bugsnag.Notify as well.

func (w http.ResponseWriter, r *http.Request) {
    // ...
    bugsnag.Notify(err, r)
}

See this reference to learn more about the r.Context() argument and the advantages of using it.