Skip to content

Log worker records as JSON with a pluggable formatter - #44

Merged
codingjoe merged 6 commits into
mainfrom
codingjoe-json-log-formatter
Sep 7, 2026
Merged

Log worker records as JSON with a pluggable formatter#44
codingjoe merged 6 commits into
mainfrom
codingjoe-json-log-formatter

Conversation

@codingjoe

Copy link
Copy Markdown
Owner

Why

The multiprocessing logger's format was hardcoded to a single text layout. This PR makes worker logs JSON by default (one object per line, easy to ingest for log collectors) while keeping the formatter pluggable, as requested.

What changed

  • JsonFormatter (new default): one JSON object per log record with created_at (ISO 8601 UTC), level, logger, message, process, process_name, thread, plus an exception field with the traceback when present.
  • TaskExecutor(log_formatter=...) accepts any logging.Formatter instance and is the single owner of the JSON default. The formatter is passed to every WorkerProcess and applied in both the parent and child processes, so workers spawned via the spawn start method (which re-import the module) log with the same formatter.
  • manage.py threadmill worker --log-format '%(levelname)s %(message)s' accepts a free-form logging format string for human-readable output. Omitting the option keeps JSON.

Non-obvious details

  • Invalid format strings fail fast with CommandError. logging.Formatter only checks that the string contains at least one valid field, so mixed strings like '%(message)s 100% done' pass construction but raise TypeError on every emit, silently dropping all log records in the parent and all workers. The command therefore smoke-tests the formatter on a real LogRecord and catches TypeError/ValueError before any handler is touched.
  • An explicitly empty --log-format '' is honored as a format string (message-only output); only the absent option falls back to JSON.
  • WorkerProcess now requires log_formatter as a keyword-only argument. logging.Formatter instances are picklable, which is what makes the spawn path work.

Tests cover every branch of the new option (format string, JSON default, empty string, invalid input) and keep patch coverage at 100%.

codingjoe and others added 2 commits September 5, 2026 17:12
Replace the hardcoded multiprocessing log formatter with a new
JsonFormatter default and a TextFormatter preset. The formatter is
swappable via TaskExecutor(log_formatter=...) and the new
--log-format json|text worker option; spawned worker processes
receive and apply the configured formatter.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the json|text presets with a free-form logging format string:
--log-format '%(levelname)s %(message)s' wraps the string in
logging.Formatter, while omitting the option keeps the JSON default.
Invalid format strings fail fast with CommandError via a smoke-test
emit on a real LogRecord, before any handler is touched.

TaskExecutor.log_formatter remains the single owner of the JSON
default; WorkerProcess now requires the formatter as a keyword-only
argument and applies it directly on the shared handler.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread threadmill/executor.py Outdated
codingjoe and others added 4 commits September 7, 2026 11:59
Serialize log records with DjangoJSONEncoder instead of casting the
datetime to an ISO string, and stamp records with Django's current
timezone rather than hardcoded UTC.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Merge non-standard LogRecord attributes (set via logging's extra={})
into the JSON payload as top-level fields. Values must be
JSON-serializable, matching how normalize_json treats task return
values.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@codingjoe
codingjoe merged commit 0fc4d7a into main Sep 7, 2026
4 checks passed
@codingjoe
codingjoe deleted the codingjoe-json-log-formatter branch September 7, 2026 10:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant