forked from TykTechnologies/logrus-logstash-hook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logstash.go
145 lines (122 loc) · 4.57 KB
/
logstash.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package logrus_logstash
import (
"crypto/tls"
"net"
"strings"
"github.com/TykTechnologies/logrus"
"github.com/TykTechnologies/tyk/config"
)
// Hook represents a connection to a Logstash instance
type Hook struct {
conn net.Conn
appName string
alwaysSentFields logrus.Fields
hookOnlyPrefix string
}
// NewHook creates a new hook to a Logstash instance, which listens on
// `protocol`://`address`.
func NewHook(protocol, address, appName string) (*Hook, error) {
return NewHookWithFields(protocol, address, appName, make(logrus.Fields))
}
// NewHookWithConn creates a new hook to a Logstash instance, using the supplied connection
func NewHookWithConn(conn net.Conn, appName string) (*Hook, error) {
if config.Global().LogstashTLS {
WrapTLSClient(conn, config.Global().LogstashTLSSkipVerify)
}
return NewHookWithFieldsAndConn(conn, appName, make(logrus.Fields))
}
// NewHookWithFields creates a new hook to a Logstash instance, which listens on
// `protocol`://`address`. alwaysSentFields will be sent with every log entry.
func NewHookWithFields(protocol, address, appName string, alwaysSentFields logrus.Fields) (*Hook, error) {
return NewHookWithFieldsAndPrefix(protocol, address, appName, alwaysSentFields, "")
}
// NewHookWithFieldsAndPrefix creates a new hook to a Logstash instance, which listens on
// `protocol`://`address`. alwaysSentFields will be sent with every log entry. prefix is used to select fields to filter
func NewHookWithFieldsAndPrefix(protocol, address, appName string, alwaysSentFields logrus.Fields, prefix string) (*Hook, error) {
conn, err := net.Dial(protocol, address)
if err != nil {
return nil, err
}
if config.Global().LogstashTLS {
WrapTLSClient(conn, config.Global().LogstashTLSSkipVerify)
}
return NewHookWithFieldsAndConnAndPrefix(conn, appName, alwaysSentFields, prefix)
}
// wraps the existing connection in tls
func WrapTLSClient(conn net.Conn, insecureSkipVerify bool) net.Conn {
conf := &tls.Config{
InsecureSkipVerify: insecureSkipVerify,
}
return tls.Client(conn, conf)
}
// NewHookWithFieldsAndConn creates a new hook to a Logstash instance using the supplied connection
func NewHookWithFieldsAndConn(conn net.Conn, appName string, alwaysSentFields logrus.Fields) (*Hook, error) {
return NewHookWithFieldsAndConnAndPrefix(conn, appName, alwaysSentFields, "")
}
//NewHookWithFieldsAndConnAndPrefix creates a new hook to a Logstash instance using the suppolied connection and prefix
func NewHookWithFieldsAndConnAndPrefix(conn net.Conn, appName string, alwaysSentFields logrus.Fields, prefix string) (*Hook, error) {
return &Hook{conn: conn, appName: appName, alwaysSentFields: alwaysSentFields, hookOnlyPrefix: prefix}, nil
}
//NewFilterHook makes a new hook which does not forward to logstash, but simply enforces the prefix rules
func NewFilterHook() *Hook {
return NewFilterHookWithPrefix("")
}
//NewFilterHookWithPrefix make a new hook which does not forward to logstash, but simply enforces the specified prefix
func NewFilterHookWithPrefix(prefix string) *Hook {
return &Hook{conn: nil, appName: "", alwaysSentFields: make(logrus.Fields), hookOnlyPrefix: prefix}
}
func (h *Hook) filterHookOnly(entry *logrus.Entry) {
if h.hookOnlyPrefix != "" {
for key := range entry.Data {
if strings.HasPrefix(key, h.hookOnlyPrefix) {
delete(entry.Data, key)
}
}
}
}
//WithPrefix sets a prefix filter to use in all subsequent logging
func (h *Hook) WithPrefix(prefix string) {
h.hookOnlyPrefix = prefix
}
func (h *Hook) WithField(key string, value interface{}) {
h.alwaysSentFields[key] = value
}
func (h *Hook) WithFields(fields logrus.Fields) {
//Add all the new fields to the 'alwaysSentFields', possibly overwriting exising fields
for key, value := range fields {
h.alwaysSentFields[key] = value
}
}
func (h *Hook) Fire(entry *logrus.Entry) error {
//make sure we always clear the hookonly fields from the entry
defer h.filterHookOnly(entry)
// Add in the alwaysSentFields. We don't override fields that are already set.
for k, v := range h.alwaysSentFields {
if _, inMap := entry.Data[k]; !inMap {
entry.Data[k] = v
}
}
//For a filteringHook, stop here
if h.conn == nil {
return nil
}
formatter := LogstashFormatter{Type: h.appName}
dataBytes, err := formatter.FormatWithPrefix(entry, h.hookOnlyPrefix)
if err != nil {
return err
}
if _, err = h.conn.Write(dataBytes); err != nil {
return err
}
return nil
}
func (h *Hook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
logrus.WarnLevel,
logrus.InfoLevel,
logrus.DebugLevel,
}
}