Skip to content

Hosting: monitoring#

This documentation applies to Piler enterprise edition 2.2.5+

Revision #3

Publication date: 2026-OCT-27

piler-ui exposes its metrics in the Prometheus text format at /metrics, and a health check at /healthz (503 when MariaDB, Manticore or Redis is down). Any monitoring system that reads Prometheus metrics can use them: Prometheus, Grafana Cloud, VictoriaMetrics, Datadog, Zabbix, Checkmk and others.

The monitoring example has the full list of metrics, alert rules with tests, and a Grafana Cloud setup with Alloy and a dashboard.

What to scrape#

  • A single node: its piler-ui (port 3000).
  • Multi-node: the master's piler-ui, and every worker's piler-ui on the private network. The per-tenant metrics come from the workers, where the emails and indexes are, the quota metrics from the master.

/metrics and /healthz answer only the addresses in ALLOWED_CIDRS: add your scraper's. Scrape piler-ui directly: a request through a reverse proxy counts only from a proxy in TRUSTED_PROXIES, as the client address in its PROXY_HEADER (default X-Forwarded-For), and a forwarded request from any other address is refused.

What matters most#

Watch Metric Why
Each tenant's email keeps arriving piler_tenant_messages_received grows A customer's journaling rule or the path to piler-smtp broke: their email is missing from the archive. The most important alert for a hoster.
No email is stuck piler_archive_messages_total{result="error"}, piler_error_dir_files An email the piler daemon can't archive goes to the error directory: it's not in the archive until it's processed again
The daemon keeps up piler_queue_files, the rate of piler_archive_messages_total Emails waiting while the daemon processes none: it's stopped, or MariaDB or Manticore is down
S3 uploads keep up piler_s3_uploads_total{result="error"}, piler_s3_queue_oldest_age_seconds Until the upload an email is only on the node's local disk, and the archive can't read it
Archive and index size per tenant piler_tenant_stored_bytes, piler_index_disk_bytes Capacity planning and billing
Tenants within their quotas piler_tenant_quota_used / piler_tenant_quota_limit Over 1: raise the quota or bill the overage. See below
piler-ui answers up of the scrape
The tenant metrics are fresh piler_tenant_metrics_last_success_timestamp_seconds The collector runs every minute; piler-ui logs a failing tenant
Disk disk_used_bytes / disk_size_bytes The store disk; with S3 storage, watch the MariaDB and Manticore volumes with a host exporter
MariaDB connections, HTTP errors, request time db_connections_utilization_percent, http_requests_by_status_class, http_request_duration_seconds

The piler daemon and s3uploader write their metrics to the Redis of REDIS_ADDR, and piler-ui serves them with its own: on a multi-node deployment each worker's piler-ui has those of its node.

A tenant with little email may be quiet for hours: set the "journaling stopped" window per tenant if needed.

Quotas#

The master's piler-ui (a single node's) has the quotas of every tenant from the quota snapshot, collected every 15 minutes:

Metric
piler_tenant_quota_used{tenant,quota} The usage: quota="storage" in bytes, "emails", "users" (active users, see billing)
piler_tenant_quota_limit{tenant,quota} The quota, only those set: an unlimited quota has no series
piler_tenant_quota_age_seconds{tenant} Age of the tenant's usage
piler_quota_snapshot_age_seconds Age of the snapshot

When a worker doesn't answer the master, the usage of the others is too low, and a quota alert would resolve while the worker is down: the metrics keep the tenant's last usage collected from every worker, and its age grows. The example alerts: a tenant over a quota or over 90% of it for an hour, the snapshot or a tenant's usage over an hour old. With several masters each serves the same values.

Logs#

The containers log to stdout in JSON: collect them with your log system (the Grafana Cloud example sends them to Loki). piler logs every archived email (stored metadata id=..., message id=...), and errors with the reason.