observability

Observability

Documentation home

All four roles use internal/observe for JSON logs and a private Prometheus registry. Ordinary successful file operations stay at DEBUG. Failures are WARN; a successful file RPC requiring more than one HTTP attempt emits an INFO recovery summary. Raft diagnostics retain the existing WARN threshold. Log emission does not change quorum, replay identity or operation deadlines.

Library/caller fields named time, level, msg or component are preserved as diagnostic_time, diagnostic_level, diagnostic_msg or diagnostic_component, so they cannot replace the shared envelope.

Every production record has time, level, msg, component, operation, outcome, duration_seconds and request_id. Request-bound operations use a context correlation ID; file calls use the exact replay ID sent to workers. Asynchronous/background events use the explicit request_id="background" sentinel and zero duration when no operation duration exists. That sentinel is not an invented Raft request trace. Relevant calls additionally include volume, generation, replica or node identity. Failure records include bounded error_category and retry_decision; the latter describes diagnostic policy, not authorization to replay an arbitrary mutation.

Repeated WARN/ERROR and retry-recovery INFO records allow two records per 30-second window for each severity, operation, error category and operational identity. Diagnostic message classes also distinguish unrelated Raft/HTTP failures. Request IDs and changing error strings do not create new operation buckets. The limiter keeps at most 128 context buckets and one overflow bucket. The first emitted record in a subsequent window carries suppressed_count; suppression_scope="overflow" explicitly means a count shared across overflow contexts. If no later record arrives, the Prometheus suppression counter still records the suppressed events. Operation and retry metrics count every event, including events whose logs were suppressed. This policy bounds repeated failures, rather than hiding a stuck dependency behind an unlimited log stream.

Structured sensitive keys (authorization, token, password, credentials, private_key, tls.key, payload, data, file_contents) are redacted, including nested groups. Callers must still never place credentials or file contents in free-text messages, errors or arbitrary objects: key redaction is not a free-text secret detector. No endpoint, path, request ID, volume or generation is a metric label.

Metric Meaning and bounded labels
replicated_csi_operations_total One completion per logical operation; component, constant operation, outcome (success, error, timeout, canceled).
replicated_csi_operation_duration_seconds Entire logical operation, including retries; component, constant operation.
replicated_csi_logs_suppressed_total Suppressed records; component, source (operation, raft, http, diagnostic).
replicated_csi_client_attempts_total Calls to the HTTP client's Do, including initial attempts; component. It does not assert a TCP connection or delivered request.
replicated_csi_client_retries_total Additional HTTP attempts actually started; component, preceding reason (transport, unavailable, not_leader, response). Canceled backoff does not count as an attempt.
replicated_csi_client_endpoint_switches_total Configured member changes between actual attempts within one RPC; component.
replicated_csi_client_reconnects_total Logical file RPCs requiring multiple attempts; component, final outcome (recovered, failed). This is logical retry recovery, not TCP reconnects, keepalive reuse or application retries.

Retry summaries include actual attempt/switch counts and the four preceding failure-reason counts. A terminal permission, I/O or no-space error after a redirect is failed, not a claim that the deadline was exhausted. Observability does not alter the protocol's replay identity, endpoint selection, terminal admission errors or total deadline. The context hook receives one immutable summary value per call and does not introduce shared mutable per-client state. Counters are process-local and reset with the process. Non-client roles expose zero client counters; a scrape target supplies the process/Pod identity.

The 4.0.1 manager records the independent renewal pass as operation="reconcile_credentials" and each credential check/update as operation="ensure_credentials" in the operation counter and duration histogram. Failure logs correlate volume/generation and request IDs without credential contents; successful checks remain at DEBUG and actual renewals log at INFO. Renewal continues independently when lifecycle reconciliation or readiness fails. These operations are not available in the existing 4.0.0 deployment.

Replica progress and health

Replica-specific metrics below have no volume, generation, member, path or request ID labels. Identify a worker by its scrape target and process/Pod epoch. Counters reset when the worker process restarts; a counter delta across different epochs is not evidence of completed work.

Metric Unit and meaning Fixed labels
replicated_csi_raft_configured_replicas Number of fixed voting members, including unavailable members. Majority is floor(members / 2) + 1; four members require three votes. None
replicated_csi_raft_leader Boolean: this process currently considers itself the elected coordinator. This alone does not establish quorum. None
replicated_csi_raft_term Current locally known Raft term. A term change alone does not prove successful election or quorum. None
replicated_csi_raft_observed_leader_changes_total Changes in the known leader identity sampled by readiness checks, including transitions to/from no known leader. Repeated identical samples do not increment it. Short transitions between checks can be missed; this is not a count of every internal election. None
replicated_csi_raft_commit_index Latest committed Raft entry index known locally. None
replicated_csi_replica_applied_command_index Completed FSM command index, or completed baseline boundary after durable publication/validated restore. A baseline can include a later barrier/no-op boundary. None
replicated_csi_replica_apply_lag_entries Nonnegative local commit-index distance from the completed command/baseline index. Includes non-command entries, so a positive value does not necessarily mean unapplied file data. A disconnected replica cannot know the leader's newest commit index; this is not cluster-wide replication lag. None
replicated_csi_replica_journal_payload_bytes Retained serialized command bytes used for lifetime admission; excludes Raft/Bolt overhead, derived files and filesystem allocation. This is not free disk space or a filesystem quota. None
replicated_csi_replica_baseline_index Durable baseline boundary successfully published/restored by this FSM. Partial staging and rejected candidates do not advance it. None
replicated_csi_replica_baseline_restoring Boolean: isolated baseline replay is in progress. None
replicated_csi_replica_retired Boolean: the committed deletion fence has retired this generation. None
replicated_csi_baseline_active Number of currently active operations at that stage. stage: stage, send, restore
replicated_csi_baseline_processed_bytes_total Stream bytes staged or consumed, including unsuccessful attempts. Same stage values
replicated_csi_baseline_replayed_commands_total Commands successfully replayed into isolated candidates, including candidates rejected by a later validation/publication failure. None
replicated_csi_baseline_operations_total Completed stage operations. An idempotent second sink close does not count twice. Same stage values; outcome: success, error, canceled
replicated_csi_baseline_duration_seconds Stage duration histogram, from accepted operation start through completion. Same stage values
replicated_csi_replica_readiness_reason One active reason is 1; other initialized reasons are 0. reason, listed below
replicated_csi_replica_readiness_transitions_total Published reason changes, including initial starting. Repeated checks with the same reason do not increment it. Same reason values

stage means an accepted snapshot sink writing its private validation spool. It includes both locally generated baselines and incoming transfers; it is not a pure network-receive counter. Success requires validated durable publication. Cancel records an abandoned sink, including an interrupted incoming transfer; validation or publication failure on close records an error. Admission failures before a sink is created are not stage operations.

send measures bytes read by the outbound InstallSnapshot transport and its accepted/rejected result. Consumed bytes are not TCP acknowledgements or proof that a peer durably published them. restore measures bytes consumed and commands replayed while rebuilding an isolated candidate. Success requires validation and publication; discarded candidate work still contributes to attempted progress. There is no percentage-complete or resumable-transfer claim. Baselines retain the complete bounded command history; these metrics do not change membership, lifetime limits or authority recovery rules.

Completed-state gauges use atomic mirrors. Their values advance after a mutation or baseline publication completes, while progress counters remain available during replay. A metrics scrape does not acquire the filesystem mutex. Compare source/target commit and baseline indexes, validated operation outcomes and actual file results when qualifying catch-up; neither Ready nor a byte counter alone proves it.

Journal and snapshot I/O timing

Workers expose the following storage timing metrics. They were introduced after a historical no-fault failure; their presence and later captured samples do not establish that failure's cause or a performance improvement.

Metric Meaning Fixed labels
replicated_csi_storage_io_active Calls currently waiting for or performing the named storage operation. operation, from the sixteen values below
replicated_csi_storage_io_operations_total Completed calls. Errors include normal missing-log or missing-key results; an error count alone is not a corruption alarm. Same operation; outcome: success, error
replicated_csi_storage_io_duration_seconds Wall duration, including waits inside the named call; completed calls only. Same operation

Journal operations are journal_first_index, journal_last_index, journal_get_log, journal_store_log, journal_store_logs, journal_delete_range, journal_get, journal_set, journal_get_uint64 and journal_set_uint64. The wrapper preserves the concrete underlying store's optional methods, return values, error identities, transaction ordering and durability. It adds no retry or deadline. Startup authority validation uses the original store; these timings cover subsequent Raft/FSM journal accesses.

Snapshot operations are snapshot_open_published, snapshot_validate_published, snapshot_validate_staged, snapshot_copy, snapshot_publish_wait and snapshot_publish_close. The first measures HashiCorp FileSnapshotStore Open, including its complete CRC scan before returning the reader. Application-format validation of that returned stream is timed separately. Staged-candidate validation includes rewinding its spool; copy measures the underlying snapshot stream write. Publication wait measures acquisition of the snapshot-store mutex, and publication close measures the underlying durability/publication/ reaping call while that mutex is held. A local journal_delete_range interval can expose later log-compaction delay. These spans are components of existing work; do not sum them with their containing baseline-stage duration as if they were independent operations.

Histogram finite bounds are 0.001, 0.01, 0.1, 1, 3, 5, 15, 30, 60 and 120 seconds. A blocked call appears in the active gauge before its histogram or outcome counter changes. Scrapes do not acquire journal, filesystem or snapshot-store locks. The inner timing hooks perform no synchronous JSON log writes, because their caller can already hold those locks; correlate existing logical-operation logs and their replay IDs with same-epoch metrics instead. Keys, paths, filenames, volume IDs, mount IDs and credentials are never labels.

Interpreting replication lag

replicated_csi_replica_apply_lag_entries is local apply lag, not the distance behind another replica. An isolated follower can report zero after applying everything it knows, while the coordinator continues committing new work. For a leader-relative estimate, compare a fresh coordinator commit index with each same-generation worker's completed command/baseline index. The staging catch-up harness captures those actual same-group indexes alongside transfer outcomes and file checks; it does not treat the local gauge as cluster-wide lag.

The following bounded instant query uses the existing qualification collector's namespace, pod and role target labels. Replace the example volume ID in both selectors. Before interpreting it, verify exactly one fresh, ready leader for that fixed group and unchanged Pod/container and generation identities. It omits down/stale targets rather than reporting them as caught up. volume is derived only in this query from the immutable worker Pod name; it is not a new exported label, recording rule or alert.

clamp_min(
  max by (namespace, volume) (
    label_replace(
      (
        replicated_csi_raft_commit_index{namespace="kube-system",role="replica",pod=~"rv-0123456789abcdef01234567-r[0-3]"}
        and (timestamp(replicated_csi_raft_commit_index) > time() - 30)
        and on (namespace, pod) (replicated_csi_raft_leader == 1)
        and on (namespace, pod) (replicated_csi_ready{component="replica"} == 1)
        and on (namespace, pod) (up == 1)
      ),
      "volume", "$1", "pod", "(rv-[0-9a-f]{24})-r[0-3]"
    )
  )
  - on (namespace, volume) group_right
  label_replace(
    (
      replicated_csi_replica_applied_command_index{namespace="kube-system",role="replica",pod=~"rv-0123456789abcdef01234567-r[0-3]"}
      and (timestamp(replicated_csi_replica_applied_command_index) > time() - 30)
      and on (namespace, pod) (up == 1)
    ),
    "volume", "$1", "pod", "(rv-[0-9a-f]{24})-r[0-3]"
  ),
  0
)

The result retains each worker's target labels and measures an entry-index distance, not bytes, elapsed replication time or missing file writes. Barrier and no-op entries, independent scrape times and publication timing affect it; clamping a negative sample to zero does not establish synchronization. Fresh scrapes and sampled readiness also do not establish current quorum. During an election or ambiguous leader observation, defer this comparison and inspect the captured identities and protocol outcomes.

Readiness and liveness

The bounded readiness reasons are starting, ready, no_leader, quorum_unavailable, catching_up, journal_unavailable, restoring, retired, materialization_failure, check_expired, check_busy and shutdown. check_busy means a concurrent publication/state check prevented a safe completed answer; check_expired means the bounded readiness check expired. The replicated_csi_ready{component="replica"} gauge and /readyz represent the last published outcome. Reason transitions also produce structured operation logs; IDs remain log attributes, and repeated identical reasons do not generate logs.

The serving loop initiates checks on a one-second ticker and gives each check a two-second deadline. It retains the last completed result while the next check runs, but an independent expiry callback publishes unready even if a synchronous filesystem check stalls. Readiness publication and reason updates do not wait for a blocked diagnostic log writer. Checks are serialized; a slow check can delay the next tick. /healthz remains process liveness and returns 200 during missing quorum, catch-up or restore. Sticky materialization failure causes the serving worker to stop; lack of quorum alone does not trigger a restart.

A ready leader must establish current quorum and complete its committed prefix. A follower uses leader contact within two seconds and locally completed state; its readiness can briefly outlive quorum loss and never authorizes direct file I/O. File requests still require the verified coordinator. Retired, restoring, failed or expired workers are unready. These diagnostics are sampled operational evidence, not an alternative to the protocol's read/write authority checks.

Monitoring pack and inventory

The schema-1 monitoring pack supplies bounded recording rules, alert definitions and a Grafana dashboard. Load them into the platform monitoring stack and configure its existing notification routing; the driver does not deploy a collector or external receiver.

Every manager, including lease followers, refreshes a read-only API inventory every five seconds with a ten-second deadline. Lifecycle writes remain elected. A failed or partial inventory leaves its previous gauges and freshness stamp unchanged; it never publishes zero as a successful observation. This prevents an old leader's stale positive counts persisting indefinitely after takeover. HA recording rules use maximum per namespace, rather than summing duplicate inventories. A separate stale-inventory alert makes API uncertainty visible.

Metric Bounded labels and interpretation
replicated_csi_volume_availability state: unavailable when observed ready workers are below original majority, degraded between majority and desired count, healthy at desired count; active volumes only. These are observations, not current data-plane latency guarantees.
replicated_csi_cleanup_oldest_seconds reason: the same four fixed cleanup reasons as cleanup_pending; age of the oldest unchanged corresponding lifecycle status transition. Zero means no observed blocker in that reason.
replicated_csi_inventory_last_success_timestamp_seconds No application labels; manager wall-clock Unix time of its last complete inventory. Require synchronized clocks and fresh scrapes before interpreting age.
replicated_csi_durable_handles No application labels; durable handle records, including expired leases awaiting quorum-ordered maintenance.
replicated_csi_unlinked_objects No application labels; unlinked primary objects retained by durable handles or hardlink references.
replicated_csi_reclaimed_objects_total No application labels; local unlinked objects removed after final durable handle and namespace references disappear. Counts are not reclaimed bytes or capacity reservations.

Replica metrics expose current process state, not unique global object counts; never sum replica copies to infer logical files or compare deltas across Pod restarts. Exact volume drill-down uses the GET-only support bundle, preserving bounded exported application labels.

Shared NODE workers in 4.1.0

The replica host exposes replicated_csi_host_workers{state} with the fixed states starting, ready, unavailable, uncertain, replica_state_lost and stopping. Volume/generation/member identities remain log fields, not metric labels. Per-worker registries remain separate and are reachable through each replica Service's metrics port; update service discovery accordingly. Host readiness never means all hosted workers have quorum.

Operation counters/durations cover replica_host_reconcile, replica_open, replica_serve, replica_endpoint_refresh, backing_publish, backing_unpublish, runtime_transition and retire_node_controllers. Known retained-state loss uses error_category="data_loss" and the volume status reason ReplicaStateLost; no exact application-file loss is invented. The optional local-CSI consumer extension exposes bounded publish/unpublish outcome counters at its existing health listener's /metrics endpoint and emits JSON diagnostics.