PhoenixKit.Modules.Storage.BucketLog (phoenix_kit v2.52.2)

Copy Markdown View Source

What went wrong with a site storage bucket, and what its probes said (V208).

Manager reports a write, read or delete that failed (record_failure/3), and Storage.probe_bucket/1 reports every probe of a saved bucket (record/4). The bucket's own page reads it back (recent/2, summary/1).

  • Failures only. A successful write or read is not recorded — on a busy site that would be a row per request. Latency over time therefore comes from the probes.
  • A miss is not a failure. A bucket that does not hold an object is the normal case during failover; a "not found" reply is not logged.
  • A repeat is one row. The same failure of the same kind on the same bucket within a minute from its first occurrence bumps count and last_at instead of adding a row, so a bucket that is down does not write a row per request.
  • Site buckets only. A user's own bucket (V206) is private to them and is never logged here; neither is a bucket that has no uuid yet (a form's unsaved test).
  • Never in the way. Writing is best effort: record_failure/3 runs in the background (a dedicated supervisor capped at four tasks), swallows every error, and never queries the database in the read or write that reported it. If the supervisor is absent or full, the diagnostic is dropped.

Rows are pruned daily to bucket_log_retention_days (default 30) by Workers.BucketLogPruneWorker.

Summary

Functions

Removes every entry of a bucket (it was deleted). Returns how many.

The kinds of entry.

Deletes the entries last seen before the retention. Returns how many.

The bucket's entries, newest first: %{entries, page, total_pages, total}. Options: :page (1), :per_page (10), :filter (:all, or :failures).

Writes an entry now: :ok, or :skipped for a bucket that is not logged or a write that did not happen (the table is unreachable). Options: :message, :latency_ms. A repeat of a failure that is not a probe, within a minute, bumps the earlier row instead.

Reports that kind ("write", "read" or "delete") failed on bucket, with the provider's reason. Returns :ok at once; the row is written in the background. A missing object is ignored for reads and deletes, but never for writes.

How long entries are kept, in days (bucket_log_retention_days, default 30).

A controlled diagnostic for persistence and display. Provider response bodies, headers, URLs, keys and arbitrary exception text are never copied. Unknown errors deliberately lose detail; server-side provider diagnostics remain the place to investigate them.

The bucket's log at a glance: %{failures_24h, last_failure, last_probe, probes}. failures_24h counts every failure seen in the last day (a row that merged repeats counts them all, with at most one minute of boundary approximation); probes are the latest probes, oldest first, for the latency chart.

Functions

delete_for_bucket(bucket_uuid)

@spec delete_for_bucket(term()) :: non_neg_integer()

Removes every entry of a bucket (it was deleted). Returns how many.

kinds()

@spec kinds() :: [String.t()]

The kinds of entry.

prune()

@spec prune() :: non_neg_integer()

Deletes the entries last seen before the retention. Returns how many.

recent(bucket_uuid, opts \\ [])

@spec recent(term(), keyword()) :: map()

The bucket's entries, newest first: %{entries, page, total_pages, total}. Options: :page (1), :per_page (10), :filter (:all, or :failures).

record(bucket, kind, ok?, opts \\ [])

@spec record(map() | nil, String.t(), boolean(), keyword()) :: :ok | :skipped

Writes an entry now: :ok, or :skipped for a bucket that is not logged or a write that did not happen (the table is unreachable). Options: :message, :latency_ms. A repeat of a failure that is not a probe, within a minute, bumps the earlier row instead.

record_failure(bucket, kind, reason)

@spec record_failure(map() | nil, String.t(), term()) :: :ok

Reports that kind ("write", "read" or "delete") failed on bucket, with the provider's reason. Returns :ok at once; the row is written in the background. A missing object is ignored for reads and deletes, but never for writes.

retention_days()

@spec retention_days() :: pos_integer()

How long entries are kept, in days (bucket_log_retention_days, default 30).

safe_message(reason)

@spec safe_message(term()) :: String.t() | nil

A controlled diagnostic for persistence and display. Provider response bodies, headers, URLs, keys and arbitrary exception text are never copied. Unknown errors deliberately lose detail; server-side provider diagnostics remain the place to investigate them.

summary(bucket_uuid)

@spec summary(term()) :: map()

The bucket's log at a glance: %{failures_24h, last_failure, last_probe, probes}. failures_24h counts every failure seen in the last day (a row that merged repeats counts them all, with at most one minute of boundary approximation); probes are the latest probes, oldest first, for the latency chart.