Skip to content

Commit

Permalink
Add template processing for notify channels
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthony Green committed Dec 31, 2023
1 parent c91411a commit 689e988
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 8 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ However, multiple signals can map to the same channel.
The channel type `notify` is for sending messages to popular messaging
platforms.

You must specify a URL and, optionally, a message template.

`orb-ag` uses `shoutrrr` for sending notifications. Use the following
URL formats for these different services. Additional details are
available from the [`shoutrrr`
Expand All @@ -113,7 +115,29 @@ documentation](https://containrrr.dev/shoutrrr/v0.8/services/overview/).
| Telegram | `telegram://token@telegram?chats=@channel-1[,chat-id-1,...]` |
| Zulip Chat | `zulip://bot-mail:bot-key@zulip-domain/?stream=name-or-id&topic=name` |

The URL format for generic webhooks is described at
URLs are actually go templates that are processed before use. Data
that you can provide to the template engine includes:
- `.Timestamp` : the RFC3339 formatted timestamp for the matching log entry
- `.PID`: the process ID for the observed process
- `.Logline`: the matching log line

Similarly, the message sent may also be a template. If no `template`
is specified in the channel definition, then the logline is used as
the message. If a `template` is specified, then the template is
processed with the same data as above before sending.

As an example, here's a channel that sends an email containing json
data, and the observed PID is in the email subject line:

```
- name: "email-on-startup"
type: "notify"
url: "smtp://EMAIL@gmail.com:PASSWORD@smtp.gmail.com:587/?from=EMAIL@gmail.com&to=EMAIL@gmail.com&subject=Starting%20process%20{{.PID}}!"
template: "{ \"timestamp\": \"{{.Timestamp}}\", \"message\": \"{{.Logline}}\" }"
```

Generic webhooks and handled specially by `shoutrrr`. Their URL
format is described at
[https://containrrr.dev/shoutrrr/v0.8/services/generic/](https://containrrr.dev/shoutrrr/v0.8/services/generic/).

### Sending Kafka messages
Expand Down
52 changes: 45 additions & 7 deletions orb-ag.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"regexp"
"sync"
"syscall"
"text/template"
"time"
)

Expand All @@ -49,12 +50,13 @@ var restart bool = true
var observed_cmd *exec.Cmd

type Channel struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
URL string `yaml:"url"`
Topic string `yaml:"topic"`
Broker string `yaml:"broker"`
Shell string `yaml:"shell"`
Name string `yaml:"name"`
Type string `yaml:"type"`
URL string `yaml:"url"`
Template string `yaml:"template"`
Topic string `yaml:"topic"`
Broker string `yaml:"broker"`
Shell string `yaml:"shell"`
}

type Signal struct {
Expand Down Expand Up @@ -120,6 +122,12 @@ type Notification struct {
Message string
}

type TemplateData struct {
PID int
Logline string
Timestamp string
}

func loadYAMLConfig(filename string, config *Config) error {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
Expand All @@ -135,14 +143,44 @@ func loadYAMLConfig(filename string, config *Config) error {
}

func startWorkers(notificationQueue <-chan Notification, numWorkers int, wg *sync.WaitGroup) {
var messageString string

for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(workerID int) {
defer wg.Done()
for notification := range notificationQueue {
td := TemplateData{PID: notification.PID,
Logline: notification.Message,
Timestamp: time.Now().Format(time.RFC3339)}
switch notification.Channel.Type {
case "notify":
err := shoutrrr.Send(notification.Channel.URL, notification.Message)
tmpl, err := template.New("url").Parse(notification.Channel.URL)
if err != nil {
log.Fatal("org-ab error: can't parse URL template: ", err)
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, td)
if err != nil {
log.Fatal("org-ab error: can't execute URL template: ", err)
}
urlString := buffer.String()
if notification.Channel.Template != "" {
tmpl, err := template.New("msg").Parse(notification.Channel.Template)
if err != nil {
log.Fatal("org-ab error: can't parse template: ", err)
}
var buffer bytes.Buffer
err = tmpl.Execute(&buffer, td)
if err != nil {
log.Fatal("org-ab error: can't execute URL template: ", err)
}
messageString = buffer.String()
} else {
messageString = notification.Message
}

err = shoutrrr.Send(urlString, messageString)
if err != nil {
log.Println("org-ab warning: failed sending notification: ", err)
}
Expand Down

0 comments on commit 689e988

Please sign in to comment.