LOGS.md
Scope
This document defines the human-readable log format for Kron.
The log format must:
Be readable without external tooling.
Be deterministic and reproducible.
Allow operators to answer “why did this run at this time?”
Be parseable by log aggregation systems.
Remain stable across minor releases.
Logs are structured, single-line, key-value entries.
Log Principles
One event per line.
No multiline entries.
No hidden state.
All scheduling decisions are fully explainable from log content.
Stable field names.
Timestamps are always RFC3339 with nanosecond precision in UTC.
Log Format
Each line has:
<timestamp> level=<level> component=<component> event=<event> <fields...>
Example:
2026-03-01T09:58:12.483920381Z level=INFO component=scheduler event=decision namespace=prod name=db-backup period=2026-03-01T00:00:00Z nominal=2026-03-01T00:00:00Z window_start=2026-03-01T00:00:00Z window_end=2026-03-01T03:00:00Z distribution=uniform seed_hash=4f8c2a13 chosen=2026-03-01T01:42:18Z
Fields are:
space-separated
key=value
values containing spaces are quoted with double quotes
quotes escaped with
\"
Levels
Levels:
DEBUGINFOWARNERROR
Default production level is INFO.
Components
Component values:
schedulercontrollerexecutorconstraintsseedpolicyreconciler
Core Events
decision
Emitted when a scheduling decision is computed.
Fields:
namespacenameperiodnominalwindow_modewindow_startwindow_enddistributiondist_paramsseed_strategyseed_hashsaltchosentimezone
Example:
2026-03-01T00:00:00.001234567Z level=INFO component=scheduler event=decision namespace=prod name=db-backup period=2026-03-01T00:00:00Z nominal=2026-03-01T00:00:00Z window_mode=after window_start=2026-03-01T00:00:00Z window_end=2026-03-01T03:00:00Z distribution=uniform dist_params="" seed_strategy=stable seed_hash=4f8c2a13 salt=backup chosen=2026-03-01T01:42:18Z timezone=UTC
reschedule
Emitted when a decision changes due to spec update.
Fields:
namespacenameperiodprevious_chosennew_chosenreason
trigger
Emitted when chosen time is reached and execution is attempted.
Fields:
namespacenameperiodchosennow
job_created
Emitted when a Job is successfully created.
Fields:
namespacenameperiodjobuidchosen
job_exists
Emitted when a Job already exists for the period.
Fields:
namespacenameperiodjobuid
skipped_concurrency
Emitted when execution is skipped due to concurrency policy.
Fields:
namespacenameperiodpolicyactive_job
replaced_job
Emitted when an active Job is replaced.
Fields:
namespacenameperiodold_jobnew_job
missed_deadline
Emitted when execution is skipped because deadline was exceeded.
Fields:
namespacenameperiodchosendeadlinenow
constraint_reject
Emitted when a candidate time is rejected due to constraints.
Fields:
namespacenameperiodcandidatereason
Multiple constraint_reject events may be emitted for a single decision when sampling multiple candidates.
constraint_unsatisfiable
Emitted when no valid time can be found in the window.
Fields:
namespacenameperiodwindow_startwindow_endreason
error
Emitted on operational errors.
Fields:
namespacenameperiod(if applicable)operationerror
Seed Transparency
When computing the seed, a DEBUG log is emitted:
Event:
event=seed_computed
Fields:
namespacenameperiodseed_strategyresource_uidperiod_keysaltseed_hash
Example:
2026-03-01T00:00:00.000112233Z level=DEBUG component=seed event=seed_computed namespace=prod name=db-backup period=2026-03-01T00:00:00Z seed_strategy=stable resource_uid=7f12a8 period_key=2026-03-01T00:00:00Z salt=backup seed_hash=4f8c2a13
Distribution Transparency
When computing a candidate time:
Event:
event=sample
Fields:
namespacenameperioddistributionraw_valuemapped_offset_nscandidate
Example:
2026-03-01T00:00:00.000223344Z level=DEBUG component=scheduler event=sample namespace=prod name=db-backup period=2026-03-01T00:00:00Z distribution=uniform raw_value=0.57382912 mapped_offset_ns=6138000000000 candidate=2026-03-01T01:42:18Z
Human Explanation Mode
When verbose logging is enabled, Kron emits a structured explanation block as sequential INFO lines:
Events:
explain_startexplain_stepexplain_resultexplain_end
Example:
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_start namespace=prod name=db-backup period=2026-03-01T00:00:00Z
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_step detail="cron resolved nominal time"
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_step detail="window after 3h => [00:00,03:00]"
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_step detail="uniform distribution selected 0.5738"
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_result chosen=2026-03-01T01:42:18Z
2026-03-01T00:00:00Z level=INFO component=scheduler event=explain_end namespace=prod name=db-backup period=2026-03-01T00:00:00Z
Explanation mode is optional and disabled by default.
Ordering Guarantees
For a given KronJob and period:
decisionmust appear beforetrigger.triggermust appear beforejob_createdorskipped_*.If constraints are evaluated,
constraint_rejectmust appear beforedecisionfinalization.seed_computedmust appear beforesample.
Stability Guarantees
Field names will not change in stable API versions.
Additional fields may be appended.
Field ordering within a line is not guaranteed.
Events will not be renamed in stable API versions.
Log Compatibility Modes
Kron supports:
text(default, as defined here)json(same fields serialized as structured JSON)
In JSON mode, each line is a single JSON object with identical field keys.
Example:
{"timestamp":"2026-03-01T00:00:00Z","level":"INFO","component":"scheduler","event":"decision","namespace":"prod","name":"db-backup","period":"2026-03-01T00:00:00Z","nominal":"2026-03-01T00:00:00Z","window_mode":"after","window_start":"2026-03-01T00:00:00Z","window_end":"2026-03-01T03:00:00Z","distribution":"uniform","seed_strategy":"stable","seed_hash":"4f8c2a13","chosen":"2026-03-01T01:42:18Z"}