gobrake

package module
v4.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2020 License: MIT Imports: 24 Imported by: 4

README

Gobrake

Circle Build Status

Gobrake

Introduction

Gobrake is the official notifier library for Airbrake for the Go programming language, the leading exception reporting service. Gobrake provides a minimalist API that enables the ability to send any Go error or panic to the Airbrake dashboard. The library is extremely lightweight, with minimal overhead.

Key features

  • Simple, consistent and easy-to-use library API
  • Asynchronous exception reporting
  • Flexible configuration options
  • Support for environments
  • Filters support (filter out sensitive or unwanted data that shouldn't be sent)
  • Ability to ignore certain errors
  • SSL support (all communication with Airbrake is encrypted by default)
  • Panic reporting support
  • Severity support
  • Support for code hunks (lines of code surrounding each backtrace frame)
  • Automatic deploy tracking
  • Performance monitoring features such as HTTP route statistics, SQL queries, and Job execution statistics
  • Integrations with Beego and Gin
  • Last but not least, we follow semantic versioning 2.0.0

Installation

Go modules

Gobrake can be installed like any other Go package that supports Go modules.

Installing in an existing project

Just go get the library:

go get github.com/airbrake/gobrake/v4
Installing in a new project

Create a new directory, initialize a new module and go get the library:

mkdir airbrake_example && cd airbrake_example
go mod init airbrake_example
go get github.com/airbrake/gobrake/v4

Example

This is the minimal example that you can use to test Gobrake with your project.

package main

import (
	"errors"

	"github.com/airbrake/gobrake/v4"
)

var airbrake = gobrake.NewNotifierWithOptions(&gobrake.NotifierOptions{
	ProjectId:  105138,
	ProjectKey: "fd04e13d806a90f96614ad8e529b2822",
})

func main() {
	defer airbrake.Close()

	airbrake.Notify(errors.New("operation failed"), nil)
}

Configuration

There are two ways to configure Gobrake: quick and dirty & full.

Quick and dirty configuration

To configure a notifier quickly, you can call gobrake.NewNotifier, which accepts only two arguments: project id and project key. All of the other options will be set to default values.

airbrake := gobrake.NewNotifier(105138, "fd04e13d806a90f96614ad8e529b2822")
Full configuration

Full configuration is done through gobrake.NotifierOptions struct, which you are supposed to pass to gobrake.NewNotifierWithOptions. This way is much more flexible as it allows configuring all aspects of the notifier. It's the recommended way to configure your notifier.

airbrake := gobrake.NewNotifierWithOptions(&gobrake.NotifierOptions{
	ProjectId:  105138,
	ProjectKey: "fd04e13d806a90f96614ad8e529b2822",
})
ProjectId & ProjectKey

You must set both ProjectId & ProjectKey.

To find your ProjectId (int64) and ProjectKey (string) navigate to your project's General Settings and copy the values from the right sidebar.

Host

By default, it is set to https://api.airbrake.io. A host (string) is a web address containing a scheme ("http" or "https"), a host and a port. You can omit the port (80 will be assumed) and the scheme ("https" will be assumed).

opts := gobrake.NotifierOptions{
	Host: "http://localhost:8080/api/",
}
Environment

Configures the environment the application is running in. Helps Airbrake dashboard to distinguish between exceptions occurring in different environments. By default, it's not set. Expects string type.

opts := gobrake.NotifierOptions{
	Environment: "production",
}
Revision

Specifies current version control revision. If your app runs on Heroku, its value will be defaulted to SOURCE_VERSION environment variable. For non-Heroku apps this option is not set. Expects string type.

opts := gobrake.NotifierOptions{
	Revision: "d34db33f",
}
KeysBlocklist

Specifies which keys in the payload (parameters, session data, environment data, etc) should be filtered. Before sending an error, filtered keys will be substituted with the [Filtered] label.

By default, password and secret are filtered out. string and *regexp.Regexp types are permitted.

// String keys.
secrets := []string{"mySecretKey"}

// OR regexp keys
// secrets := []*regexp.Regexp{regexp.MustCompile("mySecretKey")}

blocklist := make([]interface{}, len(secrets))
for i, v := range secrets {
	blocklist[i] = v
}

opts := gobrake.NotifierOptions{
	KeysBlocklist: blocklist,
}
DisableCodeHunks

Controls code hunk collection. Code hunks are lines of code surrounding each backtrace frame. By default, it's set to false. Expects bool type.

opts := gobrake.NotifierOptions{
	DisableCodeHunks: true,
}
HTTPClient

HTTP client that is used to send data to Airbrake API. Expects *http.Client type. Normally, you shouldn't configure it.

opts := gobrake.NotifierOptions{
	HTTPClient: &http.Client{
		Timeout: 10 * time.Second,
	},
}

API

For complete API description please follow documentation on pkg.go.dev documentation.

AddFilter

AddFilter accepts a callback function which will be executed every time a gobrake.Notice is sent. You can use that for two purposes: filtering of unwanted or sensitive params or ignoring the whole notice completely.

Filtering unwanted params
// Filter out sensitive information such as credit cards.
airbrake.AddFilter(func(n *gobrake.Notice) *gobrake.Notice {
	if _, ok := n.Context["creditCard"] {
		n.Context["creditCard"] = "Filtered"
	}
	return n
})
Ignoring notices
// Ignore all notices in development.
airbrake.AddFilter(func(n *gobrake.Notice) *gobrake.Notice {
	if n.Context["environment"] == "development" {
		return nil
	}
	return n
})
Setting severity

Severity allows categorizing how severe an error is. By default, it's set to error. To redefine severity, simply overwrite context/severity of a notice object. For example:

notice := airbrake.NewNotice("operation failed", nil, 0)
notice.Context["severity"] = "critical"
airbrake.Notify(notice, nil)
Sending routes stats

In order to collect some basic routes stats you can instrument your application using notifier.Routes.Notify API. We also have prepared HTTP middleware examples for Gin and Beego. Here is an example using the net/http middleware.

package main

import (
  "fmt"
  "net/http"

  "github.com/airbrake/gobrake"
)

// Airbrake is used to report errors and track performance
var Airbrake = gobrake.NewNotifierWithOptions(&gobrake.NotifierOptions{
  ProjectId:   123123,				// <-- Fill in this value
  ProjectKey:  "YourProjectAPIKey", // <-- Fill in this value
  Environment: "Production",
})

func indexHandler(w http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(w, "Hello, There!")
}

func main() {
  fmt.Println("Server listening at http://localhost:5555/")
  // Wrap the indexHandler with Airbrake Performance Monitoring middleware:
  http.HandleFunc(airbrakePerformance("/", indexHandler))
  http.ListenAndServe(":5555", nil)
}

func airbrakePerformance(route string, h http.HandlerFunc) (string, http.HandlerFunc) {
  handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
	ctx := req.Context()
	ctx, routeMetric := gobrake.NewRouteMetric(ctx, req.Method, route) // Starts the timing
	arw := newAirbrakeResponseWriter(w)

	h.ServeHTTP(arw, req)

	routeMetric.StatusCode = arw.statusCode
	Airbrake.Routes.Notify(ctx, routeMetric) // Stops the timing and reports
	fmt.Printf("code: %v, method: %v, route: %v\n", arw.statusCode, req.Method, route)
  })

  return route, handler
}

type airbrakeResponseWriter struct {
  http.ResponseWriter
  statusCode int
}

func newAirbrakeResponseWriter(w http.ResponseWriter) *airbrakeResponseWriter {
  // Returns 200 OK if WriteHeader isn't called
  return &airbrakeResponseWriter{w, http.StatusOK}
}

func (arw *airbrakeResponseWriter) WriteHeader(code int) {
  arw.statusCode = code
  arw.ResponseWriter.WriteHeader(code)
}

To get more detailed timing you can wrap important blocks of code into spans. For example, you can create 2 spans sql and http to measure timing of specific operations:

metric := &gobrake.RouteMetric{
	Method: c.Request.Method,
	Route:	routeName,
	StartTime:	time.Now(),
}

ctx, span := metric.Start(ctx, "sql")
users, err := fetchUser(ctx, userID)
span.Finish()

ctx, span = metric.Start(ctx, "http")
resp, err := http.Get("http://example.com/")
span.Finish()

metric.StatusCode = http.StatusOK
notifier.Routes.Notify(ctx, metric)

You can also collect stats about individual SQL queries performance using following API:

notifier.Queries.Notify(&gobrake.QueryInfo{
	Query:	   "SELECT * FROM users WHERE id = ?", // query must be normalized
	Func:	   "fetchUser", // optional
	File:	   "models/user.go", // optional
	Line:	   123, // optional
	StartTime: startTime,
	EndTime:   time.Now(),
})
Sending queue stats
metric := &gobrake.QueueMetric{
	Queue: "my-queue-name",
	StartTime:	time.Now(),
}

ctx, span := metric.Start(ctx, "sql")
users, err := fetchUser(ctx, userID)
span.Finish()

ctx, span = metric.Start(ctx, "http")
resp, err := http.Get("http://example.com/")
span.Finish()

notifier.Queues.Notify(ctx, metric)

Additional notes

Exception limit

The maximum size of an exception is 64KB. Exceptions that exceed this limit will be truncated to fit the size.

Logging

There's a glog fork, which integrates with Gobrake. It provides all of original glog's functionality and adds the ability to send errors/logs to Airbrake.io.

Supported Go versions

The library supports Go v1.11+. The CI file would be the best source of truth because it contains all Go versions that we test against.

Contact

In case you have a problem, question or a bug report, feel free to:

License

The project uses the MIT License. See LICENSE.md for details.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetLogger added in v4.1.0

func GetLogger() *log.Logger

func NewBlocklistKeysFilter added in v4.1.2

func NewBlocklistKeysFilter(keys ...interface{}) func(*Notice) *Notice
Example
notifier := gobrake.NewNotifier(1, "key")
filter := gobrake.NewBlocklistKeysFilter("password", regexp.MustCompile("(?i)(user)"))
notifier.AddFilter(filter)

notice := &gobrake.Notice{
	Params: map[string]interface{}{
		"password": "slds2&LP",
		"User":     "username",
		"email":    "john@example.com",
	},
}
notifier.Notify(notice, nil)
Output:

func SetLogger

func SetLogger(l *log.Logger)

Types

type Error

type Error struct {
	Type      string       `json:"type"`
	Message   string       `json:"message"`
	Backtrace []StackFrame `json:"backtrace"`
}

type Metric

type Metric interface {
	Start(c context.Context, name string) (context.Context, Span)
}

func ContextMetric

func ContextMetric(c context.Context) Metric

type Notice

type Notice struct {
	Id    string `json:"-"` // id returned by SendNotice
	Error error  `json:"-"` // error returned by SendNotice

	Errors  []Error                `json:"errors"`
	Context map[string]interface{} `json:"context"`
	Env     map[string]interface{} `json:"environment"`
	Session map[string]interface{} `json:"session"`
	Params  map[string]interface{} `json:"params"`
}

func NewNotice

func NewNotice(e interface{}, req *http.Request, depth int) *Notice

func (*Notice) SetRequest

func (n *Notice) SetRequest(req *http.Request)

func (*Notice) String

func (n *Notice) String() string

type Notifier

type Notifier struct {
	Routes  *routes
	Queries *queryStats
	Queues  *queueStats
	// contains filtered or unexported fields
}

func NewNotifier

func NewNotifier(projectId int64, projectKey string) *Notifier

func NewNotifierWithOptions

func NewNotifierWithOptions(opt *NotifierOptions) *Notifier

func (*Notifier) AddFilter

func (n *Notifier) AddFilter(fn func(*Notice) *Notice)

AddFilter adds filter that can change notice or ignore it by returning nil.

func (*Notifier) Close

func (n *Notifier) Close() error

func (*Notifier) CloseTimeout

func (n *Notifier) CloseTimeout(timeout time.Duration) error

CloseTimeout waits for pending requests to finish and then closes the notifier.

func (*Notifier) Flush

func (n *Notifier) Flush()

Flush waits for pending requests to finish.

func (*Notifier) Notice

func (n *Notifier) Notice(err interface{}, req *http.Request, depth int) *Notice

Notice returns Aibrake notice created from error and request. depth determines which call frame to use when constructing backtrace.

func (*Notifier) Notify

func (n *Notifier) Notify(e interface{}, req *http.Request)

Notify notifies Airbrake about the error.

func (*Notifier) NotifyOnPanic

func (n *Notifier) NotifyOnPanic()

NotifyOnPanic notifies Airbrake about the panic and should be used with defer statement.

func (*Notifier) SendNotice

func (n *Notifier) SendNotice(notice *Notice) (string, error)

SendNotice sends notice to Airbrake.

func (*Notifier) SendNoticeAsync

func (n *Notifier) SendNoticeAsync(notice *Notice)

SendNoticeAsync is like SendNotice, but sends notice asynchronously. Pending notices can be flushed with Flush.

type NotifierOptions

type NotifierOptions struct {
	// Airbrake project id.
	ProjectId int64
	// Airbrake project key.
	ProjectKey string
	// Airbrake host name. Default is https://airbrake.io.
	Host string

	// Environment such as production or development.
	Environment string
	// Git revision. Default is SOURCE_VERSION on Heroku.
	Revision string
	// List of keys containing sensitive information that must be filtered out.
	// Default is password, secret.
	KeysBlocklist []interface{}
	// Deprecated version of "KeysBlocklist". Still supported but will eventually
	// be removed in a future release.
	KeysBlacklist []interface{}
	// Disables code hunks.
	DisableCodeHunks bool

	// http.Client that is used to interact with Airbrake API.
	HTTPClient *http.Client
}

type QueryInfo

type QueryInfo struct {
	Method    string
	Route     string
	Query     string
	Func      string
	File      string
	Line      int
	StartTime time.Time
	EndTime   time.Time
}

type QueueMetric

type QueueMetric struct {
	Queue   string
	Errored bool
	// contains filtered or unexported fields
}

func ContextQueueMetric

func ContextQueueMetric(c context.Context) *QueueMetric

func NewQueueMetric

func NewQueueMetric(c context.Context, name string) (context.Context, *QueueMetric)

func (*QueueMetric) Start

func (t *QueueMetric) Start(c context.Context, name string) (context.Context, Span)

func (*QueueMetric) WithSpan

func (t *QueueMetric) WithSpan(ctx context.Context, name string, body func(context.Context) error) error

type RouteMetric

type RouteMetric struct {
	Method      string
	Route       string
	StatusCode  int
	ContentType string
	// contains filtered or unexported fields
}

func ContextRouteMetric

func ContextRouteMetric(c context.Context) *RouteMetric

func NewRouteMetric

func NewRouteMetric(c context.Context, method, route string) (context.Context, *RouteMetric)

func (*RouteMetric) Start

func (t *RouteMetric) Start(c context.Context, name string) (context.Context, Span)

func (*RouteMetric) WithSpan

func (t *RouteMetric) WithSpan(ctx context.Context, name string, body func(context.Context) error) error

type Span

type Span interface {
	Finish()
}

func ContextSpan

func ContextSpan(c context.Context) Span

type StackFrame

type StackFrame struct {
	File string         `json:"file"`
	Line int            `json:"line"`
	Func string         `json:"function"`
	Code map[int]string `json:"code,omitempty"`
}

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL