can parse slack messages from scraping channel history too
parent
a91da082c7
commit
7df7528ccf
22
message.go
22
message.go
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -59,8 +60,11 @@ func Deserialize(b []byte) (Message, error) {
|
||||||
|
|
||||||
type (
|
type (
|
||||||
slackMessage struct {
|
slackMessage struct {
|
||||||
|
slackEvent
|
||||||
|
Type string
|
||||||
TS uint64 `json:"event_time"`
|
TS uint64 `json:"event_time"`
|
||||||
Event slackEvent
|
Event slackEvent
|
||||||
|
MessageTS string `json:"ts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
slackEvent struct {
|
slackEvent struct {
|
||||||
|
|
@ -108,7 +112,11 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseSlack(b []byte, assetPattern, datacenterPattern, eventNamePattern string) (Message, error) {
|
func ParseSlack(b []byte, assetPattern, datacenterPattern, eventNamePattern string) (Message, error) {
|
||||||
m, err := parseSlackJSON(b)
|
return ParseSlackFromChannel(b, assetPattern, datacenterPattern, eventNamePattern, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseSlackFromChannel(b []byte, assetPattern, datacenterPattern, eventNamePattern string, ch string) (Message, error) {
|
||||||
|
m, err := parseSlackJSON(b, ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Message{}, err
|
return Message{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -131,12 +139,16 @@ func ParseSlack(b []byte, assetPattern, datacenterPattern, eventNamePattern stri
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSlackJSON(b []byte) (Message, error) {
|
func parseSlackJSON(b []byte, ch string) (Message, error) {
|
||||||
s, err := _parseSlackJSON(b)
|
s, err := _parseSlackJSON(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Message{}, err
|
return Message{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ch != "" {
|
||||||
|
s.Event.Channel = ch
|
||||||
|
}
|
||||||
|
|
||||||
if s.Event.Bot.Name != "" {
|
if s.Event.Bot.Name != "" {
|
||||||
if len(s.Event.Attachments) == 0 {
|
if len(s.Event.Attachments) == 0 {
|
||||||
return Message{}, ErrIrrelevantMessage
|
return Message{}, ErrIrrelevantMessage
|
||||||
|
|
@ -184,6 +196,12 @@ func parseSlackJSON(b []byte) (Message, error) {
|
||||||
func _parseSlackJSON(b []byte) (slackMessage, error) {
|
func _parseSlackJSON(b []byte) (slackMessage, error) {
|
||||||
var result slackMessage
|
var result slackMessage
|
||||||
err := json.Unmarshal(b, &result)
|
err := json.Unmarshal(b, &result)
|
||||||
|
switch result.Type {
|
||||||
|
case "message":
|
||||||
|
result.Event = result.slackEvent
|
||||||
|
result.TS, _ = strconv.ParseUint(strings.Split(result.MessageTS, ".")[0], 10, 64)
|
||||||
|
result.Event.ID = result.MessageTS
|
||||||
|
}
|
||||||
if result.Event.Nested != nil && !result.Event.Nested.Empty() {
|
if result.Event.Nested != nil && !result.Event.Nested.Empty() {
|
||||||
result.Event.Blocks = result.Event.Nested.Blocks
|
result.Event.Blocks = result.Event.Nested.Blocks
|
||||||
result.Event.Bot = result.Event.Nested.Bot
|
result.Event.Bot = result.Event.Nested.Bot
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -9,6 +8,7 @@ import (
|
||||||
|
|
||||||
func TestParseSlackTestdata(t *testing.T) {
|
func TestParseSlackTestdata(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
|
inCh string
|
||||||
slackMessage slackMessage
|
slackMessage slackMessage
|
||||||
message Message
|
message Message
|
||||||
}{
|
}{
|
||||||
|
|
@ -114,6 +114,21 @@ func TestParseSlackTestdata(t *testing.T) {
|
||||||
Resolved: true,
|
Resolved: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"reingested_alert.json": {
|
||||||
|
inCh: "C06U1DDBBU4",
|
||||||
|
message: Message{
|
||||||
|
ID: "1712892637.037639/1712892637",
|
||||||
|
TS: 1712892637,
|
||||||
|
Source: "https://renderinc.slack.com/archives/C06U1DDBBU4/p1712892637037639",
|
||||||
|
Channel: "C06U1DDBBU4",
|
||||||
|
Thread: "1712892637.037639",
|
||||||
|
EventName: "Alertconfig Workflow Failed",
|
||||||
|
Event: "11061",
|
||||||
|
Plaintext: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
|
||||||
|
Asset: "",
|
||||||
|
Resolved: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, d := range cases {
|
for name, d := range cases {
|
||||||
|
|
@ -124,18 +139,8 @@ func TestParseSlackTestdata(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("_parseSlackJSON", func(t *testing.T) {
|
t.Run("ParseSlackFromChannel "+want.inCh, func(t *testing.T) {
|
||||||
got, err := _parseSlackJSON(b)
|
got, err := ParseSlackFromChannel(b, renderAssetPattern, renderDatacenterPattern, renderEventNamePattern, want.inCh)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if fmt.Sprintf("%+v", got) != fmt.Sprintf("%+v", want.slackMessage) {
|
|
||||||
t.Errorf("wanted \n\t%+v, got\n\t%+v", want.slackMessage, got)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ParseSlack", func(t *testing.T) {
|
|
||||||
got, err := ParseSlack(b, renderAssetPattern, renderDatacenterPattern, renderEventNamePattern)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"user": "U03RUK7FBUY",
|
||||||
|
"type": "message",
|
||||||
|
"ts": "1712892637.037639",
|
||||||
|
"edited": {
|
||||||
|
"user": "B03RHGBPH2M",
|
||||||
|
"ts": "1712896236.000000"
|
||||||
|
},
|
||||||
|
"bot_id": "B03RHGBPH2M",
|
||||||
|
"app_id": "A286WATV2",
|
||||||
|
"text": "",
|
||||||
|
"team": "T9RQLQ0KV",
|
||||||
|
"bot_profile": {
|
||||||
|
"id": "B03RHGBPH2M",
|
||||||
|
"app_id": "A286WATV2",
|
||||||
|
"name": "Opsgenie for Alert Management",
|
||||||
|
"icons": {
|
||||||
|
"image_36": "https://avatars.slack-edge.com/2019-05-30/652285939191_7831939cc30ef7159561_36.png",
|
||||||
|
"image_48": "https://avatars.slack-edge.com/2019-05-30/652285939191_7831939cc30ef7159561_48.png",
|
||||||
|
"image_72": "https://avatars.slack-edge.com/2019-05-30/652285939191_7831939cc30ef7159561_72.png"
|
||||||
|
},
|
||||||
|
"deleted": false,
|
||||||
|
"updated": 1658887059,
|
||||||
|
"team_id": "T9RQLQ0KV"
|
||||||
|
},
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"color": "2ecc71",
|
||||||
|
"fallback": "\"[Grafana]: Firing: Alertconfig Workflow Failed\" <https://opsg.in/a/i/render/bdbbe5a6-738b-4643-9267-39d8dfcb2ead-1712892636514|11061>\nTags: alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
|
||||||
|
"text": "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
|
||||||
|
"title": "#11061: [Grafana]: Firing: Alertconfig Workflow Failed",
|
||||||
|
"title_link": "https://opsg.in/a/i/render/bdbbe5a6-738b-4643-9267-39d8dfc$2ead-1712892636514",
|
||||||
|
"callback_id": "bbd4a269-08a9-470e-ba79-ce238ac03dc7_05fa2e9b-bec4-4a7e-842d-36043d267a13_11061",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"value": "P3",
|
||||||
|
"title": "Priority",
|
||||||
|
"short": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
|
||||||
|
"title": "Tags",
|
||||||
|
"short": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Datastores Non-Critical",
|
||||||
|
"title": "Routed Teams",
|
||||||
|
"short": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mrkdwn_in": [
|
||||||
|
"text"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue