diff --git a/logging/init.go b/logging/init.go index 3bc927d..b1e8ebd 100644 --- a/logging/init.go +++ b/logging/init.go @@ -1,7 +1,6 @@ package logging import ( - "io" "os" "time" @@ -24,9 +23,7 @@ func Initialize() { cw := zerolog.NewConsoleWriter() cw.Out = os.Stderr cw.TimeFormat = "15:04:05" - sw := NewSentryWriter() - w := io.MultiWriter(cw, sw) - log.Logger = zerolog.New(w).With().Timestamp().Logger() + log.Logger = zerolog.New(cw).With().Timestamp().Logger() zerolog.DurationFieldUnit = time.Millisecond } diff --git a/logging/sentry.go b/logging/sentry.go deleted file mode 100644 index 3a204e8..0000000 --- a/logging/sentry.go +++ /dev/null @@ -1,144 +0,0 @@ -package logging - -import ( - "io" - "time" - "unsafe" - - "github.com/buger/jsonparser" - "github.com/getsentry/sentry-go" - "github.com/rs/zerolog" -) - -var levelMapping = map[zerolog.Level]sentry.Level{ - zerolog.DebugLevel: sentry.LevelDebug, - zerolog.InfoLevel: sentry.LevelInfo, - zerolog.WarnLevel: sentry.LevelWarning, - zerolog.ErrorLevel: sentry.LevelError, - zerolog.FatalLevel: sentry.LevelFatal, - zerolog.PanicLevel: sentry.LevelFatal, -} - -var now = time.Now -var _ = io.WriteCloser(new(SentryWriter)) - -type SentryWriter struct { - hub *sentry.Hub - levels map[zerolog.Level]struct{} -} - -func NewSentryWriter() *SentryWriter { - lvls := []zerolog.Level{ - zerolog.ErrorLevel, - zerolog.FatalLevel, - zerolog.PanicLevel, - } - levels := make(map[zerolog.Level]struct{}, len(lvls)) - for _, lvl := range lvls { - levels[lvl] = struct{}{} - } - - return &SentryWriter{ - hub: sentry.CurrentHub(), - levels: levels, - } -} - -func (p *SentryWriter) Write(data []byte) (int, error) { - event, ok := p.parseLogEvent(data) - if ok { - p.hub.CaptureEvent(event) - } - - return len(data), nil -} - -func (p *SentryWriter) Close() error { - return nil -} - -func (p *SentryWriter) parseLogEvent(data []byte) (*sentry.Event, bool) { - const logger = "zerolog" - - lvlStr, err := jsonparser.GetUnsafeString(data, zerolog.LevelFieldName) - if err != nil { - return nil, false - } - - lvl, err := zerolog.ParseLevel(lvlStr) - if err != nil { - return nil, false - } - - _, enabled := p.levels[lvl] - if !enabled { - return nil, false - } - - sentryLvl, ok := levelsMapping[lvl] - if !ok { - return nil, false - } - - event := sentry.Event{ - Timestamp: now(), - Level: sentryLvl, - Logger: logger, - } - - err = jsonparser.ObjectEach(data, func(key, value []byte, vt jsonparser.ValueType, offset int) error { - switch string(key) { - case zerolog.MessageFieldName: - event.Message = bytesToStrUnsafe(value) - - case zerolog.ErrorFieldName: - event.Exception = append(event.Exception, sentry.Exception{ - Value: bytesToStrUnsafe(value), - Stacktrace: newStacktrace(), - }) - } - - return nil - }) - - if err != nil { - return nil, false - } - - return &event, true -} - -func newStacktrace() *sentry.Stacktrace { - const ( - currentModule = "git.joco.dk/joco/geck-go" - zerologModule = "github.com/rs/zerolog" - ) - - st := sentry.NewStacktrace() - - threshold := len(st.Frames) - 1 - for ; threshold > 0 && st.Frames[threshold].Module == currentModule; threshold-- { - } - -outer: - for i := threshold; i > 0; i-- { - if st.Frames[i].Module == zerologModule { - for j := i - 1; j >= 0; j-- { - if st.Frames[j].Module != zerologModule { - threshold = j - break outer - } - } - - break - } - } - - st.Frames = st.Frames[:threshold+1] - - return st -} - -func bytesToStrUnsafe(data []byte) string { - return *(*string)(unsafe.Pointer(&data)) -} diff --git a/logging/sentry_test.go b/logging/sentry_test.go deleted file mode 100644 index 0ad6147..0000000 --- a/logging/sentry_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package logging - -import ( - "testing" - "time" - - "github.com/getsentry/sentry-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var logEventJSON = []byte(`{"level":"error","requestId":"bee07485-2485-4f64-99e1-d10165884ca7","error":"dial timeout","time":"2020-06-25T17:19:00+03:00","message":"test message"}`) - -// TestParseLogEvent asserts that the log event is forwarded from ZeroLog to Sentry. -func TestParseLogEvent(t *testing.T) { - ts := time.Now() - - now = func() time.Time { return ts } - - w := NewSentryWriter() - - ev, ok := w.parseLogEvent(logEventJSON) - require.True(t, ok) - - assert.Equal(t, ts, ev.Timestamp) - assert.Equal(t, sentry.LevelError, ev.Level) - assert.Equal(t, "zerolog", ev.Logger) - assert.Equal(t, "test message", ev.Message) - - require.Len(t, ev.Exception, 1) - assert.Equal(t, "dial timeout", ev.Exception[0].Value) -} - -// BenchmarkParseLogEvent checks the performance of the event log parser. -func BenchmarkParseLogEvent(b *testing.B) { - w := NewSentryWriter() - - for i := 0; i < b.N; i++ { - w.parseLogEvent(logEventJSON) - } -}