github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/log/ansHook.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "github.com/SAP/jenkins-library/pkg/ans" 6 "github.com/pkg/errors" 7 "github.com/sirupsen/logrus" 8 "os" 9 "strings" 10 ) 11 12 // ANSHook is used to set the hook features for the logrus hook 13 type ANSHook struct { 14 client ans.Client 15 eventTemplate ans.Event 16 firing bool 17 } 18 19 // Levels returns the supported log level of the hook. 20 func (ansHook *ANSHook) Levels() []logrus.Level { 21 return []logrus.Level{logrus.WarnLevel, logrus.ErrorLevel, logrus.PanicLevel, logrus.FatalLevel} 22 } 23 24 // Fire creates a new event from the logrus and sends an event to the ANS backend 25 func (ansHook *ANSHook) Fire(entry *logrus.Entry) (err error) { 26 if ansHook.firing { 27 return fmt.Errorf("ANS hook has already been fired") 28 } 29 ansHook.firing = true 30 defer func() { ansHook.firing = false }() 31 32 if len(strings.TrimSpace(entry.Message)) == 0 { 33 return 34 } 35 var event ans.Event 36 if event, err = ansHook.eventTemplate.Copy(); err != nil { 37 return 38 } 39 40 logLevel := entry.Level 41 event.SetSeverityAndCategory(logLevel) 42 var stepName string 43 if entry.Data["stepName"] != nil { 44 stepName = fmt.Sprint(entry.Data["stepName"]) 45 } else { 46 stepName = "n/a" 47 } 48 event.Tags["cicd:stepName"] = stepName 49 if errorCategory := GetErrorCategory().String(); errorCategory != "undefined" { 50 event.Tags["cicd:errorCategory"] = errorCategory 51 } 52 53 event.EventTimestamp = entry.Time.Unix() 54 if event.Subject == "" { 55 event.Subject = fmt.Sprintf("Step '%s' sends '%s'", stepName, event.Severity) 56 } 57 event.Body = entry.Message 58 event.Tags["cicd:logLevel"] = logLevel.String() 59 60 return ansHook.client.Send(event) 61 } 62 63 type registrationUtil interface { 64 ans.Client 65 registerHook(hook *ANSHook) 66 } 67 68 type registrationUtilImpl struct { 69 ans.Client 70 } 71 72 func (u *registrationUtilImpl) registerHook(hook *ANSHook) { 73 RegisterHook(hook) 74 } 75 76 func (u *registrationUtilImpl) registerSecret(secret string) { 77 RegisterSecret(secret) 78 } 79 80 // RegisterANSHookIfConfigured creates a new ANS hook for logrus if it is configured and registers it 81 func RegisterANSHookIfConfigured(correlationID string) error { 82 return registerANSHookIfConfigured(correlationID, ®istrationUtilImpl{Client: &ans.ANS{}}) 83 } 84 85 func registerANSHookIfConfigured(correlationID string, util registrationUtil) error { 86 ansServiceKeyJSON := os.Getenv("PIPER_ansHookServiceKey") 87 if len(ansServiceKeyJSON) == 0 { 88 return nil 89 } 90 91 ansServiceKey, err := ans.UnmarshallServiceKeyJSON(ansServiceKeyJSON) 92 if err != nil { 93 return errors.Wrap(err, "cannot initialize SAP Alert Notification Service due to faulty serviceKey json") 94 } 95 RegisterSecret(ansServiceKey.ClientSecret) 96 97 util.SetServiceKey(ansServiceKey) 98 if err = util.CheckCorrectSetup(); err != nil { 99 return errors.Wrap(err, "check http request to SAP Alert Notification Service failed; not setting up the ANS hook") 100 } 101 102 eventTemplate, err := setupEventTemplate(os.Getenv("PIPER_ansEventTemplate"), correlationID) 103 if err != nil { 104 return err 105 } 106 util.registerHook(&ANSHook{ 107 client: util, 108 eventTemplate: eventTemplate, 109 }) 110 return nil 111 } 112 113 func setupEventTemplate(customerEventTemplate, correlationID string) (ans.Event, error) { 114 event := ans.Event{ 115 EventType: "Piper", 116 Tags: map[string]interface{}{"ans:correlationId": correlationID, "ans:sourceEventId": correlationID}, 117 Resource: &ans.Resource{ 118 ResourceType: "Pipeline", 119 ResourceName: "Pipeline", 120 }, 121 } 122 123 if len(customerEventTemplate) > 0 { 124 if err := event.MergeWithJSON([]byte(customerEventTemplate)); err != nil { 125 Entry().WithField("stepName", "ANS").Warnf("provided SAP Alert Notification Service event template '%s' could not be unmarshalled: %v", customerEventTemplate, err) 126 return ans.Event{}, errors.Wrapf(err, "provided SAP Alert Notification Service event template '%s' could not be unmarshalled", customerEventTemplate) 127 } 128 } 129 if len(event.Severity) > 0 { 130 Entry().WithField("stepName", "ANS").Warnf("event severity set to '%s' will be overwritten according to the log level", event.Severity) 131 event.Severity = "" 132 } 133 if len(event.Category) > 0 { 134 Entry().WithField("stepName", "ANS").Warnf("event category set to '%s' will be overwritten according to the log level", event.Category) 135 event.Category = "" 136 } 137 if err := event.Validate(); err != nil { 138 return ans.Event{}, errors.Wrap(err, "did not initialize SAP Alert Notification Service due to faulty event template json") 139 } 140 return event, nil 141 }