SYMONE performs system monitoring tasks:
-
Collect information, e.g. about cpu, memory, storage, temperature, containers
-
Format, e.g. convert to JSON or CSV
-
Publish, e.g. via MQTT
SYMONE is polite and reliable:
-
Runs in a Docker container to keep the system clean of dependencies
-
Does not need root permissions
-
Does her job regularly
Let’s suppose that SYMONE runs on a Raspberry Pi with hostname raspberry using the following configuration:
compose.ymlservices:
symone:
image: ghcr.io/git-developer/symone
container_name: symone
hostname: raspberry
init: true
restart: unless-stopped
user: "1000:44"
devices:
- /dev/vchiq
volumes:
- "./collectors:/opt/symone/host-collectors:ro"
- "/var/run/symone:/var/run/symone"
- "/lost+found:/mnt/root:ro"
- "/boot/System Volume Information:/mnt/boot:ro"
environment:
MQTT_OPTIONS: '-h broker-host'Result: every 5 minutes, she publishes a JSON message via MQTT to topic /symone/raspberry/json on broker broker-host:
{
"process": {
"load": {
"average1": 0.98,
"average5": 0.94,
"average15": 0.93
},
"memory": {
"total": "996096 kB",
"free": "98640 kB",
"available": "672800 kB"
}
},
"storage": {
"boot": {
"total": "262128 kB",
"use": "49263 kB",
"available": "212866 kB",
"use_relative": "19 %"
},
"root": {
"total": "14154680 kB",
"use": "7550664 kB",
"available": "5999948 kB",
"use_relative": "56 %"
}
},
"thermal": {
"cpu-thermal": {
"temperature": "54.768 °C"
}
},
"video-core": {
"soc": {
"temperature": "53.7 °C"
},
"core": {
"voltage": "1.2938 V"
}
}
}-
A linux system with
Docker Compose.
The Docker Compose documentation contains a comprehensive guide explaining several install options. On Debian-based systems, Docker Compose may be installed by calling
$ sudo apt install docker-compose-v2-
Create a configuration file
compose.yml(see the examples and docs for an inspiration) -
Optionally, when the host collector is used:
-
Add one or more collector scripts in
./collectors -
Install and start the
symone-host-service
-
-
Start SYMONE by calling
docker compose up -d
-
Collectors:
-
Process: cpu load, memory
-
Storage: storage use
-
Thermal: system temperatures
-
Video Core: temperature, voltage
-
Host: user-configurable info prepared on the Docker host
-
-
Formatters:
-
JSON
-
CSV
-
-
Publishers:
-
MQTT
-
stdout
-
-
Scheduling using a CRON expression
| Option | Description | Example | Default | Explanation |
|---|---|---|---|---|
|
Linux user and group |
|
none (effectively: |
This option is useful when statistics require a certain user or group. Example: In Pi OS (formerly Raspbian), user |
|
Devices for monitoring |
|
none |
This option is useful when statistics require access to a system device. Example: On a Raspberry Pi, |
|
Volumes for storage monitoring |
|
none |
Storage statistics are collected automatically for anything within |
|
Hostname |
|
none (effectively: hostname generated by Docker) |
The hostname is used as part of the MQTT topic when the option |
|
Additional host names |
|
none |
When the MQTT broker is running on the same host as SYMONE, the host has to be declared as |
| Option | Description | Example | Default |
|---|---|---|---|
|
Timezone |
|
none |
|
Schedule (a CRON expression) |
|
|
| Option | Description | Example | Default |
|---|---|---|---|
|
Enable JSON format |
|
|
|
Enable CSV format |
|
|
|
Item separator for CSV format |
|
|
| Option | Description | Example | Default |
|---|---|---|---|
|
Publish to stdout |
|
|
|
Publish via MQTT |
|
|
|
MQTT options |
|
none |
|
MQTT topic |
|
|
|
Append hostname to MQTT topic |
|
|
|
Append format to MQTT topic |
|
|
| Option | Description | Example | Default |
|---|---|---|---|
|
Collect info about system processes |
|
|
|
Collect info about system load |
|
|
|
Collect info about system memory |
|
|
|
Root directory for process info |
|
|
|
Collect info about storage |
|
|
|
Root directory for storage |
|
|
|
Collect info about thermal |
|
|
|
Root directory for thermal info |
|
|
|
Group thermal info by type |
|
|
|
Group thermal info by zone |
|
|
|
Collect video core info |
|
|
|
Collect info read from the host |
|
|
SYMONE contains an optional feature to collect info that is not available within the container. A common use case are statistics about all Docker containers running on the host.
To use this feature, you have to add two volumes and enable the symone-host-service.
compose.yml---
services:
symone:
volumes:
- '/var/run/symone:/var/run/symone'
- './collectors:/opt/symone/host-collectors:ro'/var/run/symone is a working directory that is used internally for communication between container and host.
./collectors is a directory for custom collectors.
A collector is an executable that is run by the symone-host-service on the host.
Its output is parsed and sent to publishers.
Each line of output is expected to contain one or more keys and a trailing value.
Non-executable files are skipped.
| Example | Configuration | Published output |
|---|---|---|
Simple command |
./collectors/simpleecho timestamp "$(date -u -Is)" |
{ "timestamp": "2025-04-13T10:42:34+00:00" } |
Multiple values |
./collectors/multiple-valuesfor roll in first second; do
printf 'dice %s-roll %s\n' \
"${roll}" "$(shuf -i 1-6 -n 1)"
done |
{
"dice": {
"first-roll":3,
"second-roll":5
}
} |
Post processing |
./collectors/post-processingset -a
LANG=C df -t tmpfs -h \
| tail -n +2 \
| while read fs total used available usage mountpoint; do
for field in total used available; do
printf 'tempfs-usage %s %s %s\n' \
"${mountpoint}" "${field}" "$(printenv "${field}")"
done
done |
{
"tempfs-usage": {
"/run": {
"total": "1,6G",
"used": "5,5M",
"available": "1,6G"
},
"/dev/shm": {
"total": "7,8G",
"used": 0,
"available": "7,8G"
},
"/run/lock": {
"total": "5,0M",
"used": 0,
"available": "5,0M"
}
}
} |
Container statistics |
./collectors/container-statistics#!/bin/sh
set -eua
fields='cpu_usage
memory_usage memory_limit
network_read network_written
block_read block_written
pid_count'
LANG=C
docker stats --no-stream --format \
"{{.Name}} {{.CPUPerc}} {{.MemUsage}} {{.NetIO}} {{.BlockIO}} {{.PIDs}}" \
| sed "s/kB\s/KB /g;s:/::g;s/\s\+/ /g" \
| numfmt --suffix B --field=3-8 --to-unit=1024 --from=auto --padding=1 \
| sed "s/B /kB /g" \
| while read -r container_name ${fields}; do
for field in ${fields}; do
printf '%s %s %s %s\n' \
"containers" "${container_name}" "${field}" "$(printenv "${field}")"
done
done |
{
"containers": {
"symone": {
"cpu_usage": "0.00%",
"memory_usage": "5.465MiB",
"memory_limit": "32MiB",
"network_read": "4.28kB",
"network_written": "8.41kB",
"block_read": "0B",
"block_written": "0B"
}
} |
Quoted values |
./collectors/quoted-valuescat - <<'EOF'
a "b" 'c d' $'e\nf'
EOF |
{
"a": {
"b": {
"c d": "e\nf"
}
}
} |
Commands configured for the host collector are executed by the symone-host-service.
It is running on the host and listening for requests from the container.
To download and install the symone-host-service to systemd, run
$ wget -O- https://github.com/git-developer/symone/raw/refs/heads/main/symone-host-service \
| install /dev/stdin ./symone-host-service \
&& sudo ./symone-host-service systemd-installThis will create, enable and start a minimal service unit in /etc/systemd/system that persists across boots. To uninstall it, run
$ sudo ./symone-host-service systemd-uninstallIt is possible to use the symone-host-service without systemd. It is a self-contained executable that offers subcommands to start, stop and show the status.
This section contains an example configuration to integrate SYMONE with FHEM.
-
Example for an MQTT broker running on
broker-host:1883:define mosquitto MQTT2_CLIENT broker-host:1883 define mqtt_symone_raspberrypi MQTT2_DEVICE attr mqtt_symone_raspberrypi readingList symone/raspberrypi/json:.* { json2nameValue($EVENT) } attr mqtt_symone_raspberrypi stateFormat video-core_soc_temperature
-
Trigger an immediate one-shot publish while SYMONE is running in a container named
symone:$ docker compose exec symone take-sample -
Example for a one-shot run to stdout (no MQTT) when SYMONE is not running:
$ docker compose run --rm -e PUBLISH_MQTT=false -e PUBLISH_STDOUT=true symone take-sample
SYMONE is prepared to be extended by additional collectors, formatters and publishers. To add something, simply mount a file or directory into the respective directory of the container.
-
Put an executable file within the directory
collect. This file is a collector. -
When SYMONE calls a collector, it may emit 0..n items by calling
${COLLECTOR_PUBLISHER}for each item and hand over the item as arguments:-
The last argument is treated as value of the item.
-
The last but one argument is treated as name of the item.
-
All preceding items are treated as group(s) for the item.
-
-
Put an executable file within the directory
format. This file is a formatter. The formatter’s filename is used as format id. -
When SYMONE calls a formatter, she hands over all collected items as arguments. Parts of an item are separated by spaces, quoted as required. Item parts may contain spaces, newlines and special characters.
-
The formatter is expected to print the formatted message to standard out.
SYMONE integrates the following applications and libraries: