Observability
Logging, metrics, distributed tracing, and health check endpoints
This page describes how to observe the health and behavior of Trilio Share Protection (Abacá) in production. It covers the Prometheus metrics that drive alerting and the admin panel, structured logging emitted by each service, and the health endpoints you can poll from your monitoring stack. Because a missed backup is the worst silent failure mode in a backup service, Abacá treats coverage as a first-class metric — not a derived report — so your alerting and the operator dashboard never disagree about what is protected.
Before configuring observability, ensure you have:
- Trilio Share Protection deployed with abaca-api and abaca-conductor running (OpenShift ≥ 4.12 or a Docker Compose dev stack)
- A Prometheus-compatible scrape target configured and reachable from your monitoring stack
- Access to the abaca-api service port (default 9797) from your Prometheus instance or load balancer
- (Optional) A SIEM or log aggregation platform (for audit-event ingestion)
- (Optional) CloudKitty or a compatible billing adapter (for chargeback integration with usage metrics)
- Python ≥ 3.11 and the python-abacaclient plugin installed if you want to inspect usage metrics from the CLI
- Operator-level Keystone credentials scoped to the service project if you intend to call authenticated endpoints
Observability in Abacá is built in — no separate agent or sidecar is required. The steps below connect your monitoring stack to the running services.
Step 1 — Verify the API service is reachable
Confirm that abaca-api is listening on its configured port:
curl -s http://<abaca-api-host>:9797/v1/service_info
Expected response (unauthenticated — this endpoint is public):
{
"service_user": {
"id": "<keystone-user-id>",
"name": "abaca"
},
"worker_project": {
"id": "<keystone-project-id>",
"name": "abaca"
}
}
If this call fails, check that the api.bind_host and api.bind_port configuration values match what your network rules allow.
Step 2 — Configure Prometheus to scrape Abacá metrics
Add a scrape job to your prometheus.yml. Abacá exposes a pull-based usage and operational metrics endpoint:
scrape_configs:
- job_name: abaca
static_configs:
- targets:
- '<abaca-api-host>:9797'
metrics_path: /metrics
scheme: http # or https if TLS termination is in front
Step 3 — Reload Prometheus
curl -X POST http://<prometheus-host>:9090/-/reload
Verify targets appear healthy in the Prometheus UI under Status → Targets.
Step 4 — (Optional) Configure log forwarding
Abacá services emit structured logs via oslo.log. Forward them to your SIEM or log aggregator using your standard OpenShift log forwarding pipeline (e.g., the OpenShift Logging operator with a ClusterLogForwarder custom resource) or your Kolla-Ansible log driver.
Audit events — secret access, admin actions, and enrollment acknowledgments — are included in the structured log stream in a SIEM-consumable form. No separate audit log sidecar is required.
Observability-relevant configuration lives in the [conductor] and [api] sections of your Abacá config file, plus a small number of environment variables for container deployments. All options follow the oslo.config convention: [section] key = value.
Scheduler and reconciliation cadence
These settings control how often the conductor checks for missed backups and stale state — directly affecting the freshness of your coverage and queue-latency metrics.
| Option | Section | Default | Effect |
|---|---|---|---|
scheduler_interval | [conductor] | 60 (seconds) | How often the conductor scans cron policies and enqueues overdue backups. Lower values reduce the window between a missed schedule and a metric alert. |
reconciliation_interval | [conductor] | 300 (seconds) | How often the reconciliation loop checks for stuck jobs, dead workers, and orphaned queue entries. This is also the cadence at which worker heartbeat state is evaluated. |
worker_heartbeat_deadline_seconds | [conductor] | 60 (seconds) | Seconds since a worker's last heartbeat before the fleet manager marks it DEAD. Should stay aligned with reconciliation_interval. |
worker_heartbeat_interval_seconds | [conductor] | 10 (seconds) | How often a running abaca-worker-agent sends a heartbeat RPC cast to the conductor. Must be significantly less than worker_heartbeat_deadline_seconds. |
maintenance_interval_seconds | [conductor] | 604800 (weekly) | Cadence for scheduled kopia maintenance run --full per enrolled backup target. Until maintenance runs, expired backups do not free S3 storage — relevant to bytes-at-rest metrics. |
usage_sample_interval_seconds | [conductor] | 21600 (6 hours) | How often the conductor samples kopia content stats per enrolled target. The result is the authoritative post-dedup, post-compression bytes-on-S3 figure and is more accurate than summing individual backup sizes. |
queued_job_deadline_seconds | [conductor] | 300 (seconds) | Seconds a job may remain in the queued state with no worker assigned before the reconciliation loop re-dispatches it. This bounds the worst-case queue latency visible in metrics. |
API pagination (affects metric query volume)
| Option | Section | Default | Effect |
|---|---|---|---|
max_limit | [api] | 1000 | Maximum page size for list endpoints. Relevant if your monitoring scripts page through large backup lists. |
default_limit | [api] | 100 | Default page size when no limit query parameter is supplied. |
Environment variable overrides
For container and Docker Compose deployments, the following environment variables override config file values without requiring a mounted config file:
| Variable | Config equivalent | Notes |
|---|---|---|
ABACA_DATABASE_CONNECTION | [database] connection | SQLAlchemy URL for the conductor's state store. |
ABACA_TRANSPORT_URL | oslo.messaging transport_url | RabbitMQ URL for conductor ↔ worker-agent messaging. |
ABACA_KOPIA_EXECUTOR | [kopia] executor | Set to ephemeral_container for local dev; always worker_rpc in production. |
ABACA_SERVICE_USER_ID | [abaca] service_user_id | Keystone user ID of the service account; surfaced on /v1/service_info. |
ABACA_WORKER_PROJECT_ID | [abaca] worker_project_id | Keystone project ID where worker VMs run; surfaced on /v1/service_info. |
Checking coverage and fleet health from the CLI
Using python-abacaclient, you can inspect the current health of your backup fleet and coverage posture from the OpenStack CLI.
List all protection policies and their last-run status to spot coverage gaps:
openstack share protection policy list
List recent jobs to see queue latency and error distribution:
openstack share protection job list --limit 50
Inspect a specific failed job to read its error_category and decide who needs to act:
openstack share protection job show <job-id>
The error_category field tells you:
tenant_action_required— the tenant must fix a configuration (for example, a bad S3 bucket URL or expired Barbican credentials).operator_action_required— the infrastructure or service needs attention (for example, a worker that cannot reach the Manila service).
Pulling usage metrics for chargeback
Abacá exposes a pull-based usage API compatible with CloudKitty and other external billing integrators. The key billable dimensions are:
- Protected capacity (GB-month): The logical size of the most recent successful backup per share, sampled on the
usage_sample_interval_secondscadence. - GB transferred per job: Bytes sent to S3 during each backup, covering both initial ingest and incremental churn.
- Restore count: Metered from day one; zero-rated by default (billing becomes a configuration flip — data cannot be collected retroactively).
Sample the current usage stats for a specific backup target:
openstack share protection target show <target-id>
The usage_stats field in the response reflects the most recent kopia content stats sample — post-dedup, post-compression bytes on S3. This is more accurate than summing individual backup record sizes, because Kopia's cross-snapshot deduplication means the sum would double-count shared content.
Interpreting Prometheus metrics
Every red state visible in the admin panel has a corresponding Prometheus metric, so your automated alerts and the human-readable dashboard always reflect the same data. Key signal categories:
- Heartbeat loss: A worker has not checked in within
worker_heartbeat_deadline_seconds. - Coverage breach: A share has a protection policy attached but its most recent successful backup is overdue.
- Overdue maintenance: A backup target has not had a successful
kopia maintenance run --fullwithinmaintenance_interval_seconds. - Target auth failure: Abacá could not authenticate against a target's S3 endpoint or Barbican reference.
- Queue latency: The age of the oldest job in the
queuedstate, bounded byqueued_job_deadline_seconds.
Alert rules live on the operator side — Abacá ships the metrics; you write the thresholds appropriate for your SLA.
Reading audit events
Abacá emits audit events in a structured, SIEM-consumable format for:
- Barbican secret access (reading S3 credentials and repository passwords)
- Administrative actions performed via abaca-api
- Enrollment acknowledgments (including the Keystone trust delegation)
Forward these from your log aggregation pipeline to your SIEM as you would any oslo.log-structured output. No additional configuration is needed to enable audit events — they are always emitted.
Example 1 — Query the unauthenticated health/identity endpoint
Verify the API is up and read the service account identity without needing credentials:
curl -s http://abaca-api.example.com:9797/v1/service_info | python3 -m json.tool
Expected output:
{
"service_user": {
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"name": "abaca"
},
"worker_project": {
"id": "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5",
"name": "abaca"
}
}
This endpoint is intentionally unauthenticated. Tenants use it during enrollment to look up the Keystone user ID they must delegate a trust to — without needing user-list privileges.
Example 2 — Inspect a failed job and determine who must act
A backup job has moved to the error state. Retrieve it and read the error_category:
openstack share protection job show d5e6f7a8-b9c0-1234-5678-d5e6f7a8b9c0
Expected output (truncated):
+------------------+---------------------------------------------------+
| Field | Value |
+------------------+---------------------------------------------------+
| id | d5e6f7a8-b9c0-1234-5678-d5e6f7a8b9c0 |
| status | error |
| error_category | tenant_action_required |
| error_message | S3 endpoint unreachable: connection refused |
| job_type | backup |
| created_at | 2024-10-15T03:00:01Z |
| updated_at | 2024-10-15T03:02:14Z |
+------------------+---------------------------------------------------+
tenant_action_required means the tenant must correct their backup target configuration — in this case the S3 endpoint URL stored in Barbican. The operator does not need to intervene.
Example 3 — List jobs with high queue latency
Filter for jobs still in the queued state to spot dispatch failures:
openstack share protection job list --status queued
If jobs appear here consistently beyond queued_job_deadline_seconds (default 300 s), the reconciliation loop will re-dispatch them. If the fleet has no available workers, those jobs will walk to error with operator_action_required.
Example 4 — View usage statistics on a backup target
Read the post-dedup, post-compression bytes stored in a target's Kopia repository:
openstack share protection target show f8a9b0c1-d2e3-4567-89ab-f8a9b0c1d2e3
Expected output (relevant field):
+----------------------------+----------------------------------------------+
| Field | Value |
+----------------------------+----------------------------------------------+
| id | f8a9b0c1-d2e3-4567-89ab-f8a9b0c1d2e3 |
| name | tenant-prod-bucket |
| status | available |
| usage_stats.bytes_on_s3 | 42949672960 |
| usage_stats.sampled_at | 2024-10-15T06:00:00Z |
+----------------------------+----------------------------------------------+
This sample is updated every usage_sample_interval_seconds (default 6 h). Use it as the authoritative figure for chargeback — not the sum of individual backup sizes.
Example 5 — Verify Prometheus scrape is working
After adding Abacá to your prometheus.yml, confirm the scrape target is healthy:
curl -s 'http://<prometheus-host>:9090/api/v1/targets' \
| python3 -m json.tool \
| grep -A5 'abaca'
Expected (relevant fragment):
{
"job": "abaca",
"health": "up",
"lastScrape": "2024-10-15T06:05:23Z"
}
Issue: /v1/service_info returns a connection error
Symptom: curl: (7) Failed to connect to abaca-api.example.com port 9797: Connection refused
Likely cause: The abaca-api service is not running, or api.bind_host / api.bind_port do not match the address you are targeting.
Fix:
- Check the
[api]section of your config:bind_hostdefaults to0.0.0.0andbind_portdefaults to9797. - Verify the abaca-api pod or container is in a running state.
- Check that any network policy or security group permits traffic on port 9797 from your monitoring host.
Issue: Prometheus scrape target shows health: down
Symptom: Abacá appears in Prometheus targets but health is down or last_error shows a timeout.
Likely cause: The metrics endpoint is not reachable from Prometheus — either a firewall rule blocks the scrape, or the path is incorrect.
Fix:
- Confirm the
metrics_pathin yourprometheus.ymlmatches the actual endpoint path. See the note in the Installation section — the exact path requires source confirmation. - Test reachability directly:
curl -s http://<abaca-api-host>:9797/metrics. - If using TLS termination in front of abaca-api, ensure
scheme: httpsis set in the scrape config.
Issue: Jobs remain in queued state indefinitely
Symptom: openstack share protection job list --status queued shows jobs older than 5 minutes that are not progressing.
Likely cause: No active worker VMs are available to accept jobs, or the RabbitMQ transport is unhealthy.
Fix:
- Check that at least one abaca-worker-agent VM is registered and heartbeating. If
conductor.min_workersis0(the default), workers must be booted manually usingabaca-dev worker-boot. - Verify
ABACA_TRANSPORT_URLpoints to a healthy RabbitMQ instance and that the conductor can reach it. - After
queued_job_deadline_seconds(default 300 s), the reconciliation loop will attempt to re-dispatch. If the fleet remains empty the job will move toerrorwitherror_category: operator_action_required.
Issue: Worker heartbeat loss alerts fire but the worker appears active
Symptom: Your monitoring alerts on heartbeat loss, but the worker VM exists and is processing a job.
Likely cause: worker_heartbeat_deadline_seconds (default 60 s) is too close to worker_heartbeat_interval_seconds (default 10 s) for your network conditions, or a brief network interruption ate one heartbeat cycle.
Fix:
- Increase
conductor.worker_heartbeat_deadline_secondsto give a wider margin — for example,90if heartbeats are occasionally delayed by 15–20 s. - Ensure
worker_heartbeat_interval_secondsremains significantly less thanworker_heartbeat_deadline_seconds. - Check for network congestion between the worker VM network and the RabbitMQ broker.
Issue: usage_stats.bytes_on_s3 is stale or missing
Symptom: The usage stats on a backup target show a sampled_at timestamp that is many hours old, or the field is empty.
Likely cause: The reconciliation loop's usage sampling pass has not run, or it encountered an error connecting to the Kopia repository during sampling.
Fix:
- Check
conductor.usage_sample_interval_seconds(default 21600 s / 6 h) — the field is only updated at this cadence. - Review abaca-conductor logs for errors during the
kopia content statsinvocation for the affected target. An S3 authentication failure or an unreachable endpoint will cause the sample to be skipped. - Confirm the target's Barbican credentials are valid:
openstack share protection target show <target-id>— ifstatusis notavailable, re-enroll or update credentials.
Issue: Audit events are missing from the SIEM
Symptom: Secret-access or enrollment events are not appearing in your log aggregation pipeline.
Likely cause: Log forwarding is not configured for the abaca-api or abaca-conductor pods, or your log aggregator is filtering out oslo.log-formatted entries.
Fix:
- Verify your OpenShift
ClusterLogForwarder(or equivalent Kolla log driver) is configured to forward logs from theabacanamespace. - Confirm your SIEM ingest parser handles oslo.log's structured JSON format. Audit events are emitted inline in the same log stream — there is no separate audit log file.
- Check that you are not filtering by log level in a way that drops
INFO-level audit records.