https://github.com/filippofinke/docker-events
๐ Real-time docker events notifications
https://github.com/filippofinke/docker-events
discord docker docker-events events notifications real-time slack status stream uptime
Last synced: about 2 months ago
JSON representation
๐ Real-time docker events notifications
- Host: GitHub
- URL: https://github.com/filippofinke/docker-events
- Owner: filippofinke
- License: mit
- Created: 2025-09-30T14:16:55.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-09-30T14:20:26.000Z (9 months ago)
- Last Synced: 2025-10-08T23:39:06.954Z (9 months ago)
- Topics: discord, docker, docker-events, events, notifications, real-time, slack, status, stream, uptime
- Language: Go
- Homepage: https://github.com/filippofinke/docker-events
- Size: 38.1 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
> Watch Docker events in real-time and dispatch rich notifications with a lightweight Go service.
This project uses docker system events and forwards meaningful summaries through configurable notification channels powered by [`nikoksr/notify`](https://github.com/nikoksr/notify). It is designed to be small, dependable, and easy to extend with new transports or event processing rules.
## Features
- [x] Real-time streaming of `docker system events` via a managed watcher
- [x] Human-friendly notifications enriched with context (timestamp, actor attributes, status)
- [x] Multi-channel delivery (Slack, Telegram, Discord) powered by `github.com/nikoksr/notify`
- [x] Opt-in filtering by Docker event types and CLI filters
- [x] Environment variable driven configuration with validation at startup
- [x] Composable code structure (config, watcher, notifier) and unit tests for formatting helpers
## Quick Start
Prerequisites
- Go 1.24+
- Docker CLI with access to the target daemon
- At least one notifications provider configured (Slack bot token + channel IDs, Telegram bot token + chat IDs, Discord bot token + channel IDs, or Discord webhook URLs)
Clone & install dependencies
```bash
git clone https://github.com/filippofinke/docker-events.git
cd docker-events
go mod tidy
```
Configure environment
1. Copy the example environment file:
```bash
cp .env.example .env
```
2. Update `.env` with your Slack token, target channels, and any optional Docker filters.
Run locally
```bash
# start the watcher (module-aware path)
go run ./cmd
```
The service will stream logs to stdout and post notifications for matching Docker events. Stop with `Ctrl+C`.
## Configuration
All settings are provided via environment variables (see `.env.example`). Key options:
- `SLACK_BOT_TOKEN`: Slack bot token used to authenticate the notifier.
- `SLACK_CHANNEL_IDS`: Comma-separated list of Slack channel IDs (e.g. `C0123456,C0ABCDEF`).
- `TELEGRAM_BOT_TOKEN`: Telegram bot token created with [BotFather](https://core.telegram.org/bots#6-botfather).
- `TELEGRAM_CHAT_IDS`: Comma-separated list of chat IDs (negative values for group chats are supported).
- `DISCORD_BOT_TOKEN`: Discord bot token generated from the Developer Portal.
- `DISCORD_CHANNEL_IDS`: Comma-separated list of Discord channel IDs to notify.
- `DISCORD_WEBHOOK_URLS`: Comma-separated list of Discord webhook URLs (recommended over bot tokens for simple notifications).
- `NOTIFY_SUBJECT_PREFIX`: Prefix for notification subjects (defaults to `Docker event`).
- `MESSAGE_TEMPLATE`: Custom message template using Go template syntax (see [Message Customization](#message-customization) below).
- `MESSAGE_LOG_LINES`: Number of container log lines to fetch for events (defaults to 0, disabled).
- `EVENT_GROUP_WINDOW`: Time window for grouping events from the same container (e.g., `5s`, `10s`, `1m`). Events for the same container within this window will be grouped into a single notification. Set to `0` to disable grouping (defaults to `5s`).
- `DOCKER_EVENT_FILTERS`: Comma-separated filters passed to `docker system events` (same syntax as the CLI `--filter` flag, e.g. `status=start,type=container`).
- `DOCKER_EVENT_TYPES`: Comma-separated list of Docker event types to keep (e.g. `container,image,volume`).
> **Security note:** Do not commit an `.env` file containing real tokens. Use `.env` locally or provide the variables through your orchestrator of choice.
## Docker Event Filters
The Docker CLI supports a rich set of filters that can be combined in `DOCKER_EVENT_FILTERS`. Supported filter keys include:
- `config=`
- `container=`
- `daemon=`
- `event=`
- `image=`
- `label=` or `label==`
- `network=`
- `node=`
- `plugin=`
- `scope=`
- `secret=`
- `service=`
- `type=`
- `volume=`
Provide multiple filters by comma-separating entries (e.g. `DOCKER_EVENT_FILTERS=event=start,scope=swarm`); the service will translate each entry into an individual `--filter` flag for `docker system events`.
More details in the [Docker documentation](https://docs.docker.com/reference/cli/docker/system/events/#filter).
## Docker Event Types
`DOCKER_EVENT_TYPES` narrows processing to one or more top-level Docker object kinds. Valid values:
- `container`
- `image`
- `plugin`
- `volume`
- `network`
- `daemon`
- `service`
- `node`
- `secret`
- `config`
Leave the variable empty to accept every event type from the stream.
More details in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/system_events/#object-types).
## Event Grouping
To prevent notification spam when a container experiences multiple events in quick succession (e.g., during a restart: kill โ stop โ die โ start โ restart), docker-events can group events for the same container within a configurable time window.
### How It Works
When event grouping is enabled (default: 5 seconds), the service will:
1. Collect all events for the same container within the time window
2. Wait for the window to expire or for events from a different container
3. Send a single grouped notification with all events instead of individual messages
### Configuration
Set the `EVENT_GROUP_WINDOW` environment variable to control the grouping window:
```bash
EVENT_GROUP_WINDOW=5s # Default: group events within 5 seconds
EVENT_GROUP_WINDOW=10s # Group events within 10 seconds
EVENT_GROUP_WINDOW=1m # Group events within 1 minute
EVENT_GROUP_WINDOW=0 # Disable grouping, send all events immediately
```
Valid time units: `ns`, `us` (or `ยตs`), `ms`, `s`, `m`, `h`
### Grouped Notification Format
When multiple events are grouped, the notification will include:
- Container ID and total event count
- Time range (first to last event)
- Common attributes shared across all events
- List of all events with timestamps and actions
Example grouped notification:
```
Docker events: 5 events for container d23c731f32ba (die, kill, restart, start, stop)
Container: d23c731f32ba41defa48b2804299e9378b84442857701b1d51b8e6aca77c35da
Event count: 5
Time range: 2025-10-09T08:10:58Z to 2025-10-09T08:10:59Z
Common attributes:
- com.docker.compose.project=myapp
- com.docker.compose.service=web
- image=nginx:latest
Events:
1. [08:10:58] container kill
2. [08:10:59] container stop
3. [08:10:59] container die
4. [08:10:59] container start
5. [08:10:59] container restart
```
### Benefits
- **Reduced notification spam**: Restart operations typically generate 5+ events, which are now grouped into one message
- **Better context**: See all related events together with their timing
- **Cleaner notification channels**: Fewer messages to scroll through
- **Preserved details**: All event information is retained, just organized better
### Behavior Notes
- Single events are sent immediately (no grouping overhead)
- Events for different containers are never grouped together
- The timer resets each time a new event arrives for the same container
- On shutdown, all pending grouped events are flushed immediately
- **Custom templates are fully supported**: If you have a `MESSAGE_TEMPLATE` configured, it will be used for both single and grouped events. Use `{{.EventCount}}` and `{{.Events}}` in your template to handle grouped events differently.
## Message Customization
By default, docker-events sends detailed notifications with all available event information. You can customize the message format using Go templates via the `MESSAGE_TEMPLATE` environment variable.
### Available Template Placeholders
- `{{.Type}}` - Event type (container, image, volume, network, etc.)
- `{{.Action}}` - Event action (start, stop, create, destroy, etc.)
- `{{.ID}}` - Full object ID
- `{{.ShortID}}` - Short ID (first 12 characters)
- `{{.Name}}` - Container/object name (extracted from attributes when available)
- `{{.Status}}` - Event status
- `{{.From}}` - From field (typically the image name for container events)
- `{{.Time}}` - Event timestamp in RFC3339 format
- `{{.Scope}}` - Event scope (local or swarm)
- `{{.Actor.ID}}` - Actor ID
- `{{.Attribute "key"}}` - Get specific attribute value by key
- `{{.GetLogs}}` - Fetch container logs (requires `MESSAGE_LOG_LINES` > 0)
- `{{.EventCount}}` - Number of events (returns 1 for single events, >1 for grouped events)
- `{{.Events}}` - Array of all events (only available for grouped events; use with range)
**Note:** When events are grouped (multiple events for the same container), `{{.Type}}`, `{{.Action}}`, etc. refer to the first event in the group. Use `{{.Events}}` to access all events in the group.
### Template Examples
**Simple notification:**
```bash
MESSAGE_TEMPLATE="Container {{.Name}} ({{.ShortID}}) {{.Action}} at {{.Time}}"
```
**With container logs:**
```bash
MESSAGE_TEMPLATE="Container {{.Name}} {{.Action}}\nImage: {{.From}}\nLogs:\n{{.GetLogs}}"
MESSAGE_LOG_LINES=20
```
**Custom attributes:**
```bash
MESSAGE_TEMPLATE="{{.Type}} {{.Action}}: {{.Name}}\nProject: {{.Attribute \"com.docker.compose.project\"}}\nService: {{.Attribute \"com.docker.compose.service\"}}"
```
**Conditional formatting:**
```bash
MESSAGE_TEMPLATE="{{.Type}} {{.Action}}: {{if .Name}}{{.Name}}{{else}}{{.ShortID}}{{end}}\nTime: {{.Time}}"
```
**Grouped events with custom template:**
```bash
MESSAGE_TEMPLATE="{{if gt .EventCount 1}}๐ {{.EventCount}} events for {{.Name}} ({{.ShortID}})\n{{range .Events}}- [{{.Timestamp.Format \"15:04:05\"}}] {{.Action}}\n{{end}}{{else}}{{.Type}} {{.Action}}: {{.Name}}\nTime: {{.Time}}{{end}}"
EVENT_GROUP_WINDOW=5s
```
**Grouped events with logs:**
```bash
MESSAGE_TEMPLATE="Container: {{.Name}} ({{.ShortID}})\nEvents: {{.EventCount}}\n{{if gt .EventCount 1}}Actions: {{range .Events}}{{.Action}} {{end}}\n{{end}}{{if .GetLogs}}\nLogs:\n{{.GetLogs}}{{end}}"
MESSAGE_LOG_LINES=20
EVENT_GROUP_WINDOW=5s
```
### Logs Configuration
Set `MESSAGE_LOG_LINES` to fetch the last N lines of container logs when using `{{.GetLogs}}`:
```bash
MESSAGE_LOG_LINES=10 # Fetch last 10 lines
MESSAGE_LOG_LINES=50 # Fetch last 50 lines
MESSAGE_LOG_LINES=0 # Disable log fetching (default)
```
**Note:** Log fetching only works for container events and may add latency to notifications. Use reasonable line counts to avoid performance issues.
### Default Template
If no custom template is provided, the default format includes:
```
Time:
Status:
From:
Scope:
ID:
Actor:
```
## Discord Webhooks vs Bots
This project supports two methods for Discord notifications:
**Discord Webhooks (Recommended)**
Discord webhooks are the simplest way to send notifications. They use HTTP POST requests and don't require a bot session or gateway connection.
Advantages:
- Simpler setup - just create a webhook in your Discord channel settings
- No bot permissions or OAuth scopes needed
- More efficient - uses plain HTTP instead of maintaining a WebSocket connection
- Can send to multiple channels by providing multiple webhook URLs
To create a Discord webhook:
1. Open your Discord server and go to the channel where you want notifications
2. Click the gear icon (Edit Channel) next to the channel name
3. Go to "Integrations" โ "Webhooks" โ "New Webhook"
4. Copy the webhook URL and add it to `DISCORD_WEBHOOK_URLS`
Example:
```bash
DISCORD_WEBHOOK_URLS=https://discord.com/api/webhooks/123456789/your-webhook-token
```
**Discord Bot (Alternative)**
Bot tokens can be used if you need more advanced features or already have a bot infrastructure. Configure with `DISCORD_BOT_TOKEN` and `DISCORD_CHANNEL_IDS`.
You can also use both webhooks and bot tokens simultaneously if needed.
## Extending Notifications
`internal/notifier` wraps `github.com/nikoksr/notify`, so adding more destinations is straightforward:
1. Import the desired service package (e.g. `github.com/nikoksr/notify/service/telegram`).
2. Create a service instance in `Setup` based on new configuration.
3. Register it with the shared notifier (`n.client.UseServices(service)`).
## Running Tests
```bash
go test ./...
```
## Docker Usage
A minimal container image can be built with:
```bash
# build the Go binary locally and package it into a container image
docker build -t docker-events:latest .
```
The included `Dockerfile` uses a multi-stage build: it compiles a static Go binary in a Go builder image and copies it into the official Docker CLI image so the binary can call `docker` if needed.
Important runtime considerations:
- The service talks to the Docker daemon. In most deployments you should mount the host Docker socket into the container so the service can observe events:
- `/var/run/docker.sock:/var/run/docker.sock:ro` (read-only mount used in the example compose file)
- Environment variables are used for configuration. The repository contains a `.env.example`โcopy it to `.env` and set your provider tokens and channels. Do not commit `.env` with real secrets.
Compose example (loads `.env` automatically)
```yaml
services:
docker-events:
build: .
env_file:
- .env
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
```
Start with docker-compose:
```bash
# ensure .env exists in the project root (copy from .env.example)
cp .env.example .env
# build & start in background
docker compose up -d --build
# view logs
docker compose logs -f docker-events
```
If you prefer to run the image directly:
```bash
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro \
--env-file .env filippofinke/docker-events:latest
```
Remember: by default Docker Compose loads a top-level `.env` file. The `env_file` entry above is explicit and can be used by other tools that also support `env_file`.
## Author
๐ค **Filippo Finke**
- Website: [https://filippofinke.ch](https://filippofinke.ch)
- Twitter: [@filippofinke](https://twitter.com/filippofinke)
- GitHub: [@filippofinke](https://github.com/filippofinke)
- LinkedIn: [@filippofinke](https://linkedin.com/in/filippofinke)