@@ -2,7 +2,6 @@ package notifications
22
33import (
44 "bytes"
5- "fmt"
65 stdlog "log"
76 "strings"
87 "text/template"
@@ -13,23 +12,33 @@ import (
1312 log "github.com/sirupsen/logrus"
1413)
1514
15+ // LocalLog is a logrus logger that does not send entries as notifications
16+ var LocalLog = log .WithField ("notify" , "no" )
17+
1618const (
1719 shoutrrrDefaultLegacyTemplate = "{{range .}}{{.Message}}{{println}}{{end}}"
18- shoutrrrDefaultTemplate = `{{- with .Report -}}
20+ shoutrrrDefaultTemplate = `
21+ {{- if .Report -}}
22+ {{- with .Report -}}
23+ {{- if ( or .Updated .Failed ) -}}
1924{{len .Scanned}} Scanned, {{len .Updated}} Updated, {{len .Failed}} Failed
20- {{ range .Updated - }}
25+ {{- range .Updated}}
2126- {{.Name}} ({{.ImageName}}): {{.CurrentImageID.ShortID}} updated to {{.LatestImageID.ShortID}}
22- {{ end -}}
23- {{ range .Fresh - }}
27+ {{- end -}}
28+ {{- range .Fresh}}
2429- {{.Name}} ({{.ImageName}}): {{.State}}
25- {{ end -}}
26- {{ range .Skipped - }}
30+ {{- end -}}
31+ {{- range .Skipped}}
2732- {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
28- {{ end -}}
29- {{ range .Failed - }}
33+ {{- end -}}
34+ {{- range .Failed}}
3035- {{.Name}} ({{.ImageName}}): {{.State}}: {{.Error}}
31- {{end -}}
32- {{end -}}`
36+ {{- end -}}
37+ {{- end -}}
38+ {{- end -}}
39+ {{- else -}}
40+ {{range .Entries -}}{{.Message}}{{"\n"}}{{- end -}}
41+ {{- end -}}`
3342 shoutrrrType = "shoutrrr"
3443)
3544
@@ -47,6 +56,7 @@ type shoutrrrTypeNotifier struct {
4756 messages chan string
4857 done chan bool
4958 legacyTemplate bool
59+ params * types.Params
5060}
5161
5262// GetScheme returns the scheme part of a Shoutrrr URL
@@ -58,6 +68,7 @@ func GetScheme(url string) string {
5868 return url [:schemeEnd ]
5969}
6070
71+ // GetNames returns a list of notification services that has been added
6172func (n * shoutrrrTypeNotifier ) GetNames () []string {
6273 names := make ([]string , len (n .Urls ))
6374 for i , u := range n .Urls {
@@ -66,9 +77,10 @@ func (n *shoutrrrTypeNotifier) GetNames() []string {
6677 return names
6778}
6879
69- func newShoutrrrNotifier (tplString string , acceptedLogLevels []log.Level , legacy bool , urls ... string ) t.Notifier {
80+ func newShoutrrrNotifier (tplString string , acceptedLogLevels []log.Level , legacy bool , title string , urls ... string ) t.Notifier {
7081
7182 notifier := createNotifier (urls , acceptedLogLevels , tplString , legacy )
83+ notifier .params = & types.Params {"title" : title }
7284 log .AddHook (notifier )
7385
7486 // Do the sending in a separate goroutine so we don't block the main process.
@@ -102,67 +114,87 @@ func createNotifier(urls []string, levels []log.Level, tplString string, legacy
102114
103115func sendNotifications (n * shoutrrrTypeNotifier ) {
104116 for msg := range n .messages {
105- errs := n .Router .Send (msg , nil )
117+ errs := n .Router .Send (msg , n . params )
106118
107119 for i , err := range errs {
108120 if err != nil {
109121 scheme := GetScheme (n .Urls [i ])
110122 // Use fmt so it doesn't trigger another notification.
111- fmt .Printf ("Failed to send shoutrrr notification (#%d, %s): %v\n " , i , scheme , err )
123+ LocalLog .WithFields (log.Fields {
124+ "service" : scheme ,
125+ "index" : i ,
126+ }).WithError (err ).Error ("Failed to send shoutrrr notification" )
112127 }
113128 }
114129 }
115130
116131 n .done <- true
117132}
118133
119- func (n * shoutrrrTypeNotifier ) buildMessage (data Data ) string {
134+ func (n * shoutrrrTypeNotifier ) buildMessage (data Data ) ( string , error ) {
120135 var body bytes.Buffer
121136 var templateData interface {} = data
122137 if n .legacyTemplate {
123138 templateData = data .Entries
124139 }
125140 if err := n .template .Execute (& body , templateData ); err != nil {
126- fmt . Printf ( "Failed to execute Shoutrrrr template: %s \n " , err . Error ())
141+ return "" , err
127142 }
128143
129- return body .String ()
144+ return body .String (), nil
130145}
131146
132147func (n * shoutrrrTypeNotifier ) sendEntries (entries []* log.Entry , report t.Report ) {
133- msg := n .buildMessage (Data {entries , report })
148+ msg , err := n .buildMessage (Data {entries , report })
149+
150+ if msg == "" {
151+ // Log in go func in case we entered from Fire to avoid stalling
152+ go func () {
153+ if err != nil {
154+ LocalLog .WithError (err ).Fatal ("Notification template error" )
155+ } else {
156+ LocalLog .Info ("Skipping notification due to empty message" )
157+ }
158+ }()
159+ return
160+ }
134161 n .messages <- msg
135162}
136163
164+ // StartNotification begins queueing up messages to send them as a batch
137165func (n * shoutrrrTypeNotifier ) StartNotification () {
138166 if n .entries == nil {
139167 n .entries = make ([]* log.Entry , 0 , 10 )
140168 }
141169}
142170
171+ // SendNotification sends the queued up messages as a notification
143172func (n * shoutrrrTypeNotifier ) SendNotification (report t.Report ) {
144- //if n.entries == nil || len(n.entries) <= 0 {
145- // return
146- //}
147-
148173 n .sendEntries (n .entries , report )
149174 n .entries = nil
150175}
151176
177+ // Close prevents further messages from being queued and waits until all the currently queued up messages have been sent
152178func (n * shoutrrrTypeNotifier ) Close () {
153179 close (n .messages )
154180
155181 // Use fmt so it doesn't trigger another notification.
156- fmt . Println ("Waiting for the notification goroutine to finish" )
182+ LocalLog . Info ("Waiting for the notification goroutine to finish" )
157183
158184 _ = <- n .done
159185}
160186
187+ // Levels return what log levels trigger notifications
161188func (n * shoutrrrTypeNotifier ) Levels () []log.Level {
162189 return n .logLevels
163190}
164191
192+ // Fire is the hook that logrus calls on a new log message
165193func (n * shoutrrrTypeNotifier ) Fire (entry * log.Entry ) error {
194+ if entry .Data ["notify" ] == "no" {
195+ // Skip logging if explicitly tagged as non-notify
196+ return nil
197+ }
166198 if n .entries != nil {
167199 n .entries = append (n .entries , entry )
168200 } else {
0 commit comments