Prometheus exporter for rustic/restic backup.
Originally I would like to craft a restic-exporter supporting multiple backup repositories because of the issue. After checking the code, I found restic do not separate its library from the CLI. This forces downstream user to rely on subprocess binary calls, which causes additional maintaince overhead. So, I switched gears to rustic, and started this project.
The backup client should use restic >= v0.17, or metrics like rustic_snapshot_size_bytes will be dropped.
Two image variants are available:
- Distroless (default):
ghcr.io/timtorchen/rustic-exporter:latest - Alpine:
ghcr.io/timtorchen/rustic-exporter:latest-alpine- Includes openssh-client for SSH-based remote repositories
Both variants support linux/amd64 and linux/arm64 platforms.
Usage: rustic-exporter [OPTIONS] --config <CONFIG>
Options:
-i, --interval <INTERVAL> Metrics collection frequency in seconds [default: 300]
--log-level <LOG_LEVEL> Log level [default: info] [possible values: debug, info, warn, error]
-o, --output <OUTPUT> output format [default: text] [possible values: text, json]
-c, --config <CONFIG> Path to the configuration file
--defensive Enable defensive check to detect unexpected empty snapshots
--host <HOST> Server host [default: 0.0.0.0]
--port <PORT> Server port [default: 8080]
-h, --help Print help
-V, --version Print version
The configuration file is in TOML format, and follows the rustic supported services. You can also interpolate
environment variables in the configuration file using a ${VARIABLE} syntax. They are interpolated and replaced into the configuration file at runtime.
# Local backend
[[backup]]
repository = "/local-path/to/backup"
password = "test"
[backup.options]
# OpenDAL backend for AWS S3
[[backup]]
repository = "opendal:s3"
password_file = "/path/to/password/file"
[backup.options]
## set OpenDAL AWS S3 service configurations in the form of key-value
## https://opendal.apache.org/docs/rust/opendal/services/struct.S3.html#configuration
endpoint = "https://s3.west-2.amazonaws.com"
access_key_id = "${ACCESS_KEY_ID}"
secret_access_key = "${SECRET_ACCESS_KEY}"
bucket = "bucket-name"
root = "/"
region = "auto"
# OpenDAL backend for Google Cloud Storage
[[backup]]
repository = "opendal:gcs"
password = "test"
[backup.options]
## https://opendal.apache.org/docs/rust/opendal/services/struct.Gcs.html#configuration
endpoint = "https://storage.googleapis.com"
credential = "base64-encoded-json"
bucket = "bucket-name"
root = "/"
# OpenDAL backend for Azure Blob Storage
[[backup]]
repository = "opendal:azblob"
password = "test"
[backup.options]
## https://opendal.apache.org/docs/rust/opendal/services/struct.Azblob.html#configuration
endpoint = "https://account-name.blob.core.windows.net"
account_name = "account-name"
account_key = "account-key"
container = "container-name"
root = "/"
# OpenDAL backend for Google Drive
[[backup]]
repository = "opendal:gdrive"
password = "test"
[backup.options]
## https://opendal.apache.org/docs/rust/opendal/services/struct.Gdrive.html#configuration
access_token = "access-token"
root = "/"
# OpenDAL backend for SFTP
[[backup]]
repository = "opendal:sftp"
password = "test"
[backup.options]
## https://opendal.apache.org/docs/rust/opendal/services/struct.Sftp.html#configuration
endpoint = "ssh://user@hostname:port"
root = "/remote-path/to/backup"# HELP rustic_repository_info Repository information.
# TYPE rustic_repository_info gauge
rustic_repository_info{repo_name="test",repo_id="3b0165bb",version="2"} 1
# HELP rustic_snapshot_info Snapshot inforamation.
# TYPE rustic_snapshot_info gauge
rustic_snapshot_info{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5",paths="data",hostname="air",username="",tags="",program_version="rustic 0.11.0"} 1
rustic_snapshot_info{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981",paths="data",hostname="air",username="",tags="",program_version="rustic 0.11.0"} 1
# HELP rustic_snapshot_files_total Total files in a snapshot.
# TYPE rustic_snapshot_files_total gauge
rustic_snapshot_files_total{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 1
rustic_snapshot_files_total{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 2
# HELP rustic_snapshot_timestamp Snapshot creation time in unix timestamp.
# TYPE rustic_snapshot_timestamp gauge
rustic_snapshot_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 1780212689.337172
rustic_snapshot_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 1780214434.184508
# HELP rustic_snapshot_size_bytes Snapshot size in bytes.
# TYPE rustic_snapshot_size_bytes gauge
rustic_snapshot_size_bytes{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 3072
rustic_snapshot_size_bytes{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 1024
# HELP rustic_snapshot_backup_start_timestamp Backup start time of a snapshot in unix timestamp.
# TYPE rustic_snapshot_backup_start_timestamp gauge
rustic_snapshot_backup_start_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 1780214434.190304
rustic_snapshot_backup_start_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 1780212689.345597
# HELP rustic_snapshot_backup_end_timestamp Backup finished time of a snapshot in unix timestamp.
# TYPE rustic_snapshot_backup_end_timestamp gauge
rustic_snapshot_backup_end_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 1780214434.231709
rustic_snapshot_backup_end_timestamp{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 1780212689.397221
# HELP rustic_snapshot_backup_duration_seconds Backup duration of a snapshot.
# TYPE rustic_snapshot_backup_duration_seconds gauge
rustic_snapshot_backup_duration_seconds{repo_name="test",repo_id="3b0165bb",snapshot_id="f797d9b5"} 0.041405
rustic_snapshot_backup_duration_seconds{repo_name="test",repo_id="3b0165bb",snapshot_id="9e3db981"} 0.051624
# EOF
