Skip to content

Instantly share code, notes, and snippets.

@devishot
Last active December 7, 2017 09:51
Show Gist options
  • Save devishot/c0e0813a2cc2370ed476cd757dc5e6b4 to your computer and use it in GitHub Desktop.
Save devishot/c0e0813a2cc2370ed476cd757dc5e6b4 to your computer and use it in GitHub Desktop.
Gelf with log15 UPD: use go-gelf.v2 by Graylog2
package gelflog15
import (
"os"
"strconv"
"strings"
"gopkg.in/inconshreveable/log15.v2"
"gopkg.in/Graylog2/go-gelf.v2/gelf"
)
// Handler sends logs to Graylog in GELF.
type Handler struct {
writer gelf.Writer
host string
facility string
}
// New creates a log15 handler that emits GELF to addr. It is already wrapped
// in log15's LazyHandler and SyncHandler helpers. Its error is non-nil if there
// is a problem creating the GELF writer or determining our hostname.
func New(addr string, facility string) (log15.Handler, error) {
w, err := gelf.NewUDPWriter(addr)
if err != nil {
return nil, err
}
host, err := os.Hostname()
if err != nil {
return nil, err
}
return log15.CallerFileHandler(log15.LazyHandler(log15.SyncHandler(Handler{
writer: w,
host: host,
facility: facility,
}))), nil
}
// Log forwards a log message to the specified receiever.
func (h Handler) Log(r *log15.Record) error {
short, full := shortAndFull(r.Msg)
ctx := ctxToMap(r.Ctx)
callerFile, callerLine := caller(ctx)
delete(ctx, "_caller")
ctx["_file"] = callerFile
ctx["_line"] = callerLine
m := &gelf.Message{
Version: "1.1",
Host: h.host,
Short: short,
Full: full,
TimeUnix: float64(r.Time.Unix()),
Level: log15LevelsToSyslog[r.Lvl],
Facility: h.facility,
Extra: ctx,
}
return h.writer.WriteMessage(m)
}
func ctxToMap(ctx []interface{}) map[string]interface{} {
m := make(map[string]interface{}, len(ctx)/2)
for i := 0; i < len(ctx); i += 2 {
s := ctx[i].(string)
m["_" + s] = ctx[i+1]
}
return m
}
func shortAndFull(msg string) (short, full string) {
lines := strings.SplitN(msg, "\n", 2)
short = lines[0]
if len(lines) > 1 {
full = msg
}
return
}
// caller searches a context list for an entry called "caller" and splits it into
// filename and line number.
func caller(ctx map[string]interface{}) (string, int) {
info, present := ctx["_caller"]
if !present {
return "", 0
}
parts := strings.Split(info.(string), ":")
line, _ := strconv.Atoi(parts[1])
return parts[0], line
}
// source: http://www.cisco.com/c/en/us/td/docs/security/asa/syslog-guide/syslogs/logsevp.html
var log15LevelsToSyslog = map[log15.Lvl]int32{
log15.LvlCrit: 2,
log15.LvlError: 3,
log15.LvlWarn: 4,
log15.LvlInfo: 6,
log15.LvlDebug: 7,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment