A standalone Prometheus exporter for Ansible Automation Platform (AAP) that exposes job metrics, platform resource counts, instance health, and license status by polling the AAP REST API (/api/controller/v2/).
Follows the Prometheus exporter best practices and the architectural pattern of windows_exporter: pluggable collectors, concurrent collection with per-collector timeouts, and CLI flag-driven cardinality controls.
| Metric | Type | Labels | Description |
|---|---|---|---|
aap_jobs |
Gauge | organization, job_template, status |
All-time job count by template and status (successful, failed, canceled, error) |
aap_jobs_running |
Gauge | — | Currently running jobs |
aap_jobs_pending |
Gauge | — | Currently pending jobs |
aap_job_duration_seconds |
Histogram | organization, job_template |
Job run durations within the lookback window |
| Metric | Type | Labels | Description |
|---|---|---|---|
aap_job_templates |
Gauge | organization |
Job template count per org |
aap_workflow_job_templates |
Gauge | organization |
Workflow job template count per org |
aap_projects |
Gauge | organization |
Project count per org |
aap_inventories |
Gauge | organization |
Inventory count per org |
aap_hosts |
Gauge | organization |
Host count per org |
aap_schedules |
Gauge | organization |
Schedule count per org |
aap_info |
Gauge | version, license_type |
Platform info (constant 1) |
aap_license_expiry_seconds |
Gauge | — | Seconds until license expiry |
aap_license_instances_limit |
Gauge | — | Maximum managed hosts allowed by license |
aap_license_instances_free |
Gauge | — | Free managed host slots remaining |
aap_license_instances_current |
Gauge | — | Currently managed hosts |
| Metric | Type | Labels | Description |
|---|---|---|---|
aap_instance_capacity |
Gauge | hostname, node_type |
Node capacity |
aap_instance_consumed_capacity |
Gauge | hostname, node_type |
Node consumed capacity |
aap_instance_cpu_cores |
Gauge | hostname |
CPU cores |
aap_instance_memory_bytes |
Gauge | hostname |
Memory in bytes |
aap_instance_info |
Gauge | hostname, node_type, version, enabled |
Node info (constant 1) |
| Metric | Type | Labels | Description |
|---|---|---|---|
aap_scrape_duration_seconds |
Gauge | — | Total scrape duration |
aap_collector_scrape_duration_seconds |
Gauge | collector |
Per-collector scrape duration |
aap_collector_scrape_success |
Gauge | collector |
1 if collector succeeded, 0 otherwise |
aap_collector_scrape_timeout |
Gauge | collector |
1 if collector hit the scrape timeout |
./aap_exporter \
--aap.url="https://your-aap-host/api/controller/v2/" \
--aap.token="your-bearer-token"Metrics available at http://localhost:9269/metrics.
./aap_exporter \
--aap.url="https://your-aap-host/api/controller/v2/" \
--aap.token-file="/run/secrets/aap_token"| Flag | Env | Default | Description |
|---|---|---|---|
--aap.url |
AAP_URL |
— | AAP API base URL (required, must end with /api/controller/v2/) |
--aap.token |
AAP_TOKEN |
— | Bearer token |
--aap.token-file |
AAP_TOKEN_FILE |
— | Path to token file |
--aap.tls-skip-verify |
— | false |
Skip TLS certificate verification |
--web.listen-address |
— | :9269 |
Listen address |
--web.telemetry-path |
— | /metrics |
Metrics path |
--scrape.timeout |
— | 30s |
Maximum scrape duration |
--collectors.enabled |
— | jobs,platform,instances |
Comma-separated list of enabled collectors |
| Flag | Default | Description |
|---|---|---|
--collector.jobs.include-templates |
.+ |
Regexp of template names to include |
--collector.jobs.exclude-templates |
— | Regexp of template names to exclude |
--collector.jobs.include-orgs |
.+ |
Regexp of org names to include |
--collector.jobs.exclude-orgs |
— | Regexp of org names to exclude |
--collector.jobs.concurrency |
10 |
Parallel API calls for template fan-out |
--collector.jobs.duration-lookback |
24h |
Lookback window for duration histogram |
| Flag | Default | Description |
|---|---|---|
--collector.platform.include-orgs |
.+ |
Regexp of org names to include |
--collector.platform.exclude-orgs |
— | Regexp of org names to exclude |
Reduce jobs collector from ~700 API calls to ~24 by scoping to specific templates and orgs:
--collector.jobs.include-templates="^(deploy_prod|rollback|health_check)$" \
--collector.jobs.include-orgs="^(Ops|Platform)$"docker run --rm \
-e AAP_URL="https://your-aap-host/api/controller/v2/" \
-e AAP_TOKEN="your-bearer-token" \
-p 9269:9269 \
ghcr.io/dominik-esb/aap_exporter:latestMetrics available at http://localhost:9269/metrics.
Mount a file and use --aap.token-file instead of the env var:
docker run --rm \
-e AAP_URL="https://your-aap-host/api/controller/v2/" \
-v /path/to/token.txt:/run/secrets/aap_token:ro \
-p 9269:9269 \
ghcr.io/dominik-esb/aap_exporter:latest \
--aap.token-file=/run/secrets/aap_tokenCopy .env.example to .env, fill in your values, then:
docker compose up -ddocker-compose.yml reads AAP_URL and AAP_TOKEN from the environment (or .env). Uncomment the command lines to restrict which templates and orgs are scraped.
make docker-build # docker build -t aap_exporter:latest .
make docker-build IMAGE=myrepo/aap_exporter TAG=1.0.0scrape_configs:
- job_name: aap
static_configs:
- targets: ["aap-exporter-host:9269"]
scrape_interval: 60s
scrape_timeout: 35sSet
scrape_timeoutslightly above--scrape.timeoutso Prometheus waits for the full scrape before declaring it stale.
make build # produces bin/aap_exporter
make test # go test ./... -race -count=1
make lint # go vet ./...Requires Go 1.23+.
cmd/aap_exporter/ # Entry point
internal/
client/ # AAP HTTP client (bearer auth, pagination)
collector/ # Collector interface + orchestrator
collector/jobs/ # jobs collector
collector/platform/ # platform collector
collector/instances/ # instances collector