Skip to content
Snippets Groups Projects
Commit e3263107bd44 authored by Christophe de Vienne's avatar Christophe de Vienne
Browse files

Add sentry logger

parent 36b138158c43
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
require ( require (
github.com/getsentry/sentry-go v0.7.0 github.com/getsentry/sentry-go v0.7.0
github.com/json-iterator/go v1.1.6
github.com/orus-io/go-flags v1.4.0
github.com/rs/zerolog v1.19.0 github.com/rs/zerolog v1.19.0
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
...@@ -84,4 +85,5 @@ ...@@ -84,4 +85,5 @@
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
...@@ -87,4 +89,5 @@ ...@@ -87,4 +89,5 @@
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
...@@ -93,6 +96,8 @@ ...@@ -93,6 +96,8 @@
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/orus-io/go-flags v1.4.0 h1:eDbrM1iRPkT68HUJibvtli/xhXSst5FOj7EGTEOeeCA=
github.com/orus-io/go-flags v1.4.0/go.mod h1:DZNFUSWKy2JbxIQeDVY6onal2VQbdL9ug5ODZfawylw=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
......
...@@ -39,6 +39,12 @@ ...@@ -39,6 +39,12 @@
*o.log = o.log.Output(out) *o.log = o.log.Output(out)
} }
// AddLogWrapper adds a log wrapper to the stack
func (o *LoggingOptions) AddLogWrapper(wrapper func(io.Writer) io.Writer) {
o.logWrappers = append(o.logWrappers, wrapper)
o.resetOutput()
}
// SetMinLoggingLevel makes sure the logging level is not under a given value // SetMinLoggingLevel makes sure the logging level is not under a given value
func (o *LoggingOptions) SetMinLoggingLevel(level zerolog.Level) { func (o *LoggingOptions) SetMinLoggingLevel(level zerolog.Level) {
if level < o.log.GetLevel() { if level < o.log.GetLevel() {
......
sentry.go 0 → 100644
package orusapi
import (
"bytes"
"io"
"time"
"github.com/getsentry/sentry-go"
jsoniter "github.com/json-iterator/go"
"github.com/rs/zerolog/log"
)
// SentryOptions ...
type SentryOptions struct {
SentryDSN func(string) `long:"dsn" env:"DSN" ini-name:"dsn" description:"Sentry DSN"`
client *sentry.Client
hub *sentry.Hub
}
// GetClient returns the sentry client
func (o SentryOptions) GetClient() *sentry.Client {
return o.client
}
// GetHub returns the sentry hub
func (o SentryOptions) GetHub() *sentry.Hub {
return o.hub
}
// SentryLogger ...
type SentryLogger struct {
hub *sentry.Hub
next io.Writer
}
var (
levelMarker = []byte(`"level":"`)
levelMarkerLen = len(levelMarker)
levelsFirstLetter = []byte(`wefp`)
)
func buildEventIfLevelGtWarn(p []byte) *sentry.Event {
if i := bytes.Index(p, levelMarker); i != -1 {
first := p[i+levelMarkerLen]
if bytes.IndexByte(levelsFirstLetter, first) != -1 {
return buildEvent(p)
}
}
return nil
}
func buildEvent(p []byte) *sentry.Event {
iter := jsoniter.ConfigFastest.BorrowIterator(p)
defer jsoniter.ConfigFastest.ReturnIterator(iter)
if iter.WhatIsNext() != jsoniter.ObjectValue {
return nil
}
event := sentry.NewEvent()
if !iter.ReadObjectCB(func(iter *jsoniter.Iterator, field string) bool {
switch field {
case "message":
event.Message = iter.ReadString()
case "error":
errMsg := iter.ReadString()
if event.Message == "" {
event.Message = errMsg
}
event.Extra["error"] = errMsg
case "level":
level := iter.ReadString()
if level == "warn" {
event.Level = sentry.LevelWarning
} else {
event.Level = sentry.Level(level)
}
case "request":
iter.ReadVal(&event.Request)
case "user":
if !iter.ReadObjectCB(func(iter *jsoniter.Iterator, field string) bool {
switch field {
case "id":
event.User.ID = iter.ReadString()
default:
event.Extra["user."+field] = iter.Read()
}
return true
}) {
return false
}
case "exception":
var e sentry.Exception
iter.ReadVal(&e)
event.Exception = []sentry.Exception{e}
default:
event.Extra[field] = iter.Read()
}
return true
}) {
return nil
}
if op, ok := event.Extra["api-operation-id"]; ok {
tag, _ := event.Extra["api-tag"].(string)
event.Message = tag + "/" + op.(string) + ": " + event.Message
} else if event.Request != nil && event.Request.Method != "" {
event.Message = event.Request.Method + " " + event.Request.URL + ": " + event.Message
}
return event
}
// Write ...
func (l SentryLogger) Write(p []byte) (n int, err error) {
if event := buildEventIfLevelGtWarn(p); event != nil {
l.hub.CaptureEvent(event)
}
return l.next.Write(p)
}
// Setup ...
func (o *SentryOptions) Setup(loggingOptions *LoggingOptions, environment *string) {
o.SentryDSN = func(dsn string) {
client, err := sentry.NewClient(sentry.ClientOptions{
Environment: *environment,
Dsn: dsn,
})
if err != nil {
log.Err(err).Msg("Could not initialize sentry")
return
}
o.client = client
o.hub = sentry.NewHub(client, sentry.NewScope())
loggingOptions.AddLogWrapper(func(next io.Writer) io.Writer {
return SentryLogger{o.hub, next}
})
}
}
// Shutdown ...
func (o SentryOptions) Shutdown() {
if o.hub != nil {
o.hub.Flush(time.Second)
o.hub = nil
o.client = nil
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment