Skip to main content
Version: 0.9

Monitoring & metrics

Self-hosted TokenTimer exposes Prometheus metrics from the API and pushes worker metrics to an optional Pushgateway. Metrics are disabled by default.

Enabling metrics

VariableDescriptionDefaultScope
ENABLE_METRICSEnable /metrics and metric push attempts when truefalseAPI, worker
PUSHGATEWAY_URLPrometheus Pushgateway endpoint for worker metricsunsetWorker
ENVIRONMENT_SUFFIXMetrics environment label (env) when running multiple instancesunsetWorker

With ENABLE_METRICS=true, the API serves Prometheus text format at GET /metrics on the API port (default 4000). The endpoint has no authentication, so restrict access at the network layer (NetworkPolicy, firewall, or scrape from inside the cluster only).

Worker runs are short-lived (one job per scheduled run, whether launched by a Kubernetes CronJob or by the long-running Compose runner), so workers push their metrics to PUSHGATEWAY_URL at the end of each run instead of exposing a scrape endpoint. Schedules are described in Configuration → Worker scheduling.

API metrics

MetricTypeLabelsMeaning
tokentimer_api_http_request_duration_secondsHistogrammethod, route, statusHTTP request duration
tokentimer_api_http_requests_totalCountermethod, route, statusTotal HTTP requests
tokentimer_api_login_attempts_totalCounteroutcomeLogin attempts
tokentimer_api_2fa_verifications_totalCounteroutcome2FA verification attempts
tokentimer_api_rate_limit_hits_totalCounterHTTP 429 responses
tokentimer_api_csrf_rejections_totalCounterRequests rejected by CSRF protection
tokentimer_api_rbac_denied_totalCounterRBAC authorization denials
tokentimer_api_workspace_created_totalCounterWorkspaces created
tokentimer_api_invite_sent_totalCounterWorkspace invites created
tokentimer_invite_cancelled_totalCounterPending invites cancelled

Route labels use the matched Express route pattern (for example /api/v1/workspaces/:id), never raw request paths, to keep label cardinality bounded.

Worker metrics

Pushed to the Pushgateway per run, labeled with env (from ENVIRONMENT_SUFFIX or NODE_ENV):

MetricTypeLabelsMeaning
alerts_queue_depthGaugestatusAlert queue depth by status
alerts_queue_due_nowGaugeAlerts due now (pending/failed, not under cooldown)
alerts_cooldown_in_effectGaugeAlerts with active retry cooldown
runner_upGaugecomponentWorker heartbeat by component
alerts_delivery_totalCounterchannel, provider, statusAlert deliveries
alerts_retry_totalCounterchannel, kindRetries (auto/manual)
alerts_delivery_latency_secondsHistogramchannel, providerDelivery latency
alerts_webhook_denied_host_totalCounterprovider, hostWebhook hosts denied by the provider allowlist
weekly_digest_sent_totalCounterchannel, statusWeekly digests sent
weekly_digest_processedGaugeGroups processed in the last digest run
auto_sync_runs_totalCounterprovider, statusAuto-sync runs by outcome (success/failure)
auto_sync_items_imported_totalCounterproviderItems imported (created or updated) by auto-sync
auto_sync_last_run_timestampGaugeprovider, statusUnix timestamp of the last auto-sync attempt
app_log_errors_totalCounterserviceError-level log events

Worker metrics are pushed with job name tokentimer-alerts and a worker grouping label per worker type.

Kubernetes (Helm)

The Helm chart ships optional monitoring resources, all disabled by default:

monitoring:
metrics:
enabled: true # sets ENABLE_METRICS=true
pushgatewayUrl: "http://pushgateway.monitoring:9091"

serviceMonitor:
enabled: true # requires the Prometheus Operator CRDs
interval: "30s"
scrapeTimeout: "10s"

prometheusRules:
enabled: true
groups: [] # your PrometheusRule groups

The Ingress template routes /metrics to the API service; if you enable the Ingress and do not want metrics exposed publicly, keep monitoring.metrics.enabled off or block the path at your ingress controller.

Suggested alerts

  • alerts_queue_due_now above a threshold for more than 15 minutes: the delivery worker is stuck or SMTP/webhooks are failing.
  • Rate of alerts_delivery_total{status="failure"} above zero: inspect the alert queue and the audit log for ALERT_SEND_FAILED events.
  • runner_up stale for a component: the corresponding worker CronJob is not running.
  • Increase in tokentimer_api_rate_limit_hits_total or tokentimer_api_csrf_rejections_total: possible abusive traffic or a misconfigured client.

Health endpoint

Independent of metrics, GET /health on the API returns a JSON status suitable for container healthchecks and load balancer probes:

{
"status": "healthy",
"timestamp": "2026-03-19T12:00:00.000Z",
"uptime": 123.456,
"memory": { "rss": 52428800 },
"environment": "production"
}