/
ansHook.go
141 lines (122 loc) · 4.3 KB
/
ansHook.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
package log
import (
"fmt"
"github.com/SAP/jenkins-library/pkg/ans"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"os"
"strings"
)
// ANSHook is used to set the hook features for the logrus hook
type ANSHook struct {
client ans.Client
eventTemplate ans.Event
firing bool
}
// Levels returns the supported log level of the hook.
func (ansHook *ANSHook) Levels() []logrus.Level {
return []logrus.Level{logrus.WarnLevel, logrus.ErrorLevel, logrus.PanicLevel, logrus.FatalLevel}
}
// Fire creates a new event from the logrus and sends an event to the ANS backend
func (ansHook *ANSHook) Fire(entry *logrus.Entry) (err error) {
if ansHook.firing {
return fmt.Errorf("ANS hook has already been fired")
}
ansHook.firing = true
defer func() { ansHook.firing = false }()
if len(strings.TrimSpace(entry.Message)) == 0 {
return
}
var event ans.Event
if event, err = ansHook.eventTemplate.Copy(); err != nil {
return
}
logLevel := entry.Level
event.SetSeverityAndCategory(logLevel)
var stepName string
if entry.Data["stepName"] != nil {
stepName = fmt.Sprint(entry.Data["stepName"])
} else {
stepName = "n/a"
}
event.Tags["cicd:stepName"] = stepName
if errorCategory := GetErrorCategory().String(); errorCategory != "undefined" {
event.Tags["cicd:errorCategory"] = errorCategory
}
event.EventTimestamp = entry.Time.Unix()
if event.Subject == "" {
event.Subject = fmt.Sprintf("Step '%s' sends '%s'", stepName, event.Severity)
}
event.Body = entry.Message
event.Tags["cicd:logLevel"] = logLevel.String()
return ansHook.client.Send(event)
}
type registrationUtil interface {
ans.Client
registerHook(hook *ANSHook)
}
type registrationUtilImpl struct {
ans.Client
}
func (u *registrationUtilImpl) registerHook(hook *ANSHook) {
RegisterHook(hook)
}
func (u *registrationUtilImpl) registerSecret(secret string) {
RegisterSecret(secret)
}
// RegisterANSHookIfConfigured creates a new ANS hook for logrus if it is configured and registers it
func RegisterANSHookIfConfigured(correlationID string) error {
return registerANSHookIfConfigured(correlationID, ®istrationUtilImpl{Client: &ans.ANS{}})
}
func registerANSHookIfConfigured(correlationID string, util registrationUtil) error {
ansServiceKeyJSON := os.Getenv("PIPER_ansHookServiceKey")
if len(ansServiceKeyJSON) == 0 {
return nil
}
ansServiceKey, err := ans.UnmarshallServiceKeyJSON(ansServiceKeyJSON)
if err != nil {
return errors.Wrap(err, "cannot initialize SAP Alert Notification Service due to faulty serviceKey json")
}
RegisterSecret(ansServiceKey.ClientSecret)
util.SetServiceKey(ansServiceKey)
if err = util.CheckCorrectSetup(); err != nil {
return errors.Wrap(err, "check http request to SAP Alert Notification Service failed; not setting up the ANS hook")
}
eventTemplate, err := setupEventTemplate(os.Getenv("PIPER_ansEventTemplate"), correlationID)
if err != nil {
return err
}
util.registerHook(&ANSHook{
client: util,
eventTemplate: eventTemplate,
})
return nil
}
func setupEventTemplate(customerEventTemplate, correlationID string) (ans.Event, error) {
event := ans.Event{
EventType: "Piper",
Tags: map[string]interface{}{"ans:correlationId": correlationID, "ans:sourceEventId": correlationID},
Resource: &ans.Resource{
ResourceType: "Pipeline",
ResourceName: "Pipeline",
},
}
if len(customerEventTemplate) > 0 {
if err := event.MergeWithJSON([]byte(customerEventTemplate)); err != nil {
Entry().WithField("stepName", "ANS").Warnf("provided SAP Alert Notification Service event template '%s' could not be unmarshalled: %v", customerEventTemplate, err)
return ans.Event{}, errors.Wrapf(err, "provided SAP Alert Notification Service event template '%s' could not be unmarshalled", customerEventTemplate)
}
}
if len(event.Severity) > 0 {
Entry().WithField("stepName", "ANS").Warnf("event severity set to '%s' will be overwritten according to the log level", event.Severity)
event.Severity = ""
}
if len(event.Category) > 0 {
Entry().WithField("stepName", "ANS").Warnf("event category set to '%s' will be overwritten according to the log level", event.Category)
event.Category = ""
}
if err := event.Validate(); err != nil {
return ans.Event{}, errors.Wrap(err, "did not initialize SAP Alert Notification Service due to faulty event template json")
}
return event, nil
}