Monitoring daemon for Redis server's `MONITOR` with logs and alerts
1.3K
Redis Watcher is a small, production-minded daemon that subscribes to a Redis
server's MONITOR stream, parses every command it observes and forwards the
result to logs, Prometheus metrics, and alert channels (Telegram,
generic webhooks, Prometheus Pushgateway).
Caution
**Performance note** — `MONITOR` is expensive on busy Redis instances because the server has to serialize every command into ASCII for the watcher. Use Redis Watcher on a side replica or on hosts where the additional CPU cost is acceptable. See [Redis docs on MONITOR](https://redis.io/docs/latest/commands/monitor/).
MONITOR events with automatic exponential-backoff reconnectFLUSH*, CONFIG, ACL, KEYS,
EVAL, SCRIPT, SHUTDOWN, DEBUG, …) with per-(command, IP) rate
limiting; delivered via Telegram, webhook, or Pushgateway +--------------------+
| Redis (MONITOR) |
+---------+----------+
|
v
+----------+----------+
| monitor.Client |
| (RESP, reconnect) |
+----------+----------+
|
events chan *Event
|
v
+--------+--------+
| Dispatcher |
+--------+--------+
|
+-------------------------+-------------------------+
| | |
v v v
+---------------+ +-----------------+ +-----------------+
| Prom metrics | | Outputs | | Alert engine |
| /metrics:9100 | | file/stdout/ | | Telegram / |
| | | UDP / TCP | | Webhook / PGW |
+---------------+ +-----------------+ +-----------------+
Each sink runs in its own goroutine with a bounded buffered channel. When
pipeline.drop_on_full: true (recommended), a slow downstream cannot back
up the MONITOR consumer.
git clone https://github.com/hatamiarash7/Redis-Watcher.git
cd Redis-Watcher
cp config.example.yaml config.yaml # edit to taste
make build
./bin/redis-watcher --config config.yaml
cp config.example.yaml config.yaml
make docker-compose-up
curl http://localhost:9100/metrics # metrics
docker logs -f rw-watcher # process logs
The compose stack starts a Redis instance with both a TCP port and a unix socket (shared via a named volume) so the watcher can connect over either transport.
Configuration is loaded in this order (later sources override earlier ones):
--config (or REDIS_WATCHER_CONFIG)REDIS_WATCHER_See config.example.yaml for an exhaustive,
commented example.
| Variable | Purpose |
|---|---|
REDIS_WATCHER_CONFIG | Path to the config file |
REDIS_WATCHER_REDIS_NETWORK | unix or tcp |
REDIS_WATCHER_REDIS_ADDRESS | Socket path or host:port |
REDIS_WATCHER_REDIS_PASSWORD | AUTH password (avoid checking-in) |
REDIS_WATCHER_LOG_LEVEL | debug, info, warn, error |
REDIS_WATCHER_METRICS_ADDRESS | host:port to expose metrics on |
REDIS_WATCHER_SENTRY_DSN | Sentry DSN |
REDIS_WATCHER_ALERTS_TELEGRAM_BOT_TOKEN | Telegram bot token |
REDIS_WATCHER_ALERTS_TELEGRAM_CHAT_ID | Telegram chat ID |
REDIS_WATCHER_ALERTS_WEBHOOK_URL | Webhook URL |
REDIS_WATCHER_ALERTS_PUSHGATEWAY_URL | Pushgateway URL |
In Redis Sentinel deployments the primary may move between hosts at any time. Running Redis Watcher on every node would duplicate audit trails across the fleet and trigger spurious alerts from the replication command stream itself. Also, the real source IP:PORT will be shown only when the instance is master
Redis Watcher therefore ships with a built-in role detector. It probes
the upstream Redis with INFO replication every few seconds:
role_check:
enabled: true
interval: 5s
dial_timeout: 3s
read_timeout: 3s
allow_replica: false # set to true only for debugging or non-Sentinel setups
Observability:
redis_watcher_redis_is_master # gauge: 1=master, 0=replica
redis_watcher_redis_role_info{role="master"} # 1 for the currently observed role
redis_watcher_redis_role_transitions_total{from,to} # counter of role flips
Deployment pattern: install Redis Watcher as a sidecar on every node
that can become a primary (e.g. as a DaemonSet, or alongside each Redis
unit in your service manager). With role_check enabled this is safe:
only one Redis Watcher in the cluster will actively audit at any time,
and the active one automatically follows the primary across failovers.
Busy production hosts emit a lot of PING, INFO, AUTH, SELECT,
SUBSCRIBE and similar housekeeping traffic that is almost never worth
auditing. Use the top-level filter section to drop these commands as
early as possible:
filter:
ignored_commands:
- PING
- INFO
- AUTH
- SELECT
- HELLO
- COMMAND
- SUBSCRIBE
- UNSUBSCRIBE
- PSUBSCRIBE
- PUNSUBSCRIBE
Matching is case-insensitive on the command name (the first token of the
Redis command). Listing a parent command like CLIENT also silences every
CLIENT <subcommand> invocation.
Filtered events do not reach outputs, metrics or alerts. They are counted
separately in redis_watcher_ignored_events_total{command="..."} so you
can still verify the filter is doing what you expect.
Note
`filter.ignored_commands` is the right knob for silencing noise. `metrics.ignored_commands` is a narrower setting that only suppresses Prometheus labels while still writing the event to outputs and the alert engine -- useful if you want to keep audit logs for, say, `PING` but not pay the metric-cardinality price.
All metrics are exposed at /metrics on the configured metrics.address
(default :9100). Notable series:
| Metric | Type | Labels |
|---|---|---|
redis_watcher_commands_total | counter | command, db |
redis_watcher_commands_by_ip_total | counter | command, source_ip |
redis_watcher_commands_by_db_total | counter | db |
redis_watcher_suspicious_commands_total | counter | command, source_ip |
redis_watcher_alerts_sent_total | counter | channel, command |
redis_watcher_alert_send_errors_total | counter | channel |
redis_watcher_dropped_events_total | counter | consumer |
redis_watcher_ignored_events_total | counter | command |
redis_watcher_monitor_reconnects_total | counter | — |
redis_watcher_parse_errors_total | counter | — |
redis_watcher_events_processed_total | counter | — |
redis_watcher_build_info | gauge | version, commit |
redis_watcher_redis_is_master | gauge | — |
redis_watcher_redis_role_info | gauge | role |
redis_watcher_redis_role_transitions_total | counter | from, to |
Health endpoints /healthz and /readyz are also exposed for liveness /
readiness probes.
Warning
If you operate Redis with many client IPs, set `metrics.track_source_ip: false` to keep per-command time series cardinality bounded.
The alert engine matches each event against:
alerts.suspicious_commands — exact command names (e.g. FLUSHALL,
CONFIG). For commands that route by subcommand (CONFIG, CLIENT,
ACL, SCRIPT, …) the watcher exposes the joined name (e.g.
CONFIG SET) as the alert title.alerts.patterns — case-insensitive regular expressions applied to
the reconstructed command line.Rate limiting is applied per (command, source_ip) tuple. When the rate is
exceeded the event is recorded in metrics but not pushed downstream.
network: unix when watching the local instance — no port, no
network round-trip, easier filesystem permissions.metrics.track_source_ip: false if clients use many IPs.pipeline.drop_on_full: true. Back-pressuring MONITOR causes
Redis to drop the watcher./metrics, alert on:
rate(redis_watcher_dropped_events_total[5m]),
rate(redis_watcher_monitor_reconnects_total[5m]) > 0,
rate(redis_watcher_suspicious_commands_total[5m]).monitor, metrics_server, and
outputs components.unixsocketperm 770 in redis.conf).make tidy # go mod tidy
make fmt # go fmt + goimports
make vet lint # static checks
make test # unit tests with race detector
make test-cover # unit tests + coverage report
make test-integration # against a running Redis instance
make docker # build the OCI image
See Makefile for the full list of targets.
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/my-new-featuremake install-devmake checkgit commit -am 'Add some feature'git push origin feature/my-new-featureFound a bug or have a suggestion? Please open an issue.
Content type
Image
Digest
sha256:e357a8ea5…
Size
5.6 MB
Last updated
4 months ago
docker pull hatamiarash7/redis-watcher