A Cortex worker exposes a Prometheus scrape endpoint at GET /metrics on its monitoring port —
the same server that serves the health and readiness probes. All Cortex meters are prefixed
cortex_. For the server-side counterpart see Loom Metrics; for liveness
and readiness see Monitoring API.
Endpoint
| Property | Value | Notes |
|---|---|---|
Path |
|
Standard Prometheus text exposition format |
Port |
|
Env |
Auth |
none |
Internal monitoring surface — restrict at the network layer |
curl http://cortex-1.internal:8093/metrics
Changing the port
CORTEX_MONITORING_PORT=9090
Loom Connection
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
gauge |
— |
|
|
gauge |
— |
|
|
gauge |
— |
Consecutive reconnect attempts since the last successful connect. |
|
counter |
— |
Reconnect attempts scheduled over the worker’s lifetime. |
|
counter |
|
Control-channel messages received from Loom (the message type, lower-cased). |
cortex_loom_connected and cortex_loom_registered are the two gauges to alert on — a worker that is
live but has cortex_loom_registered == 0 will never receive work.
Tasks
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
counter |
|
Tasks accepted from Loom. |
|
counter |
|
Task outcomes reported back. |
|
timer |
|
End-to-end task execution time. |
Node Operations
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
counter |
|
Individual node executions, by node kind. |
|
timer |
|
Per-node execution time. |
|
counter |
— |
Media files referenced by a task that no longer exist on disk. |
Node operations are counted once, at the task-handling choke point, keyed by the node kind carried in
the task. A non-zero cortex_files_missing_total usually means Loom’s asset paths and the worker’s
view of the shared media storage have diverged.
Result Egress
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
counter |
— |
Individual results written back to Loom. |
|
counter |
— |
Batches flushed to Loom. |
|
counter |
|
Assets processed by the bulk sync writer. |
|
counter |
— |
Items enumerated by a source task. |
|
counter |
— |
Source batches Loom did not acknowledge in time. |
Comparing rate(cortex_results_sent_total) against rate(cortex_node_operations_total) shows whether
results are reaching Loom as fast as the worker produces them.
AI Model Calls
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
counter |
|
Calls to an upstream model service. |
|
timer |
|
Latency of those calls. |
|
counter |
|
Calls avoided by the in-process skip cache. |
These are instrumented at the node call sites — the LLM, Captioning, Speech-to-Text and OCR nodes — so they measure what the worker actually experienced, including network time to the model service.
Worker Resources
| Metric | Type | Labels | Meaning |
|---|---|---|---|
|
gauge |
— |
Heap in use, as also reported to Loom in the status heartbeat. |
|
gauge |
— |
Maximum heap the JVM may grow to. |
|
gauge |
— |
Process CPU load. |
|
gauge |
— |
Disk usage of the worker’s working file store. |
Vert.x built-in metrics and the Micrometer JVM binders share the same registry, so jvm_*,
process_cpu_usage and vertx_* families are exported alongside the cortex_ meters.
Prometheus Configuration
scrape_configs:
- job_name: metaloom-cortex
static_configs:
- targets: ["cortex-1.internal:8093", "cortex-2.internal:8093"]
With workers running as a Kubernetes Deployment, prefer service discovery over static targets so
scaling the fleet does not require a config change:
scrape_configs:
- job_name: metaloom-cortex
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
regex: cortex-server
action: keep
- source_labels: [__address__]
regex: (.+?)(?::\d+)?
replacement: $1:8093
target_label: __address__
Useful Queries
# Node failure ratio by kind over 5 minutes
sum by (node_kind) (rate(cortex_node_operations_total{state="failed"}[5m]))
/ sum by (node_kind) (rate(cortex_node_operations_total[5m]))
# Mean node latency by kind
sum by (node_kind) (rate(cortex_node_operation_duration_seconds_sum[5m]))
/ sum by (node_kind) (rate(cortex_node_operation_duration_seconds_count[5m]))
# Workers that are up but not registered with Loom
cortex_loom_registered == 0
# Model-service error rate by provider
sum by (provider) (rate(cortex_ai_calls_total{outcome="failure"}[5m]))
Naming Conventions
Metric names follow Prometheus conventions: counters carry a _total suffix, timers are exported in
base units as _seconds, and labels are deliberately low-cardinality — node kind, task type, message
type or model provider. Asset UUIDs, file paths and run UUIDs are never used as label values.
Timers are exported without a percentile histogram, so each one yields _seconds_count,
_seconds_sum and _seconds_max series. Derive averages from sum / count; histogram_quantile()
is not available for these meters.