Schedule icon
List icon
OutputValues icon
If icon
Fail icon
Loop icon
Count icon
Query icon
Fetch icon
IonToJson icon
Write icon
Concat icon
Labels icon
Log icon
SlackIncomingWebhook icon
Set icon
Delete icon

Nightly digest of failed Kestra executions with their ERROR log lines per namespace

Nightly Kestra failure digest with executions.Count, executions.Query and logs.Fetch. ERROR lines of failed runs land in one JSON Lines file, the first error of each run goes to Slack, bad namespaces are dead-lettered in KV.

Categories
CoreInfrastructure

"What failed last night, and why" usually means opening the Executions page, filtering by FAILED and clicking into each run. This flow does that through the Kestra API once a night for the instance it runs on: it counts executions and failures per namespace for the window, fetches the logs of the recent failed executions, keeps the ERROR lines, writes them to one JSON Lines file and posts the first error of each failed run to Slack. Nothing on the instance is modified.

It is the companion of kestra-instance-snapshot-and-drift-manifest, which backs up the flows themselves; the two run on their own schedules and hold their own state.

How it works

  1. The nightly Schedule (02:45) or a manual run starts the flow. checks block the execution before it exists when window_hours or max_failed_per_namespace is out of range, exclude_namespaces is not a JSON array of strings, namespace_prefix has invalid characters, or kestra_api_url ends with a slash.
  2. discover_namespaces (namespaces.List, existingOnly: false) lists every namespace under the prefix; scope removes the excluded ones and fixes a window ending at trigger.date, so a recovered run covers its own night. A prefix that matches nothing fails the run in refuse_empty_scope.
  3. failures is a Loop over the namespaces, two at a time, transmitFailed: false. Each iteration counts all and FAILED executions of the window (executions.Count) and lists the recent failed ones (executions.Query, page: 1 with size). The Loop outputs give one row per namespace with an ok flag and digest_truncated when the namespace had more failures than the limit.
  4. error_digest is a second Loop, one iteration per failed execution across all namespaces: logs.Fetch reads its logs into an ION file, IonToJson and a jq pick keep the ERROR lines and add the execution id, storage.Write saves them as JSON Lines.
  5. summary aggregates, digest_file concatenates the files (or writes an empty one so the output always exists), label sets three digest_* execution labels, log_summary prints the report, notify_digest posts to Slack when at least one execution failed, and dead_letter stores namespaces whose counts failed in KV for 7 days and fails the run.

What this blueprint teaches

  • The Kestra plugin against its own instance: namespaces.List, executions.Count, executions.Query and logs.Fetch share kestraUrl, tenantId and an auth object (username and password, or apiToken). On 2.0 pluginDefaults is no longer a flow property, so they repeat per task.
  • Reading another execution's logs: logs.Fetch with namespace, flowId and executionId. On 2.0.5 its level: ERROR still returned DEBUG and WARN lines and the ION rows carry taskId as {present: true}, which breaks FilterItems on that file; JSON Lines plus a jq pick works.
  • Loop rows that survive failures: transmitFailed: false on both loops and an ok flag per row, so one namespace with a broken API call, or one execution whose logs cannot be read, does not stop the digest.
  • A bounded digest: max_failed_per_namespace caps the log calls; the row says when the cap was hit and the Slack message shows at most 20 runs and points at the file for the rest.
  • State in KV with ttl: dead-letter list (P7D) and last run (P90D); a stopped flow leaves no state behind.

What you get

  • error_digest: JSON Lines with namespace, flow id, execution id, timestamp and message of every ERROR line of the window.
  • error_digest_rows: one row per failed execution with its ERROR line count and first error message; namespaces: execution and failure counts per namespace.
  • In Slack: one message per night with failures, the first error of each failed run and the execution link.

Prerequisites

  • Kestra 2.0 with the Kestra, Serdes and Slack plugins; an API user that can read namespaces, executions and logs (vars.tenant is main on OSS); kestra_api_url reachable from the worker.
  • Secrets KESTRA_API_USERNAME and KESTRA_API_PASSWORD (required) and SLACK_WEBHOOK_URL (optional, every message is also in the logs and the Slack tasks have allowFailure: true).

Quick start

  1. Add the secrets and run with the defaults: every namespace except system, the last 24 hours, up to 10 failed executions per namespace. log_summary lists each failed run with its first ERROR line; with failures in the window the Slack message arrives.
  2. Run with namespace_prefix set to a namespace without failures: the digest file is empty, notify_digest is skipped and the labels read 0.
  3. Leave the nightly trigger on; recoverMissedSchedules: LAST writes one digest after an outage, not one per missed night.

Error handling

  • Bad inputs never create an execution (checks). An unreachable API or a wrong password fails discover_namespaces; the errors branch reads errorLogs() once into first_error, logs task and message with the execution link and sends a Slack alert.
  • A namespace whose counts fail is dead-lettered in kestra_error_digest_failed_namespaces for 7 days and report_partial_failure fails the run naming it; an execution whose logs cannot be read gets ok: false in its row and is listed in unreadable_logs, never a failed digest.
  • concurrency limit: 1 with CANCEL stops a manual run during the nightly one; finally always writes kestra_error_digest_last_run with the counts reached.

How to adapt

  • Set window_hours to the gap between runs and max_failed_per_namespace to what your Slack channel can read; raise the cron frequency for an hourly digest.
  • Copy the digest file to object storage after digest_file, or replace notify_digest with a Subflow that opens a ticket per failed flow.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.