Velocity • Durability

14. Observability

Alerts, audit trail, PanFS events, logs, and metrics, each as a point-in-time snapshot endpoint and a matching Server-Sent Events (SSE) stream endpoint for live updates.

14.1 Metrics and Logs Behind These Endpoints

The endpoints in this chapter are windows onto the data stores of the VDURA observability stack, not a separate data model. Knowing what those stores hold, and how it is named, is what makes the query endpoints useful. This section summarizes it; the full catalog of metric names, labels, alert definitions, and dashboards is in the PanFS Metrics Reference Guide.

Where each endpoint group reads from

Endpoint group Backing store How it reads
metrics/query, metrics/query_range VictoriaMetrics (Prometheus-compatible, MetricsQL) Forwarded to the VictoriaMetrics /api/v1/query and /api/v1/query_range endpoints. Only the documented parameters are accepted; any other name returns 422.
metrics/{key}, metrics/stream, metrics/{key}/stream, metrics/targets VictoriaMetrics Snapshots and Server-Sent Events streams for named metric keys, and node target discovery in Prometheus HTTP Service Discovery format.
logs, logs/stream, logs/{logsql_endpoint} VictoriaLogs (LogsQL) The proxy forwards to /select/logsql/{endpoint} on the VictoriaLogs query instance on the director node.
audit, audit/stream, audit/{request_id}, events, events/stream VictoriaLogs The server owns the LogsQL query, so clients pass no query text. Audit records are deduplicated by request_id and PanFS events by event_id.
alerts, alerts/stream, storagesets/status Alert series in the metrics database Active alerts evaluated by vmalert and projected from the ALERTS series.

Metric naming families

Four naming families coexist in the metrics database. Recognizing the family tells you where a metric comes from and how to read it.

Prefix Source and reading rules
magent_local_*, magent_shelf_* The PanFS management agent statistics tree, flattened as magent_local_<hw, sw, or sys>_<subsystem>_<stat>. Array statistics get a numeric suffix, and a string statistic becomes a series with the value 1 and the text in a value label.
panfs_* Realm-level inventory and events from the management database. The sample value is a state code and the content is in the labels. Each family has a matching <family>_scrape_success gauge.
cpu_, mem_, disk_, diskio_, net_, netstat_, nstat_, ethtool_, processes_, procstat_, system_ Host operating system metrics from Telegraf input plugins, named <measurement>_<field>. Standard Linux semantics apply, and counters need rate() or increase().
ALERTS, ALERTS_FOR_STATE, observability_node_type The vmalert output, and the declaration of each node’s role.

Common labels

Nearly every series carries five labels that identify the emitting node, so any metric can be sliced by node or node role without a join. Realm-level panfs_* inventory metrics describe realm objects rather than the emitting host and carry only node_name.

Label Meaning
host Linux hostname of the node.
host_id Stable node UUID assigned by the node identity service.
ip_address Management IP address of the node.
node_name The PanFS realm name of the node, in enclosure,slot form, such as VCH-1,1.
node_type The node role: director_l for a director, vpod for a virtual storage node hosting one OSD. Other values appear on physical realms.

Reading values correctly

  • Counters (host disk and network totals, File Manager operation counts) increase monotonically; use rate() or increase().
  • Gauges are read directly.
  • Info metrics have a constant sample value and carry their content in labels; read them with last_over_time() or group by the label, never with rate().
  • Interval gauges (the measure_ group under magent_local_sw_iopath_) already represent the last collection interval; sum them across nodes for a realm figure, and do not apply rate() to them.
  • Management agent and realm metrics arrive about every 20 seconds.

Example queries

Pass any of these as the query parameter of GET /api/v1/observability/metrics/query:

curl -sG "https://<realm-address>/api/v1/observability/metrics/query" \
  -H "Authorization: Bearer $TOKEN" \
  --data-urlencode 'query=count by (node_type) (system_uptime)'
Question Expression
How many nodes of each role are reporting? count by (node_type) (system_uptime)
Which director holds the realm president role? panfs_president == 1
Is the master management server reachable? min(panfs_master_mserver_up)
How many realm alerts are active, by severity? sum by (severity) (panfs_alert_occurrences)
How many alerts are firing, by severity? count by (severity) (ALERTS{alertstate="firing"})
How long has each alert been active? time() - ALERTS_FOR_STATE
Which network interfaces have the link down? panfs_nic{uplink_down="true"}

Logs and the audit trail

The audit and event endpoints read structured log lines from VictoriaLogs. The fields of an AuditRecord are the fields of the API audit log (/var/log/panapi-audit.log): client_ip, method, request_id, result, status_code, action, resource, target_id, tenant_id, and user_id. Every log line also carries stream identity fields such as _time, _msg, node_name, host_id, and filename (or unit for journald entries). To go beyond what the audit endpoints offer, query the logs directly through the proxy with LogsQL. For example, to list recent failed API operations:

curl -sG "https://<realm-address>/api/v1/observability/logs/query" \
  -H "Authorization: Bearer $TOKEN" \
  --data-urlencode 'query=filename:="/var/log/panapi-audit.log" result:=failed' \
  --data-urlencode 'limit=20'

14.2 Endpoint Reference

Endpoint Summary

Path Summary Method
/api/v1/observability/alerts Alerts snapshot (keyed set) GET
/api/v1/observability/alerts/stream Alerts SSE stream (added/resolved) GET
/api/v1/observability/audit Audit trail snapshot (last N) GET
/api/v1/observability/audit/stream Audit SSE stream (append deltas) GET
/api/v1/observability/audit/{request_id} Audit record with failure diagnostics GET
/api/v1/observability/events PanFS events snapshot (last N) GET
/api/v1/observability/events/stream PanFS events SSE stream (append deltas) GET
/api/v1/observability/logs Logs snapshot (last N) GET
/api/v1/observability/logs/stream Logs SSE stream (append deltas) GET
/api/v1/observability/logs/{logsql_endpoint} VictoriaLogs /select/logsql proxy GET
/api/v1/observability/metrics/query Prometheus instant query proxy GET
/api/v1/observability/metrics/query_range Prometheus range query proxy GET
/api/v1/observability/metrics/stream Grouped metric SSE stream (append deltas for several keys) GET
/api/v1/observability/metrics/targets List metrics targets GET
/api/v1/observability/metrics/{key} Metric snapshot (range window) GET
/api/v1/observability/metrics/{key}/stream Metric SSE stream (append deltas) GET
/api/v1/observability/storagesets/status Storage-set alert status GET

GET /api/v1/observability/alerts

Alerts snapshot (keyed set)

The current alert set of the caller’s own tenant, most severe first. A platform caller widens to one tenant with tenant_id, or to every tenant with all_tenants=true; its own tenant is the realm’s telemetry, so the default read is the realm’s health rather than the tenants’ records. A tenant-filtered read returns only records that carry a tenant, so during a rolling upgrade a node that has not taken the new configuration yet produces records no tenant-filtered read returns. That fails closed: it is a completeness limit, never a disclosure.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Successful Response array
422 Validation Error HTTPValidationError

GET /api/v1/observability/alerts/stream

Alerts SSE stream (added/resolved)

Deltas for the same feed the alerts snapshot reads, taking the same tenant_id scope. The stream ends itself with one terminal end event whose reason is credential_expired (refresh the token and reconnect), credential_revoked (sign in again), permission_revoked (the caller no longer holds the grant), lifetime_expired (the maximum stream lifetime; reconnect) or recheck_unavailable (the credential could not be re-checked several times running; reconnect with backoff). The checks run on stream ticks, which on a quiet feed happen every 20 seconds, so an end can lag by about that.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
422 Validation Error HTTPValidationError

GET /api/v1/observability/audit

Audit trail snapshot (last N)

Newest API audit records, newest first, one row per request. The server owns the LogsQL query, so clients pass no query text. Records are deduplicated by their request_id - one record per API call. A tenant caller reads its own tenant’s records; and so does a platform caller by default; a platform caller widens with tenant_id or all_tenants=true. user_id reads one user’s records; the filters compose. only keeps just the records recorded under the named actions, and skip drops them - skip=list,view hides the read-only bulk, leaving the records that changed something, while only=create,delete reads the lifecycle alone. since and until bound the record time inclusively (RFC 3339; a value with no timezone reads as UTC); an inverted range matches nothing. A tenant-filtered read returns only records that carry a tenant, so during a rolling upgrade a node that has not taken the new configuration yet produces records no tenant-filtered read returns. That fails closed: it is a completeness limit, never a disclosure.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
user_id query string (uuid), nullable no Read one user’s audit records, including what they did while switched into another tenant. Omit it to read every record, whoever made the request. Applied upstream, so the limit is spent on the records asked for; composes with tenant_id.
skip query string, nullable no Comma-separated action names to drop, e.g. skip=list,view. Any action name is accepted; one matching no records excludes nothing. A record carrying no action survives every exclusion.
only query string, nullable no Comma-separated action names to keep, e.g. only=create,delete. Any action name is accepted; a record carrying no action is dropped. Composes with skip, which wins where they overlap.
since query string (date-time), nullable no Oldest record time to return (inclusive, RFC 3339; no timezone reads as UTC).
until query string (date-time), nullable no Newest record time to return (inclusive, RFC 3339; no timezone reads as UTC).
limit query integer no Maximum records to return; unbounded above, so ask only for what you will render.
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Successful Response array
422 Validation Error HTTPValidationError

GET /api/v1/observability/audit/stream

Audit SSE stream (append deltas)

Deltas for the same feed the audit snapshot reads, taking the same tenant_id, user_id, skip and only filters - pass the values the snapshot was taken with, so the stream continues it. since/until have no stream counterpart: a stream starts at its baseline and appends from there. The stream ends itself with one terminal end event whose reason is credential_expired (refresh the token and reconnect), credential_revoked (sign in again), permission_revoked (the caller no longer holds the grant), lifetime_expired (the maximum stream lifetime; reconnect) or recheck_unavailable (the credential could not be re-checked several times running; reconnect with backoff). The checks run on stream ticks, which on a quiet feed happen every 20 seconds, so an end can lag by about that.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
user_id query string (uuid), nullable no Read one user’s audit records, including what they did while switched into another tenant. Omit it to read every record, whoever made the request. Applied upstream, so the limit is spent on the records asked for; composes with tenant_id.
skip query string, nullable no Comma-separated action names to drop, as on the audit snapshot.
only query string, nullable no Comma-separated action names to keep, as on the audit snapshot.
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
422 Validation Error HTTPValidationError

GET /api/v1/observability/audit/{request_id}

Audit record with failure diagnostics

One audit record plus the correlated pan-api log detail for that request. diagnostics is parsed from the correlated ERROR line when one is found, and is always present, empty when no correlated lines exist. 404 for an unknown or aged-out id, and for a tenant caller also for a record of another tenant or one carrying no tenant, so a tenant cannot probe which ids exist. There is no all-tenants form here, because a request id already names one record: a platform caller reads another tenant’s record by naming it with tenant_id, and gets the same 404 otherwise.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
request_id path string yes The audit record id, as returned by the audit snapshot.
tenant_id query string (uuid), nullable no Platform tenant only. Read an audit record of another tenant instead of your own. There is no all-tenants form here: a request id already names exactly one record, so the only question is whose record the caller may reach.

Responses

Status Description Schema
200 Successful Response AuditRecordDetail
422 Validation Error HTTPValidationError

Response Body (200, AuditRecordDetail)

Field Type Required Default Example Description
action string no (empty string) Action performed on that resource, e.g. create.
auth_token_id string no (empty string) Id of the API token that authenticated the request; empty for a session.
client_ip string no (empty string) Client IP address of the request.
diagnostics AuditDiagnostics object no n/a Correlated pan-api log detail for this request.
duration_ms number no 0 Request duration in milliseconds.
id string yes n/a The record’s own identifier, which is its request_id.
method string yes n/a HTTP method of the audited request.
principal_id string no (empty string) Who acted, as <tenant id>/<principal id>. Under a tenant switch this is the person who switched, in their own tenant. Empty when the request was not authenticated.
principal_name string no (empty string) <tenant name>/<name>, or the bare name when the tenant name was not known.
principal_type string no (empty string) user | service-account.
query string no (empty string) Query string of the audited request.
reason any, nullable no null Reason for a denied or failed result, if recorded.
request_body any, nullable no null Request body, secret-redacted at write time.
request_id string yes n/a Audit request id; the identity used for deduplication.
resource string no (empty string) Resource the request acted on, e.g. volumes.
result string yes n/a Outcome of the request: success | denied | failed.
severity string yes n/a Audit-significance severity: INFO | WARNING.
status_code integer, nullable no null HTTP response status code.
target_id string no (empty string) Id of the specific instance acted on, if any.
tenant_id string no (empty string) The tenant the credential acts in: the caller’s own, or under a tenant switch the tenant switched into. It differs from the tenant half of principal_id only under a switch.
time string yes n/a When the request was audited (RFC 3339, from VictoriaLogs _time).
url string yes n/a URL path of the audited request.
user_agent string no (empty string) Client User-Agent header of the request.

GET /api/v1/observability/events

PanFS events snapshot (last N)

Newest PanFS management events, newest first, one row per event. The server owns the query, so clients pass no query text. Records are deduplicated by their PanFS event_id, which the feed repeats whenever the events file is re-read, or by their request_id when they come from the audit trail and carry no event_id. A tenant caller reads its own tenant’s events, and so does a platform caller by default; a platform caller widens to one tenant’s with tenant_id. A tenant-filtered read returns only records that carry a tenant, so during a rolling upgrade a node that has not taken the new configuration yet produces records no tenant-filtered read returns. That fails closed: it is a completeness limit, never a disclosure.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
limit query integer no
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Successful Response array
422 Validation Error HTTPValidationError

GET /api/v1/observability/events/stream

PanFS events SSE stream (append deltas)

Deltas for the same feed the snapshot reads, taking the same tenant_id filter. Pass the value the snapshot was taken with, so the stream continues it. The stream ends itself with one terminal end event whose reason is credential_expired (refresh the token and reconnect), credential_revoked (sign in again), permission_revoked (the caller no longer holds the grant), lifetime_expired (the maximum stream lifetime; reconnect) or recheck_unavailable (the credential could not be re-checked several times running; reconnect with backoff). The checks run on stream ticks, which on a quiet feed happen every 20 seconds, so an end can lag by about that.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
tenant_id query string (uuid), nullable no Platform tenant only. Read the observability records of another tenant instead of your own.
all_tenants query boolean no Platform tenant only. Read the observability records of every tenant. Omitted, a read covers the caller’s own tenant alone - for the platform tenant that is the realm’s own telemetry, which carries the platform tenant id, and not the records tenants own.

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
422 Validation Error HTTPValidationError

GET /api/v1/observability/logs

Logs snapshot (last N)

Newest log records matching a LogsQL query. A query the backend cannot parse answers 400 with Invalid query: and the backend’s own diagnosis, which never echoes the query itself. A backend that is down answers 503.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
query query string no
limit query integer no

Responses

Status Description Schema
200 Successful Response -
422 Validation Error HTTPValidationError

GET /api/v1/observability/logs/stream

Logs SSE stream (append deltas)

Deltas for the same feed the logs snapshot reads. A query the backend cannot parse answers 400 with Invalid query: and the backend’s own diagnosis, which never echoes the query itself. A backend that is down answers 503. The stream ends itself with one terminal end event whose reason is credential_expired (refresh the token and reconnect), credential_revoked (sign in again), permission_revoked (the caller no longer holds the grant), lifetime_expired (the maximum stream lifetime; reconnect) or recheck_unavailable (the credential could not be re-checked several times running; reconnect with backoff). The checks run on stream ticks, which on a quiet feed happen every 20 seconds, so an end can lag by about that.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
query query string no

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
422 Validation Error HTTPValidationError

GET /api/v1/observability/logs/{logsql_endpoint}

VictoriaLogs /select/logsql proxy

Proxies to VictoriaLogs /select/logsql/{endpoint} on the local vlselect instance (co-located on the director node). All query parameters are forwarded as-is (GET only). See VictoriaLogs querying docs for supported endpoints and their parameters.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
logsql_endpoint path VictoriaLogsLogsqlEndpoint (query, tail, hits, facets, stats_query, stats_query_range, stream_ids, streams, stream_field_names, stream_field_values, field_names, field_values) yes VictoriaLogs /select/logsql/{endpoint} path segment. See querying docs.
query query string, nullable no LogsQL selector (upstream query). Used by query, tail, hits, facets, stats_query, stats_query_range, stream_ids, streams, stream_field_names, stream_field_values, field_names, field_values.
start query string, nullable no Time range start (Victoria timestamp format). query (optional window), hits, facets, stats_query_range, stream_ids, streams, stream_field_names, stream_field_values, field_names, field_values.
end query string, nullable no Time range end, exclusive [start, end). Same endpoints as start where applicable.
step query string, nullable no Histogram bucket width. hits, stats_query_range (e.g. 1h).
time query string, nullable no Evaluation instant for stats_query (not used by stats_query_range range API).
limit query string, nullable no Cap rows or facet/field results. query, facets, stream_ids, streams, field_values, etc., per VictoriaLogs docs.
offset query string, nullable no Pagination skip on query; timezone offset on hits / stats_query_range; delivery delay on tail - same parameter name, semantics per upstream endpoint.
timeout query string, nullable no Max query duration (e.g. 4.2s). Primarily query.
format query string, nullable no Response shape, e.g. csv for query.
start_offset query string, nullable no Historical lookback before live tail (e.g. 1h). tail only.
refresh_interval query string, nullable no Poll interval for new logs. tail only.
fields_limit query string, nullable no Max number of fields groups on hits.
ignore_pipes query string, nullable no Set to 1 to ignore LogsQL pipes where upstream supports it (hits, facets, …).
max_values_per_field query string, nullable no facets: cap distinct values per field.
max_value_len query string, nullable no facets: max length of field values to consider.
keep_const_fields query string, nullable no facets: set to 1 to include fields with a single constant value.
field query string, nullable no Field name for grouping or lookup. hits (repeatable in raw URL), stream_field_values, field_values. For multiple field= values use repeated query keys (OpenAPI shows a single value).
filter query string, nullable no Substring filter on names or values. stream_field_names, stream_field_values, field_names, field_values.
timezone query string, nullable no Bucket alignment / timezone for hits and stats_query_range when documented upstream.
extra_filters query string, nullable no Extra LogsQL filters applied by VictoriaLogs to all HTTP querying APIs (JSON or filter text).
extra_stream_filters query string, nullable no Extra stream filters applied by VictoriaLogs (JSON or stream filter text).
hidden_fields_filters query string, nullable no Hide specific log fields during execution (VictoriaLogs “hidden fields” API).

Responses

Status Description Schema
200 Successful response or upstream error body (status may vary). -
403 Forbidden. Insufficient permissions. -
422 Unknown logsql_endpoint path segment (not a VictoriaLogs logsql endpoint). -
503 Logs backend unreachable or request timed out. -

GET /api/v1/observability/metrics/query

Prometheus instant query proxy

Forwards only Prometheus instant-query parameters (query, time, timeout, step) to the Victoria Metrics /api/v1/query endpoint; other query parameter names are rejected. Upstream status, body, and end-to-end headers are forwarded; hop-by-hop headers (RFC 7230) and any names listed in Connection are stripped. Content-Length and Content-Encoding are omitted because the response body is returned already decoded. If Content-Type is missing on a 200 response, application/json is assumed; other status codes are not given a default type. Query parameters are validated with PrometheusInstantQueryParams; extra names yield 422.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
query query string, nullable no Prometheus expression (MetricsQL / PromQL-compatible instant query). Evaluated by the upstream VictoriaMetrics /api/v1/query endpoint.
time query string, nullable no Evaluation time as Unix timestamp or RFC3339 (Prometheus time).
timeout query string, nullable no Maximum evaluation timeout (Prometheus timeout), e.g. 5s.
step query string, nullable no Optional resolution step (VictoriaMetrics compatibility). Range queries use /api/v1/query_range on the upstream; this route proxies instant queries only.

Responses

Status Description Schema
200 Successful query or upstream error body (status may vary). -
403 Forbidden. Insufficient permissions. -
422 Unknown query parameter names (not in the allow-listed instant-query model). -
503 Metrics backend unreachable or request timed out. -

GET /api/v1/observability/metrics/query_range

Prometheus range query proxy

Forwards Prometheus range-query parameters (query, start, end, step, timeout) to the Victoria Metrics /api/v1/query_range endpoint; other query parameter names are rejected. Upstream status, body, and end-to-end headers are forwarded; hop-by-hop headers (RFC 7230) and any names listed in Connection are stripped. Content-Length and Content-Encoding are omitted because the response body is returned already decoded. If Content-Type is missing on a 200 response, application/json is assumed; other status codes are not given a default type. Query parameters are validated with PrometheusRangeQueryParams; extra names yield 422.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
query query string, nullable no Prometheus expression (MetricsQL / PromQL-compatible range query). Evaluated by the upstream VictoriaMetrics /api/v1/query_range endpoint.
start query string, nullable no Range start as Unix timestamp or RFC3339 (Prometheus start).
end query string, nullable no Range end as Unix timestamp or RFC3339 (Prometheus end).
step query string, nullable no Resolution step width as duration string (e.g. 60s, 5m) or float seconds.
timeout query string, nullable no Maximum evaluation timeout (Prometheus timeout), e.g. 5s.

Responses

Status Description Schema
200 Successful query or upstream error body (status may vary). -
403 Forbidden. Insufficient permissions. -
422 Unknown query parameter names (not in the allow-listed range-query model). -
503 Metrics backend unreachable or request timed out. -

GET /api/v1/observability/metrics/stream

Grouped metric SSE stream (append deltas for several keys)

Streams append deltas for every key in k over a single connection. Each event carries {"key": "<metric key>", "samples": [...]} so the client can route it to the right chart. Snapshots stay per-key (GET /observability/metrics/{key}).

Grouping keeps concurrent SSE connections low: browsers cap HTTP/1.1 connections at six per host, so one stream per chart would starve ordinary REST calls. Each key is still subscribed as its own broker feed, so clients requesting overlapping sets share one upstream poller per common key.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
step query integer no Resolution step (seconds); rounded up to a supported tier.
k query string yes Comma-separated metric keys, e.g. disk_throughput,disk_iops.

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
404 One or more keys in k are not registered metrics. -
422 Empty k, or more keys than the per-stream cap. -

GET /api/v1/observability/metrics/targets

List metrics targets

Returns a list of cluster nodes grouped by their type and state in Prometheus HTTP Service Discovery format. Each target is <node management IP>:<port> where the port is the observability agent (telegraf) Prometheus exporter serving /metrics on that node - 9273 by default. __meta_node_state is the PanFS node state, not the health of the scrape endpoint. Nodes that do not run the observability agent are still listed.

Authentication: required (PasswordLogin or BearerJWT).

Responses

Status Description Schema
200 Successful retrieval of metrics targets. array
400 Bad request due to invalid parameters or service error. -
401 Unauthorized. -
403 Forbidden. Insufficient permissions. -
404 Requested metrics target or resource not found. -
500 Internal server error. -

GET /api/v1/observability/metrics/{key}

Metric snapshot (range window)

Range-query snapshot for a named metric over the lookback window.

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
key path string yes
window query integer no Lookback window (seconds).
step query integer no Resolution step (seconds); rounded up to a supported tier.

Responses

Status Description Schema
200 Successful Response -
422 Validation Error HTTPValidationError

GET /api/v1/observability/metrics/{key}/stream

Metric SSE stream (append deltas)

SSE: append events as new metric samples arrive (deltas only).

Authentication: required (PasswordLogin or BearerJWT).

Parameters

Name In Type Required Description
key path string yes
step query integer no Resolution step (seconds); rounded up to a supported tier.

Responses

Status Description Schema
200 Server-Sent Events stream (text/event-stream). -
422 Validation Error HTTPValidationError

GET /api/v1/observability/storagesets/status

Storage-set alert status

Active-alert presence per storage set, resolved from one query over all PanFS alerts. Only sets carrying at least one critical or warning alert are listed - an absent set means no alerts. Callers combine this with the set’s node/spare counts to render its status badge.

Authentication: required (PasswordLogin or BearerJWT).

Responses

Status Description Schema
200 Successful Response array