Skip to content

Reports and Metrics

rhoopr edited this page Jun 1, 2026 · 1 revision

Reports and Metrics

kei can write machine-readable sync status for service, Docker, and watch-mode deployments.

JSON sync report

Set a report path in TOML:

[report]
json = "/config/sync_report.json"

kei atomically rewrites the file after each completed sync cycle. Skipped watch wakeups do not overwrite the previous report.

The report includes:

  • version, kei_version, timestamp, and cycle status
  • resolved run options with no secrets
  • counters for seen, downloaded, failed, skipped, bytes downloaded, bytes written, rate limiting, EXIF failures, state-write failures, and enumeration errors
  • pagination shortfall warnings and affected asset counts
  • sync-token safety fields such as sync_token_blocked, reason, source, explanation, affected zone, and token receiver counts
  • full_enumeration_reason when kei used full enumeration instead of incremental sync
  • a capped failed_assets sample with failed_assets_truncated when more rows exist

status is one of success, partial_failure, interrupted, or session_expired.

Full enumeration reasons

full_enumeration_reason uses a bounded vocabulary so dashboards can group it safely:

Reason Meaning
no_stored_token First run, reset token, or no usable zone token
retry_failed_rows Failed rows need another full look before retry
pending_rows Pending rows from an earlier run still need work
metadata_backfill Metadata rewrite/backfill work needs a full asset view
album_relation_hydration_incomplete Album membership data is not trusted enough for incremental routing yet
enum_config_hash_drift Enumeration-affecting config changed
download_config_hash_drift Path-affecting download config changed
explicit_retry_failed The run was started with --retry-failed
other_static_reason A less specific safe fallback path was used

See State Tracking for the sync-token side of the same behavior.

Prometheus metrics

The HTTP server exposes /metrics when watch or service mode is running:

[server]
bind = "0.0.0.0"
port = 9090

Common counters include:

  • kei_sync_assets_seen_total
  • kei_sync_downloaded_total
  • kei_sync_failed_total
  • kei_sync_skipped_total{reason="..."}
  • kei_sync_enumeration_errors_total
  • kei_sync_token_blocked_cycles_total
  • kei_sync_full_enumeration_reason_total{reason="..."}

kei_sync_cycle_duration_seconds reports the most recent cycle duration.

Docker exposes the same endpoint inside the container. Publish the port if your Prometheus server runs outside the container.

Health

The HTTP server also exposes /healthz. Docker's packaged healthcheck curls port 9090 inside the container.

kei writes health.json under the data directory after sync cycles. In Docker, that is /config/health.json.

Notification scripts

Set a script path in TOML:

[notifications]
script = "/config/notify.sh"

The script receives KEI_EVENT, KEI_MESSAGE, KEI_ICLOUD_USERNAME, and sync summary variables such as KEI_ASSETS_SEEN, KEI_DOWNLOADED, KEI_FAILED, KEI_SKIPPED, KEI_ENUMERATION_ERRORS, KEI_SYNC_TOKEN_BLOCKED, and skip-breakdown counters.

Scripts run with a bounded timeout. On Windows, configured notification scripts are ignored.

Related

Commands

Getting Started

Features

Clone this wiki locally