112 lines
2.4 KiB
Go
112 lines
2.4 KiB
Go
package trace
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/jonboulle/clockwork"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
// UDPDefaultAddr is a default address to emit logs to
|
|
UDPDefaultAddr = "127.0.0.1:5000"
|
|
// UDPDefaultNet is a default network
|
|
UDPDefaultNet = "udp"
|
|
)
|
|
|
|
// UDPOptionSetter represents functional arguments passed to ELKHook
|
|
type UDPOptionSetter func(f *UDPHook)
|
|
|
|
// NewUDPHook returns logrus-compatible hook that sends data to UDP socket
|
|
func NewUDPHook(opts ...UDPOptionSetter) (*UDPHook, error) {
|
|
f := &UDPHook{}
|
|
for _, o := range opts {
|
|
o(f)
|
|
}
|
|
if f.Clock == nil {
|
|
f.Clock = clockwork.NewRealClock()
|
|
}
|
|
if f.clientNet == "" {
|
|
f.clientNet = UDPDefaultNet
|
|
}
|
|
if f.clientAddr == "" {
|
|
f.clientAddr = UDPDefaultAddr
|
|
}
|
|
addr, err := net.ResolveUDPAddr(f.clientNet, f.clientAddr)
|
|
if err != nil {
|
|
return nil, Wrap(err)
|
|
}
|
|
conn, err := net.ListenPacket("udp", ":0")
|
|
if err != nil {
|
|
return nil, Wrap(err)
|
|
}
|
|
f.addr = addr
|
|
f.conn = conn.(*net.UDPConn)
|
|
return f, nil
|
|
}
|
|
|
|
type UDPHook struct {
|
|
Clock clockwork.Clock
|
|
clientNet string
|
|
clientAddr string
|
|
addr *net.UDPAddr
|
|
conn *net.UDPConn
|
|
}
|
|
|
|
type Frame struct {
|
|
Time time.Time `json:"time"`
|
|
Type string `json:"type"`
|
|
Entry map[string]interface{} `json:"entry"`
|
|
Message string `json:"message"`
|
|
Level string `json:"level"`
|
|
}
|
|
|
|
// Fire fires the event to the ELK beat
|
|
func (elk *UDPHook) Fire(e *log.Entry) error {
|
|
// Make a copy to safely modify
|
|
entry := e.WithFields(nil)
|
|
if frameNo := findFrame(); frameNo != -1 {
|
|
t := newTrace(frameNo-1, nil)
|
|
entry.Data[FileField] = t.String()
|
|
entry.Data[FunctionField] = t.Func()
|
|
}
|
|
data, err := json.Marshal(Frame{
|
|
Time: elk.Clock.Now().UTC(),
|
|
Type: "trace",
|
|
Entry: entry.Data,
|
|
Message: entry.Message,
|
|
Level: entry.Level.String(),
|
|
})
|
|
if err != nil {
|
|
return Wrap(err)
|
|
}
|
|
|
|
conn, err := net.ListenPacket("udp", ":0")
|
|
if err != nil {
|
|
return Wrap(err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
resolvedAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5000")
|
|
if err != nil {
|
|
return Wrap(err)
|
|
}
|
|
|
|
_, err = (conn.(*net.UDPConn)).WriteToUDP(data, resolvedAddr)
|
|
return Wrap(err)
|
|
|
|
}
|
|
|
|
// Levels returns logging levels supported by logrus
|
|
func (elk *UDPHook) Levels() []log.Level {
|
|
return []log.Level{
|
|
log.PanicLevel,
|
|
log.FatalLevel,
|
|
log.ErrorLevel,
|
|
log.WarnLevel,
|
|
log.InfoLevel,
|
|
log.DebugLevel,
|
|
}
|
|
}
|