-
Notifications
You must be signed in to change notification settings - Fork 2
/
nats_logrus_hook.go
110 lines (90 loc) · 2.63 KB
/
nats_logrus_hook.go
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
package nhook
import (
"errors"
"fmt"
"github.com/nats-io/go-nats"
"github.com/sirupsen/logrus"
)
// HookConf defines the vars needed to connect to nats and add the logrus hook
type HookConf struct {
NatsConfig
Subject string `json:"subject"`
Dimensions map[string]interface{} `json:"dimensions"`
}
// NatsHook will emit logs to the subject provided
type NatsHook struct {
conn *nats.Conn
subject string
extraFields map[string]interface{}
dynamicFields map[string]func() interface{}
Formatter logrus.Formatter
LogLevels []logrus.Level
}
// AddNatsHook will connect to nats, add the hook to logrus, and percolate any errors up
func AddNatsHook(conf *HookConf) (*nats.Conn, *NatsHook, error) {
if conf.Subject == "" {
return nil, nil, errors.New("Must provide a subject for the nats hook")
}
nc, err := ConnectToNats(&conf.NatsConfig)
if err != nil {
return nil, nil, err
}
hook := NewNatsHook(nc, conf.Subject)
for k, v := range conf.Dimensions {
hook.AddField(k, v)
}
logrus.AddHook(hook)
return nc, hook, nil
}
// NewNatsHook will create a logrus hook that will automatically send
// new info into the channel
func NewNatsHook(conn *nats.Conn, subject string) *NatsHook {
hook := NatsHook{
conn: conn,
subject: subject,
extraFields: make(map[string]interface{}),
dynamicFields: make(map[string]func() interface{}),
Formatter: &logrus.JSONFormatter{},
LogLevels: []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
logrus.WarnLevel,
logrus.InfoLevel,
logrus.DebugLevel,
},
}
return &hook
}
// AddField will add a simple value each emission
func (hook *NatsHook) AddField(key string, value interface{}) *NatsHook {
hook.extraFields[key] = value
return hook
}
// AddDynamicField will call that method on each fire
func (hook *NatsHook) AddDynamicField(key string, generator func() interface{}) *NatsHook {
hook.dynamicFields[key] = generator
return hook
}
// Fire will use the connection and try to send the message to the right destination
func (hook *NatsHook) Fire(entry *logrus.Entry) error {
if hook.conn.IsClosed() {
return fmt.Errorf("Attempted to log on a closed connection")
}
// add in the new fields
for k, v := range hook.extraFields {
entry.Data[k] = v
}
for k, generator := range hook.dynamicFields {
entry.Data[k] = generator()
}
bytes, err := hook.Formatter.Format(entry)
if err != nil {
return err
}
return hook.conn.Publish(hook.subject, bytes)
}
// Levels will describe what levels the NatsHook is associated with
func (hook *NatsHook) Levels() []logrus.Level {
return hook.LogLevels
}