Skip to content

Commit 4034fb1

Browse files
authored
Add error handler for Sentry error (#78)
1 parent b7e4b43 commit 4034fb1

File tree

2 files changed

+61
-8
lines changed

2 files changed

+61
-8
lines changed

sentry.go

+21-8
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ type SentryHook struct {
4141
client *raven.Client
4242
levels []logrus.Level
4343

44-
serverName string
45-
ignoreFields map[string]struct{}
46-
extraFilters map[string]func(interface{}) interface{}
44+
serverName string
45+
ignoreFields map[string]struct{}
46+
extraFilters map[string]func(interface{}) interface{}
47+
errorHandlers []func(entry *logrus.Entry, err error)
4748

4849
asynchronous bool
4950

@@ -244,23 +245,30 @@ func (hook *SentryHook) Fire(entry *logrus.Entry) error {
244245

245246
_, errCh := hook.client.Capture(packet, nil)
246247

247-
if hook.asynchronous {
248+
switch {
249+
case hook.asynchronous:
248250
// Our use of hook.mu guarantees that we are following the WaitGroup rule of
249251
// not calling Add in parallel with Wait.
250252
hook.wg.Add(1)
251253
go func() {
252254
if err := <-errCh; err != nil {
253-
fmt.Println(err)
255+
for _, handlerFn := range hook.errorHandlers {
256+
handlerFn(entry, err)
257+
}
258+
hook.wg.Done()
254259
}
255-
hook.wg.Done()
256260
}()
257261
return nil
258-
} else if timeout := hook.Timeout; timeout == 0 {
262+
case hook.Timeout == 0:
259263
return nil
260-
} else {
264+
default:
265+
timeout := hook.Timeout
261266
timeoutCh := time.After(timeout)
262267
select {
263268
case err := <-errCh:
269+
for _, handlerFn := range hook.errorHandlers {
270+
handlerFn(entry, err)
271+
}
264272
return err
265273
case <-timeoutCh:
266274
return fmt.Errorf("no response from sentry server in %s", timeout)
@@ -342,6 +350,11 @@ func (hook *SentryHook) AddExtraFilter(name string, fn func(interface{}) interfa
342350
hook.extraFilters[name] = fn
343351
}
344352

353+
// AddErrorHandler adds a error handler function used when Sentry returns error.
354+
func (hook *SentryHook) AddErrorHandler(fn func(entry *logrus.Entry, err error)) {
355+
hook.errorHandlers = append(hook.errorHandlers, fn)
356+
}
357+
345358
func (hook *SentryHook) formatExtraData(df *dataField) (result map[string]interface{}) {
346359
// create a map for passing to Sentry's extra data
347360
result = make(map[string]interface{}, df.len())

sentry_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/getsentry/raven-go"
1919
pkgerrors "github.com/pkg/errors"
2020
"github.com/sirupsen/logrus"
21+
"github.com/stretchr/testify/assert"
2122
)
2223

2324
const (
@@ -413,3 +414,42 @@ func TestConvertStackTrace(t *testing.T) {
413414
t.Error("stack traces differ")
414415
}
415416
}
417+
418+
func TestErrorHandler(t *testing.T) {
419+
a := assert.New(t)
420+
421+
s, dsn := httptestNewServer(func(rw http.ResponseWriter, req *http.Request) {
422+
defer req.Body.Close()
423+
rw.WriteHeader(400)
424+
})
425+
defer s.Close()
426+
427+
hook, err := NewSentryHook(dsn, []logrus.Level{
428+
logrus.ErrorLevel,
429+
})
430+
a.NoError(err, "NewSentryHook should be no error")
431+
432+
logger := getTestLogger()
433+
logger.Hooks.Add(hook)
434+
435+
hook.AddErrorHandler(func(e *logrus.Entry, err error) {
436+
a.Error(err, "ErrorHandler should capture error")
437+
a.Contains(err.Error(), "raven: got http status 400")
438+
})
439+
440+
err = hook.Fire(&logrus.Entry{})
441+
a.Error(err, "hook.Fire should have error")
442+
}
443+
444+
// create http test server
445+
func httptestNewServer(handler func(http.ResponseWriter, *http.Request)) (server *httptest.Server, dsn string) {
446+
server = httptest.NewServer(http.HandlerFunc(handler))
447+
448+
fragments := strings.SplitN(server.URL, "://", 2)
449+
dsn = fmt.Sprintf(
450+
"%s://public:secret@%s/sentry/project-id",
451+
fragments[0],
452+
fragments[1],
453+
)
454+
return server, dsn
455+
}

0 commit comments

Comments
 (0)