Skip to content

Instantly share code, notes, and snippets.

@aybabtme
Created December 26, 2014 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aybabtme/9813b3100c5837c15752 to your computer and use it in GitHub Desktop.
Save aybabtme/9813b3100c5837c15752 to your computer and use it in GitHub Desktop.
// LogHook builds a func that can be fired by a doge/log through
// log.AddHook. If the entry it fires on contains an error, it will
// include a stacktrace of the logger's callsite.
//
// import "doge/log"
//
// log.AddHook(
// sentry.LogHook("my.pkg/name"),
// log.Lerror, log.Lpanic, log.Lfatal,
// )
//
func LogHook(packageRootPrefix string) func(entry *log.Entry) error {
return func(entry *log.Entry) error {
var ifaces []raven.Interface
var msg string
if err, ok := extractError(entry); ok {
msg = fmt.Sprintf("%s: %v", entry.Message, err)
skipStack := 6 // skip logger frames
contextAroundLOC := 5 // LOC above, bellow
stackTrace := raven.NewStacktrace(skipStack, contextAroundLOC, []string{
"doge/",
packageRootPrefix,
})
ifaces = append(ifaces, raven.NewException(err, stackTrace))
} else {
msg = entry.Message
}
tags := make(Tags)
for k, v := range entry.Data {
// err/error were extracted
if k == "err" || k == "error" {
continue
}
// raven has a special Interface type for *http.Requests
if req, ok := v.(*http.Request); ok {
ifaces = append(ifaces, raven.NewHttp(req))
continue
}
tags[k] = fmt.Sprintf("%v", v)
}
packet := raven.NewPacket(
msg,
ifaces...,
)
packet.Timestamp = raven.Timestamp(entry.Time)
packet.Level = extractSeverity(entry.Level)
_, errc := Client.Capture(packet, tags)
return <-errc
}
}
func extractSeverity(l logrus.Level) raven.Severity {
switch l {
case log.Lpanic:
return raven.Severity("panic")
case log.Lfatal:
return raven.FATAL
case log.Lerror:
return raven.ERROR
case log.Lwarn:
return raven.WARNING
case log.Linfo:
return raven.INFO
case log.Ldebug:
return raven.DEBUG
default:
return raven.Severity(fmt.Sprintf("unspecified (%d)", l))
}
}
func extractError(entry *log.Entry) (error, bool) {
shortErr, sok := entry.Data["err"]
longErr, lok := entry.Data["error"]
switch {
case sok && !lok:
return makeError(shortErr), true
case !sok && lok:
return makeError(longErr), true
case sok && lok:
return fmt.Errorf("two error fields set, err=%v, error=%v", shortErr, longErr), true
default:
return nil, false
}
}
func makeError(ierr interface{}) error {
switch e := ierr.(type) {
case error:
return e
default:
return fmt.Errorf("%v", e)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment