Skip to content

Commit 42486fb

Browse files
authored
Merge pull request #16 from cgilling/add_sort_field
add SortFields and SortPriorities options to SlackrusHook
2 parents f7aae32 + f860ecf commit 42486fb

File tree

2 files changed

+171
-1
lines changed

2 files changed

+171
-1
lines changed

slackrus.go

+32-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package slackrus
33

44
import (
55
"fmt"
6+
"sort"
67

78
"github.com/johntdyer/slack-go"
89
"github.com/sirupsen/logrus"
@@ -27,6 +28,14 @@ type SlackrusHook struct {
2728
Asynchronous bool
2829
Extra map[string]interface{}
2930
Disabled bool
31+
// SortFields if set to true will sort Fields before sending them to slack. By default they
32+
// are sorted in alphabetical order. For finer grained control, SortPriorities can be used.
33+
SortFields bool
34+
// SortPriorities if set will modify the straight alphabetical sort used when SortFields is set.
35+
// It is a map of field keys to sort priority, causing keys with higher priorities to appear first.
36+
// Any field field keys that do not appear in SortPriorities will appear after all those that do
37+
// and be sorted in alphabetical order.
38+
SortPriorities map[string]int
3039
}
3140

3241
// Levels sets which levels to sent to slack
@@ -42,7 +51,7 @@ func (sh *SlackrusHook) Fire(e *logrus.Entry) error {
4251
if sh.Disabled {
4352
return nil
4453
}
45-
54+
4655
color := ""
4756
switch e.Level {
4857
case logrus.DebugLevel:
@@ -90,6 +99,28 @@ func (sh *SlackrusHook) Fire(e *logrus.Entry) error {
9099
attach.Fallback = newEntry.Message
91100
attach.Color = color
92101

102+
if sh.SortFields {
103+
sort.SliceStable(attach.Fields, func(i, j int) bool {
104+
iTitle, jTitle := attach.Fields[i].Title, attach.Fields[j].Title
105+
if sh.SortPriorities == nil {
106+
return iTitle < jTitle
107+
}
108+
iVal, iOK := sh.SortPriorities[iTitle]
109+
jVal, jOK := sh.SortPriorities[jTitle]
110+
111+
if iOK && !jOK {
112+
return true
113+
}
114+
if !iOK && jOK {
115+
return false
116+
}
117+
if (!iOK && !jOK) || iVal == jVal {
118+
return iTitle < jTitle
119+
}
120+
return iVal > jVal
121+
})
122+
}
123+
93124
c := slack.NewClient(sh.HookURL)
94125

95126
if sh.Asynchronous {

slackrus_test.go

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package slackrus
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/johntdyer/slack-go"
10+
"github.com/sirupsen/logrus"
11+
)
12+
13+
type Fixture struct {
14+
Messages []slack.Message
15+
Cleanup func()
16+
MsgRcvd chan struct{}
17+
18+
server *httptest.Server
19+
}
20+
21+
func (f *Fixture) URL() string {
22+
return f.server.URL
23+
}
24+
25+
func NewFixture(t *testing.T) *Fixture {
26+
f := &Fixture{MsgRcvd: make(chan struct{}, 1)}
27+
f.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
28+
var msg slack.Message
29+
dec := json.NewDecoder(r.Body)
30+
err := dec.Decode(&msg)
31+
if err != nil {
32+
w.WriteHeader(500)
33+
return
34+
}
35+
f.Messages = append(f.Messages, msg)
36+
select {
37+
case f.MsgRcvd <- struct{}{}:
38+
default:
39+
}
40+
}))
41+
f.Cleanup = func() { f.server.Close() }
42+
return f
43+
}
44+
45+
func TestFieldSorting(t *testing.T) {
46+
f := NewFixture(t)
47+
defer f.Cleanup()
48+
49+
logger := logrus.New()
50+
logger.AddHook(&SlackrusHook{
51+
HookURL: f.URL(),
52+
Channel: "#slack-testing",
53+
SortFields: true,
54+
})
55+
56+
first, second, third := "a_should_be_first", "b_should_be_second", "c_should_be_third"
57+
58+
logger.WithFields(logrus.Fields{
59+
second: "b content",
60+
third: "c content",
61+
first: "a content",
62+
}).Info("well hello there, you better sort my fields!!!!")
63+
64+
<-f.MsgRcvd
65+
66+
if exp, got := 1, len(f.Messages); exp != got {
67+
t.Fatalf("received unexpected number of messages: exp: %d, got: %d", exp, got)
68+
}
69+
msg := f.Messages[0]
70+
if exp, got := 1, len(msg.Attachments); exp != got {
71+
t.Fatalf("received unexpected number of Attachments in message: exp: %d, got: %d", exp, got)
72+
}
73+
fields := msg.Attachments[0].Fields
74+
if exp, got := 3, len(fields); exp != got {
75+
t.Fatalf("received unexpected number of Fields in attachment: exp: %d, got: %d", exp, got)
76+
}
77+
78+
if exp, got := first, fields[0].Title; exp != got {
79+
t.Errorf("0-th field title not as expected: exp: %q, got: %q", exp, got)
80+
}
81+
if exp, got := second, fields[1].Title; exp != got {
82+
t.Errorf("1st field title not as expected: exp: %q, got: %q", exp, got)
83+
}
84+
if exp, got := third, fields[2].Title; exp != got {
85+
t.Errorf("2nd field title not as expected: exp: %q, got: %q", exp, got)
86+
}
87+
}
88+
89+
func TestFieldSortPriorities(t *testing.T) {
90+
f := NewFixture(t)
91+
defer f.Cleanup()
92+
93+
first, second, third, fourth := "d_should_be_first", "b_should_be_second", "a_should_be_third", "c_should_be_fourth"
94+
95+
logger := logrus.New()
96+
logger.AddHook(&SlackrusHook{
97+
HookURL: f.URL(),
98+
Channel: "#slack-testing",
99+
SortFields: true,
100+
SortPriorities: map[string]int{
101+
first: 10,
102+
second: 5,
103+
},
104+
})
105+
106+
logger.WithFields(logrus.Fields{
107+
first: "first content",
108+
second: "second content",
109+
third: "third content",
110+
fourth: "fourth content",
111+
}).Info("well hello there, you better sort my fields!!!!")
112+
113+
<-f.MsgRcvd
114+
115+
if exp, got := 1, len(f.Messages); exp != got {
116+
t.Fatalf("received unexpected number of messages: exp: %d, got: %d", exp, got)
117+
}
118+
msg := f.Messages[0]
119+
if exp, got := 1, len(msg.Attachments); exp != got {
120+
t.Fatalf("received unexpected number of Attachments in message: exp: %d, got: %d", exp, got)
121+
}
122+
fields := msg.Attachments[0].Fields
123+
if exp, got := 4, len(fields); exp != got {
124+
t.Fatalf("received unexpected number of Fields in attachment: exp: %d, got: %d", exp, got)
125+
}
126+
127+
if exp, got := first, fields[0].Title; exp != got {
128+
t.Errorf("0-th field title not as expected: exp: %q, got: %q", exp, got)
129+
}
130+
if exp, got := second, fields[1].Title; exp != got {
131+
t.Errorf("1st field title not as expected: exp: %q, got: %q", exp, got)
132+
}
133+
if exp, got := third, fields[2].Title; exp != got {
134+
t.Errorf("2nd field title not as expected: exp: %q, got: %q", exp, got)
135+
}
136+
if exp, got := fourth, fields[3].Title; exp != got {
137+
t.Errorf("3rd field title not as expected: exp: %q, got: %q", exp, got)
138+
}
139+
}

0 commit comments

Comments
 (0)