A tool for monitoring audio streams.
  • Go 67.6%
  • HTML 32.4%
Find a file
2026-05-21 00:23:29 +02:00
templates Added LICENSE 2026-05-21 00:17:47 +02:00
config.go Added LICENSE 2026-05-21 00:17:47 +02:00
config_example.json Fixed process failure to backoff and alerting 2026-05-19 11:24:30 +02:00
go.mod Fixed process failure to backoff and alerting 2026-05-19 11:24:30 +02:00
LICENSE Added License 2026-05-21 00:17:28 +02:00
main.go Added LICENSE 2026-05-21 00:17:47 +02:00
monitor.go Added LICENSE 2026-05-21 00:17:47 +02:00
notifier.go Added LICENSE 2026-05-21 00:17:47 +02:00
README.md Added LICENSE 2026-05-21 00:17:47 +02:00
web.go Added LICENSE 2026-05-21 00:17:47 +02:00

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_password is set in config or settings, the admin page is protected by a session-based login. Accessing /admin or 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)