forked from bluele/logrus_slack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
slack.go
172 lines (144 loc) · 3.91 KB
/
slack.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
Slack Hooks for Logrus
package main
import (
"github.com/bluele/logrus_slack"
"github.com/sirupsen/logrus"
)
const (
// slack webhook url
hookURL = "https://hooks.slack.com/TXXXXX/BXXXXX/XXXXXXXXXX"
)
func main() {
logrus.SetLevel(logrus.DebugLevel)
logrus.AddHook(&logrus_slack.SlackHook{
HookURL: hookURL,
AcceptedLevels: logrus_slack.LevelThreshold(logrus.WarnLevel),
Channel: "#general",
IconEmoji: ":ghost:",
Username: "logrus_slack",
})
logrus.WithFields(logrus.Fields{"foo": "bar", "foo2": "bar2"}).Warn("this is a warn level message")
logrus.Debug("this is a debug level message")
logrus.Info("this is an info level message")
logrus.Error("this is an error level message")
}
You can specify hook options via `SlackHook` attributes.
*/
package logrus_slack
import (
"errors"
"github.com/bluele/slack"
"github.com/sirupsen/logrus"
"time"
)
// SlackHook is a logrus Hook for dispatching messages to the specified
// channel on Slack.
type SlackHook struct {
// Messages with a log level not contained in this array
// will not be dispatched. If nil, all messages will be dispatched.
AcceptedLevels []logrus.Level
HookURL string // Webhook URL
// slack post parameters
Username string // display name
Channel string // `#channel-name`
IconEmoji string // emoji string ex) ":ghost:":
IconURL string // icon url
FieldHeader string // a header above field data
Timeout time.Duration // request timeout
Async bool // if async is true, send a message asynchronously.
hook *slack.WebHook
}
// Fire - Sent event to slack
func (sh *SlackHook) Fire(e *logrus.Entry) error {
if sh.hook == nil {
sh.hook = slack.NewWebHook(sh.HookURL)
}
payload := &slack.WebHookPostPayload{
Username: sh.Username,
Channel: sh.Channel,
IconEmoji: sh.IconEmoji,
IconUrl: sh.IconURL,
}
color, _ := LevelColorMap[e.Level]
attachment := slack.Attachment{}
payload.Attachments = []*slack.Attachment{&attachment}
// If there are fields we need to render them at attachments
if len(e.Data) > 0 {
// Add a header above field data
attachment.Text = sh.FieldHeader
for k, v := range e.Data {
field := &slack.AttachmentField{}
if str, ok := v.(string); ok {
field.Title = k
field.Value = str
// If the field is <= 20 then we'll set it to short
if len(str) <= 20 {
field.Short = true
}
}
attachment.Fields = append(attachment.Fields, field)
}
attachment.Pretext = e.Message
} else {
attachment.Text = e.Message
}
attachment.Fallback = e.Message
attachment.Color = color
if sh.Async {
go sh.postMessage(payload)
return nil
}
return sh.postMessage(payload)
}
func (sh *SlackHook) postMessage(payload *slack.WebHookPostPayload) error {
if sh.Timeout <= 0 {
return sh.hook.PostMessage(payload)
}
ech := make(chan error, 1)
go func(ch chan error) {
ch <- nil
ch <- sh.hook.PostMessage(payload)
}(ech)
<-ech
select {
case err := <-ech:
return err
case <-time.After(sh.Timeout):
return TimeoutError
}
}
// Levels sets which levels to sent to slack
func (sh *SlackHook) Levels() []logrus.Level {
if sh.AcceptedLevels == nil {
return AllLevels
}
return sh.AcceptedLevels
}
var LevelColorMap = map[logrus.Level]string{
logrus.DebugLevel: "#9B30FF",
logrus.InfoLevel: "good",
logrus.WarnLevel: "warning",
logrus.ErrorLevel: "danger",
logrus.FatalLevel: "danger",
logrus.PanicLevel: "danger",
}
// Supported log levels
var AllLevels = []logrus.Level{
logrus.DebugLevel,
logrus.InfoLevel,
logrus.WarnLevel,
logrus.ErrorLevel,
logrus.FatalLevel,
logrus.PanicLevel,
}
var TimeoutError = errors.New("Request timed out")
// LevelThreshold - Returns every logging level above and including the given parameter.
func LevelThreshold(l logrus.Level) []logrus.Level {
for i := range AllLevels {
if AllLevels[i] == l {
return AllLevels[i:]
}
}
return []logrus.Level{}
}