- Go 67.6%
- HTML 32.4%
| templates | ||
| config.go | ||
| config_example.json | ||
| go.mod | ||
| LICENSE | ||
| main.go | ||
| monitor.go | ||
| notifier.go | ||
| README.md | ||
| web.go | ||
Stream Monitor
Monitors audio streams for silence using ffmpeg, sends Telegram alerts when silence exceeds a configurable threshold, and records silence durations to Graphite.
Licensed under the GNU Affero General Public License v3.0. See LICENSE.
Prerequisites
- Go 1.21+
- ffmpeg installed and available in PATH
Configuration
Edit config.json:
{
"telegram": {
"enabled": true,
"bot_token": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"chat_id": "-1001234567890"
},
"graphite": {
"host": "127.0.0.1",
"port": 2003,
"metric_prefix": "stream.monitor"
},
"alert_message_template": "{{.Name}} Silence was detected.",
"resolve_message_template": "RESOLVED {{.Name}} Silence lasted for {{.Duration}} seconds.",
"streams": [
{
"name": "Radio Stream",
"url": "https://example.com/stream.mp3",
"silence_threshold_seconds": 30,
"noise_level": "-30dB"
}
],
"notify_stream_start": true,
"notify_stream_stop": true,
"notify_stream_recovery": true,
"notify_stream_failed": true,
"stream_start_template": "{{.Name}} started monitoring",
"stream_stop_template": "{{.Name}} stopped monitoring",
"stream_recovery_template": "{{.Name}} stream recovered",
"stream_failed_template": "{{.Name}} failed after 3 consecutive errors",
"retry_interval_seconds": 300,
"uptime_interval_seconds": 600,
"admin_password": "",
"debug_telegram": true,
"debug_graphite": true,
"debug_http": true,
"start_notification_delay": 15,
"http_port": 8080
}
| Field | Description |
|---|---|
telegram.enabled |
Enable/disable Telegram notifications (default true) |
telegram.bot_token |
Telegram bot token from @BotFather |
telegram.chat_id |
Chat/group ID to send alerts to |
graphite.host |
Graphite carbon host (omit to disable) |
graphite.port |
Graphite carbon plaintext port |
graphite.metric_prefix |
Prefix for all Graphite metric names (default: stream.monitor) |
alert_message_template |
Go template for silence alert (default: {{.Name}} Silence was detected.) |
resolve_message_template |
Go template for resolve message (default: RESOLVED {{.Name}} Silence lasted for {{.Duration}} seconds.) |
streams[].name |
Human-readable stream label |
streams[].url |
Stream URL passed to ffmpeg -i |
streams[].silence_threshold_seconds |
Seconds of silence before alerting |
streams[].noise_level |
Noise floor (e.g. -30dB) for ffmpeg silencedetect |
streams[].disabled |
Set to true to skip monitoring on startup |
admin_password |
Password to protect the admin interface (leave empty to disable auth) |
uptime_interval_seconds |
Interval between Graphite uptime reports (default 600) |
debug_telegram |
Log Telegram events when true |
debug_graphite |
Log Graphite events when true |
debug_http |
Log HTTP requests (method, path, remote addr) when true |
start_notification_delay |
Minimum seconds a stream must run before the start notification is sent (default 15) |
notify_stream_start |
Send Telegram alert when a stream starts (default true) |
notify_stream_stop |
Send Telegram alert when a stream stops (default true) |
notify_stream_recovery |
Send Telegram alert when a failed stream recovers (default true) |
stream_recovery_template |
Go template for stream recovery (default: {{"{{.Name}}"}} stream recovered); variables {{"{{.Name}}"}}, {{"{{.URL}}"}}, {{"{{.Status}}"}} |
notify_stream_failed |
Send Telegram alert on the 3rd consecutive failure (default true) |
stream_failed_template |
Go template for stream failed state (default: {{"{{.Name}}"}} failed after 3 consecutive errors) |
retry_interval_seconds |
Delay between connection attempts after 3 consecutive failures (default 300) |
http_port |
Web dashboard port (default 8080) |
Usage
./streammonitor -config config.json
Telegram Alerts
Messages are rendered using Go text/template. Available variables:
| Variable | Description |
|---|---|
{{.Name}} |
Stream name (both alert and resolve) |
{{.Duration}} |
Silence duration in seconds (resolve only) |
{{.Threshold}} |
Silence threshold in seconds (both alert and resolve) |
{{.Status}} |
Current stream status: Silence! or OK (both alert and resolve) |
{{.Timestamp}} |
Detection timestamp as time.Time (both alert and resolve) — use {{.Timestamp.Format "2006-01-02 15:04:05"}} to format |
Defaults:
- Alert:
{{.Name}} Silence was detected. - Resolve:
RESOLVED {{.Name}} Silence lasted for {{.Duration}} seconds.
Examples of custom templates:
🔇 {{.Name}} went silent✅ {{.Name}} back after {{printf "%.1f" .Duration}}s of silence[{{.Timestamp.Format "15:04:05"}}] {{.Name}} — {{.Status}}
Notification delivery is best-effort; errors are logged. Configure templates in the admin page or directly in config.json.
Graphite Metrics
On each resolved silence event, a metric is sent:
<metric_prefix>.<sanitized_name>.silence <seconds> <unix_timestamp>
Additionally, uptime and bitrate are reported periodically (configurable via uptime_interval_seconds, default 600s / 10 min) for each active stream:
<metric_prefix>.<sanitized_name>.uptime <seconds> <unix_timestamp>
<metric_prefix>.<sanitized_name>.bitrate <kbps> <unix_timestamp>
The metric prefix defaults to stream.monitor and is configurable via graphite.metric_prefix in the config or admin page.
The timestamp is the wall-clock time when the silence was first detected.
Web Interface
Open http://localhost:8080 in a browser.
Dashboard (/): Shows per-stream state (Monitoring / Alerting / Failed / Inactive / Disabled) alongside stream status (OK / Silence!), last alert and resolve times, last silence duration, and stream errors. Enable/disable buttons are shown only when authenticated (or when auth is disabled). Auto-refreshes every 10 seconds.
Admin (/admin): Configure the application at runtime. All changes persist to config.json immediately.
- Settings — Update Telegram bot token, chat ID, Graphite host/port, metric prefix, message templates, stream event notification templates, retry interval, uptime interval, HTTP port, admin password, and debug logging (Telegram/Graphite independently). Note: port changes require a restart.
- Auth — When
admin_passwordis set in config or settings, the admin page is protected by a session-based login. Accessing/adminor any admin action redirects to/admin/login. - Streams — Add, edit, enable, disable, and delete streams without restarting the application
- Editing a stream (including renaming) stops the old ffmpeg process and starts a new one with the updated config
- Enable/disable toggles stop/start monitoring without removing the stream from config
- When auth is enabled, enable/disable buttons on the dashboard are hidden for unauthenticated users
JSON API (/api/status): Returns per-stream status for programmatic access.
Build from Source
go build -o streammonitor .
Routes
| Path | Method | Description |
|---|---|---|
/ |
GET | Status dashboard |
/api/status |
GET | Stream statuses as JSON |
/admin/login |
GET/POST | Admin login page |
/admin/logout |
POST | Log out of admin |
/admin |
GET | Admin configuration page (auth required) |
/admin/settings |
POST | Update Telegram/Graphite settings (auth required) |
/admin/streams/add |
POST | Add a new stream (auth required) |
/admin/streams/edit |
POST | Edit an existing stream (auth required) |
/admin/streams/delete |
POST | Remove a stream (auth required) |
/admin/streams/enable |
POST | Enable a disabled stream (auth required) |
/admin/streams/disable |
POST | Disable an active stream (auth required) |