Skip to content

Use contextvars for the log context and add log_context - #52

Merged
markbac merged 1 commit into
mainfrom
feat/21-contextvars
Oct 3, 2026
Merged

markbac merged 1 commit into
mainfrom
feat/21-contextvars

Conversation

@markbac

@markbac markbac commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Summary

The global log context used threading.local, which does not follow asyncio tasks: concurrent tasks on one thread shared, and overwrote, each other's context.

Changes

  • Store the context in a contextvars.ContextVar. Threads and tasks each get their own value. A new thread still starts empty, as before, and set_log_context now stores a copy of its arguments.
  • Add log_context(**fields), a context manager that merges fields over the active context and restores the previous one on exit, including when the block raises. Blocks nest.
  • Export it from the package root, document it in the README and the changelog.
  • Tests: restoration, exceptions, nesting, records inside and outside the block, isolation between concurrent asyncio tasks, and the stored context being a copy.

Verification

  • pytest: 111 passed (latest dependencies) and 93 passed with 18 skipped (no extras). ruff and mypy --strict are clean.

Closes #21

🤖 Generated with Claude Code

https://claude.ai/code/session_01U2nYHVGDdthQpcwNBPbp8r


Generated by Claude Code

## Summary

The global log context used `threading.local`, which does not follow `asyncio` tasks: concurrent tasks on one thread shared, and overwrote, each other's context.

## Changes

- Store the context in a `contextvars.ContextVar`. Threads and tasks each get their own value. A new thread still starts empty, as before, and `set_log_context` now stores a copy of its arguments.
- Add `log_context(**fields)`, a context manager that merges fields over the active context and restores the previous one on exit, including when the block raises. Blocks nest.
- Export it from the package root, document it in the README and the changelog.
- Tests: restoration, exceptions, nesting, records inside and outside the block, isolation between concurrent `asyncio` tasks, and the stored context being a copy.

## Verification

- `pytest`: 111 passed (latest dependencies) and 93 passed with 18 skipped (no extras). `ruff` and `mypy --strict` are clean.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U2nYHVGDdthQpcwNBPbp8r
@markbac
markbac merged commit 6ff266c into main Oct 3, 2026
9 checks passed
@markbac
markbac deleted the feat/21-contextvars branch October 19, 2026 08:53
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.

Feature: async-safe context via contextvars, with a context manager

2 participants