Documentation
¶
Overview ¶
Package beacon is a small library for sending notifications and pushing telemetry: alerts to the channels people watch, and health and status to a monitor. It imports nothing application-specific, and secret resolution is injected by the host program.
The API is under construction.
Index ¶
- func RegisterBackend(typ string, ctor BackendFactory)
- func RegisterSink(typ string, ctor SinkFactory)
- type Backend
- type BackendFactory
- type Beacon
- type ChannelConfig
- type Config
- type DiscordBackend
- type GatusSink
- type GotifyBackend
- type HTTPBackend
- type Health
- type Level
- type LogBackend
- type MatrixBackend
- type MattermostBackend
- type Notification
- type NtfyBackend
- type PushoverBackend
- type SMTPBackend
- type SecretResolver
- type SinkFactory
- type SlackBackend
- type TelegramBackend
- type TelemetryConfig
- type TelemetrySink
- type WebhookBackend
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RegisterBackend ¶
func RegisterBackend(typ string, ctor BackendFactory)
RegisterBackend makes a notification backend type available to Config, keyed by typ (e.g. "ntfy", "discord"). It is meant to be called from an init function in the package implementing that backend. Registering the same type twice panics, since it almost always indicates two packages fighting over the same name.
func RegisterSink ¶
func RegisterSink(typ string, ctor SinkFactory)
RegisterSink makes a telemetry sink type available to Config, keyed by typ (e.g. "gatus"). It is meant to be called from an init function in the package implementing that sink. Registering the same type twice panics.
Types ¶
type Backend ¶
type Backend interface {
// Name identifies this backend instance, typically its registered type
// (e.g. "ntfy"). Used in error messages and logs.
Name() string
// Send delivers a notification through this channel. Implementations
// should resolve any secrets they need at send time, not at
// construction time, so credential rotation does not require a
// rebuild.
Send(ctx context.Context, n Notification) error
}
Backend is one notification channel: email, ntfy, Discord, a generic webhook, and so on. A Backend is constructed by the BackendFactory registered under its Type and lives for the lifetime of a Beacon.
type BackendFactory ¶
type BackendFactory func(settings map[string]string, resolve SecretResolver) (Backend, error)
BackendFactory builds a Backend from its configured settings. resolve is never nil; a host with no secret store still provides a resolver that returns an error for every name, so factories can call it unconditionally.
type Beacon ¶
type Beacon struct {
// contains filtered or unexported fields
}
Beacon fans a notification out to configured channels and a health result out to configured telemetry sinks.
func New ¶
func New(cfg Config, resolve SecretResolver) (*Beacon, error)
New builds a Beacon from cfg, constructing each configured channel and sink from the registry populated by RegisterBackend and RegisterSink. resolve may be nil if the host has no secrets to offer; New then uses a resolver that errors on every lookup.
New fails if a Channels or Telemetry entry names a Type that has not been registered, or if a factory returns an error.
func (*Beacon) Notify ¶
func (b *Beacon) Notify(ctx context.Context, n Notification) error
Notify fans n out to every channel whose MinLevel is at or below n.Level. It attempts every eligible channel even if one fails, and returns the combined error via errors.Join (nil if all succeeded, or if no channel was eligible).
type ChannelConfig ¶
type ChannelConfig struct {
// Type selects the backend, matching a name passed to RegisterBackend
// (e.g. "log", "ntfy", "discord").
Type string
// MinLevel is the lowest severity this channel receives. A
// Notification below MinLevel is not sent to this channel.
MinLevel Level
// Settings is backend-specific configuration. Any value that names a
// secret rather than holding it directly is resolved through the
// SecretResolver by the backend itself, at send time, so credential
// rotation takes effect without a rebuild or restart.
Settings map[string]string
}
ChannelConfig configures one notification backend.
type Config ¶
type Config struct {
Channels []ChannelConfig
Telemetry []TelemetryConfig
}
Config is the full beacon configuration: the notification channels and telemetry sinks to build.
type DiscordBackend ¶
type DiscordBackend struct {
// contains filtered or unexported fields
}
DiscordBackend sends notifications to a Discord incoming webhook.
func (*DiscordBackend) Send ¶
func (b *DiscordBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the configured webhook as an embed: title, description, and a color keyed off Level. If n.Title is empty there is nothing meaningful to title an embed with, so Send falls back to a plain content message instead.
type GatusSink ¶
type GatusSink struct {
// contains filtered or unexported fields
}
GatusSink pushes health results to a Gatus external endpoint, Gatus's push-based heartbeat API for monitoring things Gatus cannot reach or poll itself (a cron job, a background worker, a service behind a firewall). Gatus treats the endpoint as unhealthy if it does not receive a push within its configured interval, so Report should be called on a dead-man's-switch schedule even when h.OK is true.
func (*GatusSink) Report ¶
Report POSTs h to the configured external endpoint's push URL. success is h.OK; duration is encoded as a Go duration string (e.g. "250ms"); error is included, carrying h.Message, only when h.OK is false. All three are sent as URL query parameters, since Gatus's external-endpoint API takes no request body.
type GotifyBackend ¶
type GotifyBackend struct {
// contains filtered or unexported fields
}
GotifyBackend sends notifications to a self-hosted Gotify server.
func (*GotifyBackend) Send ¶
func (b *GotifyBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the Gotify /message endpoint, authenticated with the app token via the X-Gotify-Key header. Priority uses the same 1-5 scale shared with ntfy, which sits comfortably inside Gotify's 0-10 range.
type HTTPBackend ¶ added in v0.1.2
type HTTPBackend struct {
// contains filtered or unexported fields
}
HTTPBackend is the generic templatable HTTP channel: it renders a caller-supplied body template into an HTTP POST and, optionally, checks a named field of the JSON response to decide whether the delivery actually succeeded. It makes no assumption about the target's request or response shape, so any service that accepts an HTTP POST can be reached by configuration alone, without a bespoke backend and without a new dependency.
It complements WebhookBackend: "webhook" sends beacon's own fixed JSON payload (optionally HMAC-signed), while "http" lets the caller define the exact bytes on the wire. Reach for "http" when a receiver dictates its own payload shape.
func (*HTTPBackend) Send ¶ added in v0.1.2
func (b *HTTPBackend) Send(ctx context.Context, n Notification) error
Send renders the body template for n and POSTs it. A transport error or a non-2xx status is a failure. When success_field is configured, the JSON response is parsed and the field is checked too, so a service that returns 200 while reporting a failure in its body (a common pattern) is not mistaken for a successful delivery.
type Health ¶
type Health struct {
// Name identifies what this health result is about, e.g. a service or
// job name.
Name string
// OK reports whether the thing being monitored is healthy.
OK bool
// Message is a short human-readable detail, especially useful when
// OK is false.
Message string
// Duration is how long the underlying operation took, if applicable.
Duration time.Duration
}
Health is one telemetry result to push to a monitor.
type Level ¶
type Level int
Level is the severity of a Notification, ordered from least to most urgent.
type LogBackend ¶
type LogBackend struct {
// contains filtered or unexported fields
}
LogBackend is the built-in, always-available notification backend. It writes notifications either as plain lines to an io.Writer or as structured records through log/slog, and depends on nothing outside the standard library. It is registered under the type "log", and is the floor every beacon.Config can fall back to when no other channel is configured or reachable.
func NewLogBackend ¶
func NewLogBackend(w io.Writer) *LogBackend
NewLogBackend returns a LogBackend that writes one formatted line per notification to w.
func NewSlogBackend ¶
func NewSlogBackend(logger *slog.Logger) *LogBackend
NewSlogBackend returns a LogBackend that emits each notification as a structured record through logger, at a level matching Notification.Level.
func (*LogBackend) Send ¶
func (l *LogBackend) Send(ctx context.Context, n Notification) error
Send writes n to the configured writer or slog logger. It never returns an error: the log backend is the always-on floor and is not allowed to be the reason a notification is lost.
type MatrixBackend ¶
type MatrixBackend struct {
// contains filtered or unexported fields
}
MatrixBackend sends notifications to a Matrix room as a bot user, via the client-server API's room-send endpoint. It only sends: the bot account named by token_secret must already be joined to the room, since this backend has no way to accept or act on an invite.
func (*MatrixBackend) Send ¶
func (b *MatrixBackend) Send(ctx context.Context, n Notification) error
Send PUTs n to the room-send endpoint for the configured room, combining Title and Body into the message's "body" field. Every call generates a fresh transaction ID: Matrix homeservers deduplicate room-send requests by (access token, transaction ID), so reusing one across sends would cause every notification after the first to be silently dropped instead of posted.
type MattermostBackend ¶
type MattermostBackend struct {
// contains filtered or unexported fields
}
MattermostBackend sends notifications to a Mattermost incoming webhook. Mattermost's incoming webhooks accept the same JSON shape as Slack's, so this backend reuses buildSlackPayload from slack.go rather than duplicating it.
func (*MattermostBackend) Name ¶
func (b *MattermostBackend) Name() string
Name returns "mattermost".
func (*MattermostBackend) Send ¶
func (b *MattermostBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the configured Mattermost incoming webhook.
type Notification ¶
type Notification struct {
// Title is a short summary line.
Title string
// Body is the longer message, if any.
Body string
// Level is the severity, used both for display and for routing: a
// channel only receives notifications at or above its MinLevel.
Level Level
// Tags are free-form labels a backend may use for routing or display
// (e.g. topic names for ntfy).
Tags []string
// Fields are structured key/value details a backend may render
// alongside the body (e.g. a service name, a duration, an exit code).
Fields map[string]string
}
Notification is one alert to send to the channels people watch.
type NtfyBackend ¶
type NtfyBackend struct {
// contains filtered or unexported fields
}
NtfyBackend sends notifications to an ntfy server (ntfy.sh or self-hosted) as a plain HTTP POST to a topic.
func (*NtfyBackend) Send ¶
func (b *NtfyBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the configured ntfy topic. The request body is n.Body, falling back to n.Title if there is no body. Title, Tags, and Priority are sent as ntfy headers.
type PushoverBackend ¶
type PushoverBackend struct {
// contains filtered or unexported fields
}
PushoverBackend sends notifications through Pushover.
func (*PushoverBackend) Send ¶
func (b *PushoverBackend) Send(ctx context.Context, n Notification) error
Send posts n to the Pushover messages API. Message is required by Pushover, so Send falls back to Title when Body is empty. Priority is deliberately capped below Pushover's emergency tier (2), which requires additional retry/expire parameters this backend does not manage.
type SMTPBackend ¶
type SMTPBackend struct {
// contains filtered or unexported fields
}
SMTPBackend sends notifications as email through an SMTP relay.
func (*SMTPBackend) Send ¶
func (b *SMTPBackend) Send(ctx context.Context, n Notification) error
Send dials the configured relay and delivers n as an email. Credentials, when configured, are resolved fresh on every call so rotating them never requires a rebuild or restart.
type SecretResolver ¶
SecretResolver resolves a secret by name to its value. The host program supplies one so beacon never assumes where secrets live. A nil resolver is treated as "no secrets available": New replaces it with a resolver that returns an error for every name, so backend and sink factories can call resolve unconditionally.
type SinkFactory ¶
type SinkFactory func(settings map[string]string, resolve SecretResolver) (TelemetrySink, error)
SinkFactory builds a TelemetrySink from its configured settings, with the same resolve contract as BackendFactory.
type SlackBackend ¶
type SlackBackend struct {
// contains filtered or unexported fields
}
SlackBackend sends notifications to a Slack incoming webhook.
func (*SlackBackend) Send ¶
func (b *SlackBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the configured Slack incoming webhook.
type TelegramBackend ¶
type TelegramBackend struct {
// contains filtered or unexported fields
}
TelegramBackend sends notifications through a Telegram bot to a chat.
func (*TelegramBackend) Send ¶
func (b *TelegramBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the bot's sendMessage endpoint. Title and Body are combined into a single text field, since Telegram has no separate subject.
type TelemetryConfig ¶
type TelemetryConfig struct {
// Type selects the sink, matching a name passed to RegisterSink
// (e.g. "gatus").
Type string
// Settings is sink-specific configuration, with the same
// secret-naming and send-time resolution convention as
// ChannelConfig.Settings.
Settings map[string]string
}
TelemetryConfig configures one telemetry sink.
type TelemetrySink ¶
type TelemetrySink interface {
// Name identifies this sink instance, typically its registered type.
Name() string
// Report pushes a health result to this sink.
Report(ctx context.Context, h Health) error
}
TelemetrySink is one telemetry target: a monitor that wants health and status pushed to it on a schedule or on change, such as a Gatus external endpoint.
type WebhookBackend ¶
type WebhookBackend struct {
// contains filtered or unexported fields
}
WebhookBackend sends notifications as a JSON POST to an arbitrary URL, for services with no dedicated backend of their own. If a signing secret is configured, the request carries an X-Beacon-Signature header so the receiver can verify it came from this beacon.
func (*WebhookBackend) Send ¶
func (b *WebhookBackend) Send(ctx context.Context, n Notification) error
Send POSTs n to the configured URL as a webhookPayload. The body is marshaled once, so a configured signature is guaranteed to match the exact bytes transmitted.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package beacontest provides Capture, a capturing beacon.Backend, and New, a *beacon.Beacon wired to it.
|
Package beacontest provides Capture, a capturing beacon.Backend, and New, a *beacon.Beacon wired to it. |