1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
package trace
import (
"encoding/json"
"net"
"time"
"github.com/gravitational/trace/internal"
"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 cursor := findFrame(); cursor != nil {
t := internal.GetTracesFromCursor(*cursor)
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,
}
}
|