Added helper variables and templating for custom messages
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package alerts
|
||||
|
||||
// TemplateVarsHint returns a compact, multi-line listing of the
|
||||
// variables a subject/body template can reference. Designed for
|
||||
// embedding in TUI form hints where vertical space is tight.
|
||||
//
|
||||
// Continuation lines are pre-indented so they line up under the
|
||||
// first line when the caller prepends a fixed indent (e.g. " ").
|
||||
func TemplateVarsHint() string {
|
||||
return "Go text/template — leave empty to use the built-in format.\n" +
|
||||
" Vars: {{.Check.Name}}, {{.Check.Target}}, {{.Check.Type}}, {{.Check.ID}},\n" +
|
||||
" {{.Verb}} (UP|DOWN|RECOVERED), {{.From}}, {{.To}}, {{.NodeID}}, {{.When}},\n" +
|
||||
" {{.Snapshot.Detail}}, {{.Snapshot.Reports}}, {{.Snapshot.OKCount}}, {{.Snapshot.NotOK}}"
|
||||
}
|
||||
|
||||
// TemplateVarsHelp returns the long-form documentation for available
|
||||
// template variables, suitable for embedding in a CLI command's Long
|
||||
// help text. Each variable is described on its own line and an
|
||||
// example template is included at the end.
|
||||
func TemplateVarsHelp() string {
|
||||
return `Subject and body templates use Go text/template syntax. They are
|
||||
optional — leaving them empty falls back to the built-in format.
|
||||
Discord ignores the subject template (it has no subject line); SMTP
|
||||
uses both.
|
||||
|
||||
Available variables:
|
||||
{{.Check.Name}} check name (e.g. "homepage")
|
||||
{{.Check.Target}} URL / host:port / host being probed
|
||||
{{.Check.Type}} http | tcp | icmp
|
||||
{{.Check.ID}} stable check UUID
|
||||
{{.Verb}} UP | DOWN | RECOVERED
|
||||
{{.From}} previous state name
|
||||
{{.To}} new state name
|
||||
{{.NodeID}} master node that rendered the message
|
||||
{{.When}} RFC3339 timestamp of the transition
|
||||
{{.Snapshot.Detail}} probe detail string (e.g. "connection refused")
|
||||
{{.Snapshot.Reports}} total reports in the flip window
|
||||
{{.Snapshot.OKCount}} ok report count
|
||||
{{.Snapshot.NotOK}} failing report count
|
||||
|
||||
Example body template:
|
||||
{{.Check.Name}} is {{.Verb}} (target {{.Check.Target}}).
|
||||
Detail: {{.Snapshot.Detail}}`
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.cer.sh/axodouble/quptime/internal/alerts"
|
||||
"git.cer.sh/axodouble/quptime/internal/config"
|
||||
"git.cer.sh/axodouble/quptime/internal/daemon"
|
||||
"git.cer.sh/axodouble/quptime/internal/transport"
|
||||
@@ -21,9 +22,9 @@ import (
|
||||
// variants (if non-empty) and returns the effective subject + body
|
||||
// template strings. Inline flags take precedence over file flags.
|
||||
func bindTemplateFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String("subject", "", "subject template (text/template syntax — SMTP only)")
|
||||
cmd.Flags().String("subject", "", "subject template, Go text/template (SMTP only; see --help for variables)")
|
||||
cmd.Flags().String("subject-file", "", "path to a file containing the subject template")
|
||||
cmd.Flags().String("body", "", "body template (text/template syntax)")
|
||||
cmd.Flags().String("body", "", "body template, Go text/template (see --help for variables)")
|
||||
cmd.Flags().String("body-file", "", "path to a file containing the body template")
|
||||
}
|
||||
|
||||
@@ -172,7 +173,9 @@ func buildAlertEditCmd() *cobra.Command {
|
||||
take effect; everything else is preserved.
|
||||
|
||||
The type (smtp/discord) cannot be changed in place — delete and re-add
|
||||
the alert if you need to switch channels.`,
|
||||
the alert if you need to switch channels.
|
||||
|
||||
` + alerts.TemplateVarsHelp(),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second)
|
||||
@@ -308,6 +311,7 @@ func buildSMTPAddCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "smtp <name>",
|
||||
Short: "Add an SMTP relay alert",
|
||||
Long: "Add an SMTP relay alert.\n\n" + alerts.TemplateVarsHelp(),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second)
|
||||
@@ -365,6 +369,7 @@ func buildDiscordAddCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "discord <name>",
|
||||
Short: "Add a Discord webhook alert",
|
||||
Long: "Add a Discord webhook alert.\n\n" + alerts.TemplateVarsHelp(),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"git.cer.sh/axodouble/quptime/internal/alerts"
|
||||
"git.cer.sh/axodouble/quptime/internal/config"
|
||||
"git.cer.sh/axodouble/quptime/internal/daemon"
|
||||
"git.cer.sh/axodouble/quptime/internal/transport"
|
||||
@@ -272,7 +273,7 @@ func newAddDiscordForm() *form {
|
||||
textField("Name", "human-friendly identifier", true),
|
||||
textField("Webhook URL", "https://discord.com/api/webhooks/...", true),
|
||||
textField("Default", "yes/no — attach to every check automatically", false),
|
||||
textField("Body template", "leave empty for default formatting", false),
|
||||
textField("Body template", alerts.TemplateVarsHint(), false),
|
||||
}
|
||||
return newForm("Add Discord alert", fields, func(vals []string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
@@ -303,8 +304,8 @@ func newAddSMTPForm() *form {
|
||||
textField("To", "comma-separated recipient addresses", true),
|
||||
textField("StartTLS", "yes/no — default yes", false),
|
||||
textField("Default", "yes/no — attach to every check", false),
|
||||
textField("Subject template", "optional", false),
|
||||
textField("Body template", "optional", false),
|
||||
textField("Subject template", alerts.TemplateVarsHint(), false),
|
||||
textField("Body template", alerts.TemplateVarsHint(), false),
|
||||
}
|
||||
return newForm("Add SMTP alert", fields, func(vals []string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
@@ -445,7 +446,7 @@ func newEditDiscordForm(existing config.Alert) *form {
|
||||
textFieldWithValue("Name", "human-friendly identifier", existing.Name, true),
|
||||
textFieldWithValue("Webhook URL", "https://discord.com/api/webhooks/...", existing.DiscordWebhook, true),
|
||||
textFieldWithValue("Default", "yes/no — attach to every check automatically", boolStr(existing.Default), false),
|
||||
textFieldWithValue("Body template", "leave empty for default formatting", existing.BodyTemplate, false),
|
||||
textFieldWithValue("Body template", alerts.TemplateVarsHint(), existing.BodyTemplate, false),
|
||||
}
|
||||
id := existing.ID
|
||||
subject := existing.SubjectTemplate
|
||||
@@ -483,8 +484,8 @@ func newEditSMTPForm(existing config.Alert) *form {
|
||||
textFieldWithValue("To", "comma-separated recipient addresses", strings.Join(existing.SMTPTo, ","), true),
|
||||
textFieldWithValue("StartTLS", "yes/no — default yes", boolStr(existing.SMTPStartTLS), false),
|
||||
textFieldWithValue("Default", "yes/no — attach to every check", boolStr(existing.Default), false),
|
||||
textFieldWithValue("Subject template", "optional", existing.SubjectTemplate, false),
|
||||
textFieldWithValue("Body template", "optional", existing.BodyTemplate, false),
|
||||
textFieldWithValue("Subject template", alerts.TemplateVarsHint(), existing.SubjectTemplate, false),
|
||||
textFieldWithValue("Body template", alerts.TemplateVarsHint(), existing.BodyTemplate, false),
|
||||
}
|
||||
id := existing.ID
|
||||
return newForm("Edit SMTP alert", fields, func(vals []string) tea.Cmd {
|
||||
|
||||
Reference in New Issue
Block a user