Skip to content

Move configure_logging() from module level to lifespan#11

Merged
JuliusScheuerer merged 1 commit into
mainfrom
worktree-move-logging-to-lifespan
Mar 25, 2026
Merged

Move configure_logging() from module level to lifespan#11
JuliusScheuerer merged 1 commit into
mainfrom
worktree-move-logging-to-lifespan

Conversation

@JuliusScheuerer
Copy link
Copy Markdown
Owner

Summary

  • Move configure_logging() call from module-level (import-time side effect) into the lifespan context manager
  • Importing the app module no longer triggers logging configuration
  • Per PYTHON-RULES.md §4: no side effects in module-level code

Test plan

  • make check passes (275 tests, 95.64% coverage)

Importing the app module no longer triggers logging configuration as a
side effect. Logging is now configured inside the lifespan context
manager, before the analyzer engine loads. structlog loggers are lazy
and work correctly before configuration.
@JuliusScheuerer JuliusScheuerer merged commit f6e534d into main Mar 25, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 25, 2026

Greptile Summary

This PR moves the configure_logging() call from module-level (import-time) into the lifespan context manager in src/document_anonymizer/api/app.py, eliminating a side effect that ran unconditionally on every import of the app module.

  • configure_logging() is now the first statement executed in lifespan(), ensuring structlog is configured before any logging occurs during startup.
  • The module-level logger = structlog.get_logger(__name__) remains at module level, which is correct — structlog.get_logger() is a lazy proxy and no logging configuration is triggered on creation; all actual log calls happen inside lifespan() after configure_logging() has run.
  • The global_exception_handler also uses logger, but it only executes during live request handling (post-startup), so logging will always be configured by the time it fires.
  • The docstring is updated to reflect the expanded responsibility of the lifespan function.
  • The change is minimal, well-scoped, and aligns with the project's no-module-level-side-effects policy.

Confidence Score: 5/5

  • This PR is safe to merge — it is a clean, focused refactoring with no logic changes and correct startup ordering preserved.
  • The change is a two-line move with no functional risk: configure_logging() is called as the very first statement in lifespan(), before any logging calls occur, so the ordering guarantee is intact. The module-level logger proxy is lazy and carries no side effects. Tests (275, 95.64% coverage) continue to pass. No new behavior is introduced.
  • No files require special attention.

Important Files Changed

Filename Overview
src/document_anonymizer/api/app.py Moves configure_logging() from module-level into the lifespan context manager as the first startup action, eliminating the import-time side effect while preserving correct ordering before any logging calls.

Sequence Diagram

sequenceDiagram
    participant I as Import / Module Load
    participant L as lifespan()
    participant CL as configure_logging()
    participant GA as get_analyzer()

    I->>I: logger = structlog.get_logger() [no side effect]
    Note over I: No configure_logging() at import time

    Note over L: App startup begins
    L->>CL: configure_logging()
    CL-->>L: structlog configured (JSON processors, log level)
    L->>L: logger.info("startup", action="loading_analyzer_engine")
    L->>GA: get_analyzer()
    GA-->>L: analyzer engine ready
    L->>L: logger.info("startup", action="analyzer_engine_ready")
    L-->>L: yield (app handles requests)
Loading

Reviews (1): Last reviewed commit: "Move configure_logging() from module lev..." | Re-trigger Greptile

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