• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..17-Jan-2019-

errors/H17-Jan-2019-324223

README.mdH A D17-Jan-201913.4 KiB490363

appengine.goH A D17-Jan-20191.5 KiB7756

bugsnag.goH A D17-Jan-20194.5 KiB13274

configuration.goH A D17-Jan-20194.9 KiB160106

doc.goH A D17-Jan-20192.4 KiB701

event.goH A D17-Jan-20193.6 KiB13582

json_tags.goH A D17-Jan-20191,008 4429

metadata.goH A D17-Jan-20194.4 KiB186122

middleware.goH A D17-Jan-20192.7 KiB9764

notifier.goH A D17-Jan-20192.5 KiB9666

panicwrap.goH A D17-Jan-2019668 2818

payload.goH A D17-Jan-20191.7 KiB9777

README.md

1Bugsnag Notifier for Golang
2===========================
3
4The Bugsnag Notifier for Golang gives you instant notification of panics, or
5unexpected errors, in your golang app. Any unhandled panics will trigger a
6notification to be sent to your Bugsnag project.
7
8[Bugsnag](http://bugsnag.com) captures errors in real-time from your web,
9mobile and desktop applications, helping you to understand and resolve them
10as fast as possible. [Create a free account](http://bugsnag.com) to start
11capturing exceptions from your applications.
12
13## How to Install
14
151. Download the code
16
17    ```shell
18    go get github.com/bugsnag/bugsnag-go
19    ```
20
21### Using with net/http apps
22
23For a golang app based on [net/http](https://godoc.org/net/http), integrating
24Bugsnag takes two steps. You should also use these instructions if you're using
25the [gorilla toolkit](http://www.gorillatoolkit.org/), or the
26[pat](https://github.com/bmizerany/pat/) muxer.
27
281. Configure bugsnag at the start of your `main()` function:
29
30    ```go
31    import "github.com/bugsnag/bugsnag-go"
32
33    func main() {
34        bugsnag.Configure(bugsnag.Configuration{
35            APIKey: "YOUR_API_KEY_HERE",
36            ReleaseStage: "production",
37            // more configuration options
38        })
39
40        // rest of your program.
41    }
42    ```
43
442. Wrap your server in a [bugsnag.Handler](https://godoc.org/github.com/bugsnag/bugsnag-go/#Handler)
45
46    ```go
47    // a. If you're using the builtin http mux, you can just pass
48    //    bugsnag.Handler(nil) to http.ListenAndServer
49    http.ListenAndServe(":8080", bugsnag.Handler(nil))
50
51    // b. If you're creating a server manually yourself, you can set
52    //    its handlers the same way
53    srv := http.Server{
54        Handler: bugsnag.Handler(nil)
55    }
56
57    // c. If you're not using the builtin http mux, wrap your own handler
58    // (though make sure that it doesn't already catch panics)
59    http.ListenAndServe(":8080", bugsnag.Handler(handler))
60    ```
61
62### Using with Revel apps
63
64There are two steps to get panic handling in [revel](https://revel.github.io) apps.
65
661. Add the `bugsnagrevel.Filter` immediately after the `revel.PanicFilter` in `app/init.go`:
67
68    ```go
69
70    import "github.com/bugsnag/bugsnag-go/revel"
71
72    revel.Filters = []revel.Filter{
73        revel.PanicFilter,
74        bugsnagrevel.Filter,
75        // ...
76    }
77    ```
78
792. Set bugsnag.apikey in the top section of `conf/app.conf`.
80
81    ```
82    module.static=github.com/revel/revel/modules/static
83
84    bugsnag.apikey=YOUR_API_KEY_HERE
85
86    [dev]
87    ```
88
89### Using with Google App Engine
90
911. Configure bugsnag at the start of your `init()` function:
92
93    ```go
94    import "github.com/bugsnag/bugsnag-go"
95
96    func init() {
97        bugsnag.Configure(bugsnag.Configuration{
98            APIKey: "YOUR_API_KEY_HERE",
99        })
100
101        // ...
102    }
103    ```
104
1052. Wrap *every* http.Handler or http.HandlerFunc with Bugsnag:
106
107    ```go
108    // a. If you're using HandlerFuncs
109    http.HandleFunc("/", bugsnag.HandlerFunc(
110        func (w http.ResponseWriter, r *http.Request) {
111            // ...
112        }))
113
114    // b. If you're using Handlers
115    http.Handle("/", bugsnag.Handler(myHttpHandler))
116    ```
117
1183. In order to use Bugsnag, you must provide the current
119[`appengine.Context`](https://developers.google.com/appengine/docs/go/reference#Context), or
120current `*http.Request` as rawData. The easiest way to do this is to create a new notifier.
121
122    ```go
123    c := appengine.NewContext(r)
124    notifier := bugsnag.New(c)
125
126    if err != nil {
127        notifier.Notify(err)
128    }
129
130    go func () {
131        defer notifier.Recover()
132
133        // ...
134    }()
135    ```
136
137
138## Notifying Bugsnag manually
139
140Bugsnag will automatically handle any panics that crash your program and notify
141you of them. If you've integrated with `revel` or `net/http`, then you'll also
142be notified of any panics() that happen while processing a request.
143
144Sometimes however it's useful to manually notify Bugsnag of a problem. To do this,
145call [`bugsnag.Notify()`](https://godoc.org/github.com/bugsnag/bugsnag-go/#Notify)
146
147```go
148if err != nil {
149    bugsnag.Notify(err)
150}
151```
152
153### Manual panic handling
154
155To avoid a panic in a goroutine from crashing your entire app, you can use
156[`bugsnag.Recover()`](https://godoc.org/github.com/bugsnag/bugsnag-go/#Recover)
157to stop a panic from unwinding the stack any further. When `Recover()` is hit,
158it will send any current panic to Bugsnag and then stop panicking. This is
159most useful at the start of a goroutine:
160
161```go
162go func() {
163    defer bugsnag.Recover()
164
165    // ...
166}()
167```
168
169Alternatively you can use
170[`bugsnag.AutoNotify()`](https://godoc.org/github.com/bugsnag/bugsnag-go/#Recover)
171to notify bugsnag of a panic while letting the program continue to panic. This
172is useful if you're using a Framework that already has some handling of panics
173and you are retrofitting bugsnag support.
174
175```go
176defer bugsnag.AutoNotify()
177```
178
179## Sending Custom Data
180
181Most functions in the Bugsnag API, including `bugsnag.Notify()`,
182`bugsnag.Recover()`, `bugsnag.AutoNotify()`, and `bugsnag.Handler()` let you
183attach data to the notifications that they send. To do this you pass in rawData,
184which can be any of the supported types listed here. To add support for more
185types of rawData see [OnBeforeNotify](#custom-data-with-onbeforenotify).
186
187### Custom MetaData
188
189Custom metaData appears as tabs on Bugsnag.com. You can set it by passing
190a [`bugsnag.MetaData`](https://godoc.org/github.com/bugsnag/bugsnag-go/#MetaData)
191object as rawData.
192
193```go
194bugsnag.Notify(err,
195    bugsnag.MetaData{
196        "Account": {
197            "Name": Account.Name,
198            "Paying": Account.Plan.Premium,
199        },
200    })
201```
202
203### Request data
204
205Bugsnag can extract interesting data from
206[`*http.Request`](https://godoc.org/net/http/#Request) objects, and
207[`*revel.Controller`](https://godoc.org/github.com/revel/revel/#Controller)
208objects. These are automatically passed in when handling panics, and you can
209pass them yourself.
210
211```go
212func (w http.ResponseWriter, r *http.Request) {
213    bugsnag.Notify(err, r)
214}
215```
216
217### User data
218
219User data is searchable, and the `Id` powers the count of users affected. You
220can set which user an error affects by passing a
221[`bugsnag.User`](https://godoc.org/github.com/bugsnag/bugsnag-go/#User) object as
222rawData.
223
224```go
225bugsnag.Notify(err,
226    bugsnag.User{Id: "1234", Name: "Conrad", Email: "me@cirw.in"})
227```
228
229### Context
230
231The context shows up prominently in the list view so that you can get an idea
232of where a problem occurred. You can set it by passing a
233[`bugsnag.Context`](https://godoc.org/github.com/bugsnag/bugsnag-go/#Context)
234object as rawData.
235
236```go
237bugsnag.Notify(err, bugsnag.Context{"backgroundJob"})
238```
239
240### Severity
241
242Bugsnag supports three severities, `SeverityError`, `SeverityWarning`, and `SeverityInfo`.
243You can set the severity of an error by passing one of these objects as rawData.
244
245```go
246bugsnag.Notify(err, bugsnag.SeverityInfo)
247```
248
249## Configuration
250
251You must call `bugsnag.Configure()` at the start of your program to use Bugsnag, you pass it
252a [`bugsnag.Configuration`](https://godoc.org/github.com/bugsnag/bugsnag-go/#Configuration) object
253containing any of the following values.
254
255### APIKey
256
257The Bugsnag API key can be found on your [Bugsnag dashboard](https://bugsnag.com) under "Settings".
258
259```go
260bugsnag.Configure(bugsnag.Configuration{
261    APIKey: "YOUR_API_KEY_HERE",
262})
263```
264
265### Endpoint
266
267The Bugsnag endpoint defaults to `https://notify.bugsnag.com/`. If you're using Bugsnag enterprise,
268you should set this to the endpoint of your local instance.
269
270```go
271bugsnag.Configure(bugsnag.Configuration{
272    Endpoint: "http://bugsnag.internal:49000/",
273})
274```
275
276### ReleaseStage
277
278The ReleaseStage tracks where your app is deployed. You should set this to `production`, `staging`,
279`development` or similar as appropriate.
280
281```go
282bugsnag.Configure(bugsnag.Configuration{
283    ReleaseStage: "development",
284})
285```
286
287### NotifyReleaseStages
288
289The list of ReleaseStages to notify in. By default Bugsnag will notify you in all release stages, but
290you can use this to silence development errors.
291
292```go
293bugsnag.Configure(bugsnag.Configuration{
294    NotifyReleaseStages: []string{"production", "staging"},
295})
296```
297
298### AppVersion
299
300If you use a versioning scheme for deploys of your app, Bugsnag can use the `AppVersion` to only
301re-open errors if they occur in later version of the app.
302
303```go
304bugsnag.Configure(bugsnag.Configuration{
305    AppVersion: "1.2.3",
306})
307```
308
309### Hostname
310
311The hostname is used to track where exceptions are coming from in the Bugsnag dashboard. The
312default value is obtained from `os.Hostname()` so you won't often need to change this.
313
314```go
315bugsnag.Configure(bugsnag.Configuration{
316    Hostname: "go1",
317})
318```
319
320### ProjectPackages
321
322In order to determine where a crash happens Bugsnag needs to know which packages you consider to
323be part of your app (as opposed to a library). By default this is set to `[]string{"main*"}`. Strings
324are matched to package names using [`filepath.Match`](http://godoc.org/path/filepath#Match).
325
326```go
327bugsnag.Configure(bugsnag.Configuration{
328    ProjectPackages: []string{"main", "github.com/domain/myapp/*"},
329}
330```
331
332### ParamsFilters
333
334Sometimes sensitive data is accidentally included in Bugsnag MetaData. You can remove it by
335setting `ParamsFilters`. Any key in the `MetaData` that includes any string in the filters
336will be redacted. The default is `[]string{"password", "secret"}`, which prevents fields like
337`password`, `password_confirmation` and `secret_answer` from being sent.
338
339```go
340bugsnag.Configure(bugsnag.Configuration{
341    ParamsFilters: []string{"password", "secret"},
342}
343```
344
345### Logger
346
347The Logger to write to in case of an error inside Bugsnag. This defaults to the global logger.
348
349```go
350bugsnag.Configure(bugsnag.Configuration{
351    Logger: app.Logger,
352}
353```
354
355### PanicHandler
356
357The first time Bugsnag is configured, it wraps the running program in a panic
358handler using [panicwrap](http://godoc.org/github.com/ConradIrwin/panicwrap). This
359forks a sub-process which monitors unhandled panics. To prevent this, set
360`PanicHandler` to `func() {}` the first time you call
361`bugsnag.Configure`. This will prevent bugsnag from being able to notify you about
362unhandled panics.
363
364```go
365bugsnag.Configure(bugsnag.Configuration{
366    PanicHandler: func() {},
367})
368```
369
370### Synchronous
371
372Bugsnag usually starts a new goroutine before sending notifications. This means
373that notifications can be lost if you do a bugsnag.Notify and then immediately
374os.Exit. To avoid this problem, set Bugsnag to Synchronous (or just `panic()`
375instead ;).
376
377```go
378bugsnag.Configure(bugsnag.Configuration{
379    Synchronous: true
380})
381```
382
383Or just for one error:
384
385```go
386bugsnag.Notify(err, bugsnag.Configuration{Synchronous: true})
387```
388
389### Transport
390
391The transport configures how Bugsnag makes http requests. By default we use
392[`http.DefaultTransport`](http://godoc.org/net/http#RoundTripper) which handles
393HTTP proxies automatically using the `$HTTP_PROXY` environment variable.
394
395```go
396bugsnag.Configure(bugsnag.Configuration{
397    Transport: http.DefaultTransport,
398})
399```
400
401## Custom data with OnBeforeNotify
402
403While it's nice that you can pass `MetaData` directly into `bugsnag.Notify`,
404`bugsnag.AutoNotify`, and `bugsnag.Recover`, this can be a bit cumbersome and
405inefficient — you're constructing the meta-data whether or not it will actually
406be used.  A better idea is to pass raw data in to these functions, and add an
407`OnBeforeNotify` filter that converts them into `MetaData`.
408
409For example, lets say our system processes jobs:
410
411```go
412type Job struct{
413    Retry     bool
414    UserId    string
415    UserEmail string
416    Name      string
417    Params    map[string]string
418}
419```
420
421You can pass a job directly into Bugsnag.notify:
422
423```go
424bugsnag.Notify(err, job)
425```
426
427And then add a filter to extract information from that job and attach it to the
428Bugsnag event:
429
430```go
431bugsnag.OnBeforeNotify(
432    func(event *bugsnag.Event, config *bugsnag.Configuration) error {
433
434        // Search all the RawData for any *Job pointers that we're passed in
435        // to bugsnag.Notify() and friends.
436        for _, datum := range event.RawData {
437            if job, ok := datum.(*Job); ok {
438                // don't notify bugsnag about errors in retries
439                if job.Retry {
440                    return fmt.Errorf("not notifying about retried jobs")
441                }
442
443                // add the job as a tab on Bugsnag.com
444                event.MetaData.AddStruct("Job", job)
445
446                // set the user correctly
447                event.User = &User{Id: job.UserId, Email: job.UserEmail}
448            }
449        }
450
451        // continue notifying as normal
452        return nil
453    })
454```
455
456## Advanced Usage
457
458If you want to have multiple different configurations around in one program,
459you can use `bugsnag.New()` to create multiple independent instances of
460Bugsnag. You can use these without calling `bugsnag.Configure()`, but bear in
461mind that until you call `bugsnag.Configure()` unhandled panics will not be
462sent to bugsnag.
463
464```go
465notifier := bugsnag.New(bugsnag.Configuration{
466    APIKey: "YOUR_OTHER_API_KEY",
467})
468```
469
470In fact any place that lets you pass in `rawData` also allows you to pass in
471configuration.  For example to send http errors to one bugsnag project, you
472could do:
473
474```go
475bugsnag.Handler(nil, bugsnag.Configuration{APIKey: "YOUR_OTHER_API_KEY"})
476```
477
478### GroupingHash
479
480If you need to override Bugsnag's grouping algorithm, you can set the
481`GroupingHash` in an `OnBeforeNotify`:
482
483```go
484bugsnag.OnBeforeNotify(
485    func (event *bugsnag.Event, config *bugsnag.Configuration) error {
486        event.GroupingHash = calculateGroupingHash(event)
487        return nil
488    })
489```
490