Sign inSign up

vremenar/semaphore-prometheus-exporter

By vremenar

•Updated 4 days ago

Image
Monitoring & observability
0

10K+

vremenar/semaphore-prometheus-exporter repository overview

ā šŸ“” Semaphore Prometheus Exporter

A lightweight Prometheus exporter for Semaphore UI⁠ written in Go.

It polls the Semaphore REST API on a configurable interval, stores the data in a local file-backed cache, and exposes all metrics via a standard /metrics endpoint — so that every Prometheus scrape reads from cache and never hammers the API.

CI/CD Pipeline


⁠Exposed Metrics

⁠Exporter Health
MetricLabelsDescription
semaphore_up—1 if data has been fetched at least once, 0 otherwise
semaphore_cache_age_seconds—Age of the cached data in seconds
semaphore_cache_last_update_timestamp_seconds—Unix timestamp of the last successful cache update
⁠Projects
MetricLabelsDescription
semaphore_project_infoproject_id, project_name, alert_chat, createdProject metadata (value is always 1)
semaphore_project_max_parallel_tasksproject_id, project_nameMaximum parallel tasks allowed per project
⁠Tasks
MetricLabelsDescription
semaphore_task_infotask_id, project_id, template_id, status, playbook, message, debug, dry_run, diff, createdTask metadata (value is always 1)
semaphore_task_duration_secondstask_id, project_id, template_id, statusTask wall-clock duration in seconds (-1 if still running or no end time recorded)
semaphore_task_status_totalproject_id, statusTask count per project and status combination
⁠Templates
MetricLabelsDescription
semaphore_template_infotemplate_id, project_id, name, playbook, description, typeTemplate metadata (value is always 1)
semaphore_template_countproject_id, project_nameTotal number of templates per project
⁠Schedules
MetricLabelsDescription
semaphore_schedule_infoschedule_id, project_id, template_id, cron_format, name, active, delete_after_runSchedule metadata (value is always 1)
semaphore_schedule_countproject_id, project_nameTotal number of schedules per project
⁠Events
MetricLabelsDescription
semaphore_event_infoobject_type, object_id, project_id, description, user_id, user_name, username, createdAudit event metadata — last N events (configurable via MAX_EVENTS)
⁠Users
MetricLabelsDescription
semaphore_user_infouser_id, name, username, email, admin, externalUser metadata (value is always 1)
semaphore_user_count—Total number of users

Note: Fetching users requires an admin API token. If a non-admin token is used, user metrics will be empty but all other metrics will still work.


⁠Quick Start

⁠1. Clone and configure
cp .env.example .env
# Edit .env — set at minimum SEMAPHORE_URL and SEMAPHORE_API_TOKEN
⁠2. Run with Docker Compose
docker compose up -d

Metrics are available at http://localhost:9090/metrics⁠.


⁠Configuration Reference

All settings are controlled via environment variables:

VariableDefaultDescription
SEMAPHORE_URL(required)Base URL of your Semaphore instance, e.g. http://semaphore:3000
SEMAPHORE_API_TOKEN(required)API token — Semaphore UI → Your Profile → API Tokens
LISTEN_ADDRESS:9090Address the HTTP server binds to
SCRAPE_INTERVAL30mHow often to fetch from Semaphore (Go duration: 30s, 5m, 1h)
MAX_EVENTS100Number of audit events to fetch and expose
HTTP_TIMEOUT30sTimeout for HTTP requests to Semaphore
INSECURE_SKIP_VERIFYfalseSkip TLS certificate verification (not recommended in production)
CACHE_FILE/opt/semaphore-prometheus-exporter/data/cache.jsonPath of the JSON cache file inside the container
CACHE_DATA_PATH./dataDocker Compose only — host path mounted as the cache volume
EXPORTER_PORT9090Docker Compose only — host port the metrics endpoint is exposed on
LOG_LEVELinfoLog verbosity: debug, info, warn, error

⁠Generating an API Token

  1. Log in to Semaphore UI
  2. Click your username → Your Profile
  3. Scroll to API Tokens → Add Token
  4. Copy the token and set it as SEMAPHORE_API_TOKEN

⁠Prometheus Scrape Config

scrape_configs:
  - job_name: semaphore
    static_configs:
      - targets: ["semaphore-prometheus-exporter:9090"]
    scrape_interval: 1m   # Can be faster than SCRAPE_INTERVAL — reads from cache

⁠Grafana Dashboard

A ready-to-import Grafana dashboard is included at grafana-dashboard.json.

Import steps:

  1. Grafana → Dashboards → Import
  2. Upload grafana-dashboard.json
  3. Select your Prometheus datasource
  4. Click Import

The dashboard covers:

  • Exporter health, cache age and last update time
  • Task status distribution (pie chart) and counts per project
  • Last 3 failed tasks and last 3 successful tasks
  • Task duration trends, average and maximum
  • Project list with max parallel tasks
  • Audit event breakdown by object type and user
  • Full user list with admin/external indicators

⁠Logging

All log output is in JSON format following the Elastic Common Schema (ECS) 1.12⁠, making it compatible with Wazuh, Elasticsearch, and other ECS-aware SIEM systems.

Example log entry:

{
  "@timestamp": "2026-03-01T19:23:26.123456789Z",
  "log": { "level": "info" },
  "message": "Fetched events",
  "count": 100,
  "service": { "name": "semaphore-prometheus-exporter", "type": "metrics" },
  "ecs": { "version": "1.12.0" }
}

Log level is controlled via the LOG_LEVEL environment variable (debug, info, warn, error).


⁠Building Manually

go mod download
go build -ldflags="-X main.Version=1.0.0" -o semaphore-prometheus-exporter .
./semaphore-prometheus-exporter

⁠Versioning

The application version is defined in version.go⁠:

const Version = "1.0.0"

Update this value manually before each release. The CI/CD pipeline reads it automatically and applies it as a Docker image tag alongside latest and the current date:

docker.io/vremenar/semaphore-prometheus-exporter:latest
docker.io/vremenar/semaphore-prometheus-exporter:2026-03-01
docker.io/vremenar/semaphore-prometheus-exporter:1.0.0

⁠Volume / Persistence

The cache directory /opt/semaphore-prometheus-exporter/data is declared as a Docker volume. On restart the exporter loads the last-known data from disk immediately and serves it until the first successful API fetch completes.

To use a custom host path, set CACHE_DATA_PATH in your .env file:

CACHE_DATA_PATH=/var/lib/semaphore-prometheus-exporter

⁠Health Check

GET /healthz  → 200 OK  (always, as long as the process is alive)
GET /         → HTML index page with links to /metrics, /healthz and GitHub

Tag summary

Content type

Image

Digest

sha256:94712f36f…

Size

11.9 MB

Last updated

4 days ago

docker pull vremenar/semaphore-prometheus-exporter