forked from mirror/logrus
Move airbrake to dedicated repo(s)
The current implementation is using an old implementation of the Airbrake v2 api. Airbrake has release v2 since, but this package is necessary for in-house solutions like errbit. The number of errbit users don't justify to continue pushing this version as the official. That's why the official hook is now using gobrake (the official package), and the one coming from logrus is now named "legacy".
This commit is contained in:
parent
fe72f59ae7
commit
297ec6fcaa
16
README.md
16
README.md
|
@ -75,17 +75,13 @@ package main
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
"github.com/gemnasium/logrus-airbrake-hook"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Log as JSON instead of the default ASCII formatter.
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
log.SetFormatter(&log.JSONFormatter{})
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
|
||||||
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
|
||||||
|
|
||||||
// Output to stderr instead of stdout, could also be a file.
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
@ -182,13 +178,16 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||||
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||||
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -202,7 +201,8 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||||
|
|
||||||
| Hook | Description |
|
| Hook | Description |
|
||||||
| ----- | ----------- |
|
| ----- | ----------- |
|
||||||
| [Airbrake](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go) | Send errors to an exception tracking service compatible with the Airbrake API. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||||
|
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
|
| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
|
||||||
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
package airbrake
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/tobi/airbrake-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
|
||||||
// with the Airbrake API.
|
|
||||||
type airbrakeHook struct {
|
|
||||||
APIKey string
|
|
||||||
Endpoint string
|
|
||||||
Environment string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHook(endpoint, apiKey, env string) *airbrakeHook {
|
|
||||||
return &airbrakeHook{
|
|
||||||
APIKey: apiKey,
|
|
||||||
Endpoint: endpoint,
|
|
||||||
Environment: env,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
airbrake.ApiKey = hook.APIKey
|
|
||||||
airbrake.Endpoint = hook.Endpoint
|
|
||||||
airbrake.Environment = hook.Environment
|
|
||||||
|
|
||||||
var notifyErr error
|
|
||||||
err, ok := entry.Data["error"].(error)
|
|
||||||
if ok {
|
|
||||||
notifyErr = err
|
|
||||||
} else {
|
|
||||||
notifyErr = errors.New(entry.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
airErr := airbrake.Notify(notifyErr)
|
|
||||||
if airErr != nil {
|
|
||||||
return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hook *airbrakeHook) Levels() []logrus.Level {
|
|
||||||
return []logrus.Level{
|
|
||||||
logrus.ErrorLevel,
|
|
||||||
logrus.FatalLevel,
|
|
||||||
logrus.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package airbrake
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/xml"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
type notice struct {
|
|
||||||
Error NoticeError `xml:"error"`
|
|
||||||
}
|
|
||||||
type NoticeError struct {
|
|
||||||
Class string `xml:"class"`
|
|
||||||
Message string `xml:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type customErr struct {
|
|
||||||
msg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *customErr) Error() string {
|
|
||||||
return e.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
testAPIKey = "abcxyz"
|
|
||||||
testEnv = "development"
|
|
||||||
expectedClass = "*airbrake.customErr"
|
|
||||||
expectedMsg = "foo"
|
|
||||||
unintendedMsg = "Airbrake will not see this string"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
noticeError = make(chan NoticeError, 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestLogEntryMessageReceived checks if invoking Logrus' log.Error
|
|
||||||
// method causes an XML payload containing the log entry message is received
|
|
||||||
// by a HTTP server emulating an Airbrake-compatible endpoint.
|
|
||||||
func TestLogEntryMessageReceived(t *testing.T) {
|
|
||||||
log := logrus.New()
|
|
||||||
ts := startAirbrakeServer(t)
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
hook := NewHook(ts.URL, testAPIKey, "production")
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
|
|
||||||
log.Error(expectedMsg)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case received := <-noticeError:
|
|
||||||
if received.Message != expectedMsg {
|
|
||||||
t.Errorf("Unexpected message received: %s", received.Message)
|
|
||||||
}
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("Timed out; no notice received by Airbrake API")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestLogEntryMessageReceived confirms that, when passing an error type using
|
|
||||||
// logrus.Fields, a HTTP server emulating an Airbrake endpoint receives the
|
|
||||||
// error message returned by the Error() method on the error interface
|
|
||||||
// rather than the logrus.Entry.Message string.
|
|
||||||
func TestLogEntryWithErrorReceived(t *testing.T) {
|
|
||||||
log := logrus.New()
|
|
||||||
ts := startAirbrakeServer(t)
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
hook := NewHook(ts.URL, testAPIKey, "production")
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"error": &customErr{expectedMsg},
|
|
||||||
}).Error(unintendedMsg)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case received := <-noticeError:
|
|
||||||
if received.Message != expectedMsg {
|
|
||||||
t.Errorf("Unexpected message received: %s", received.Message)
|
|
||||||
}
|
|
||||||
if received.Class != expectedClass {
|
|
||||||
t.Errorf("Unexpected error class: %s", received.Class)
|
|
||||||
}
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("Timed out; no notice received by Airbrake API")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestLogEntryWithNonErrorTypeNotReceived confirms that, when passing a
|
|
||||||
// non-error type using logrus.Fields, a HTTP server emulating an Airbrake
|
|
||||||
// endpoint receives the logrus.Entry.Message string.
|
|
||||||
//
|
|
||||||
// Only error types are supported when setting the 'error' field using
|
|
||||||
// logrus.WithFields().
|
|
||||||
func TestLogEntryWithNonErrorTypeNotReceived(t *testing.T) {
|
|
||||||
log := logrus.New()
|
|
||||||
ts := startAirbrakeServer(t)
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
hook := NewHook(ts.URL, testAPIKey, "production")
|
|
||||||
log.Hooks.Add(hook)
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"error": expectedMsg,
|
|
||||||
}).Error(unintendedMsg)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case received := <-noticeError:
|
|
||||||
if received.Message != unintendedMsg {
|
|
||||||
t.Errorf("Unexpected message received: %s", received.Message)
|
|
||||||
}
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
t.Error("Timed out; no notice received by Airbrake API")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func startAirbrakeServer(t *testing.T) *httptest.Server {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var notice notice
|
|
||||||
if err := xml.NewDecoder(r.Body).Decode(¬ice); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
r.Body.Close()
|
|
||||||
|
|
||||||
noticeError <- notice.Error
|
|
||||||
}))
|
|
||||||
|
|
||||||
return ts
|
|
||||||
}
|
|
Loading…
Reference in New Issue