Skip to content

Add structured logging with structlog across codebase#344

Merged
dmccoystephenson merged 8 commits into
mainfrom
copilot/add-structured-logging-using-structlog
Apr 20, 2026
Merged

Add structured logging with structlog across codebase#344
dmccoystephenson merged 8 commits into
mainfrom
copilot/add-structured-logging-using-structlog

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 19, 2026

Replaces scattered print() calls with structured logging via structlog, enabling runtime behaviour reconstruction from logs alone.

Changes

  • src/gameLogging/logger.py — Central logging module with getLogger(name), redact() helper, and LoggerFactory DI singleton. Reads LOG_LEVEL/LOG_FORMAT from env (defaults: INFO/pretty). Uses stdlib logging as backend with structlog.stdlib.filter_by_level so LOG_LEVEL actually controls log verbosity. Env var values are stripped of whitespace for robustness. Named gameLogging to avoid shadowing stdlib logging.

  • src/bootstrap.py — Registers LoggerFactory as singleton in DI container.

  • src/config/config.py — Logs all resolved config values at DEBUG on startup. Logging is configured solely via environment variables (LOG_LEVEL/LOG_FORMAT), not config.yml, since structlog is initialised at import time before Config is available.

  • All print() calls replaced in tickCounter.py, worldScreen.py, mapImageUpdater.py, mapImageGenerator.py, inventoryJsonReaderWriter.py, roomJsonReaderWriter.py, room.py, roam.py — using appropriate levels (WARN for slow ticks, INFO for save/load, ERROR for failures, DEBUG for entity lifecycle).

  • Expanded instrumentation added to config.py, roam.py, worldScreen.py, map.py, roomFactory.py, roomPreloader.py, stats.py, saveSelectionScreen.py, and inventory.py covering screen transitions, room transitions, room loading/generation, entity spawning, background preloading, save management, and inventory operations.

  • Log level audit — Fixed 2 incorrect log levels in worldScreen.py: "living entity not found in room" and "could not find new location for entity" downgraded from ERROR to DEBUG (expected entity lifecycle edge cases, not error conditions).

  • Exception logging — Background thread error handlers in roomPreloader.py and mapImageUpdater.py use logger.exception() to preserve full tracebacks for diagnosability.

  • requirements.txt — Added structlog==25.5.0, removed unused vulnerable deps (Django, sqlparse, py), upgraded Pillow to 12.2.0.

  • .github/workflows/tests.yml — Added structlog to CI dependency install step so tests can import the new logging module.

  • LOGGING.md — Documents log levels, env vars, field naming conventions (camelCase), redaction policy, and platform-specific instructions for setting environment variables on Linux/macOS (bash), Windows Command Prompt (cmd.exe), and Windows PowerShell.

Instrumentation Coverage

Area Level Files
Game startup/shutdown INFO roam.py
Config values at startup DEBUG config.py
Screen transitions INFO roam.py
World screen initialization INFO worldScreen.py
Room transitions INFO worldScreen.py
Room loading/generation INFO map.py
Room creation & type DEBUG roomFactory.py
Entity spawning (chickens, bears) DEBUG roomFactory.py
Background room preloading DEBUG/ERROR roomPreloader.py
Tick performance warnings WARN tickCounter.py
Save/load operations INFO stats.py, tickCounter.py, inventoryJsonReaderWriter.py, roomJsonReaderWriter.py, worldScreen.py
Save selection/creation/deletion INFO saveSelectionScreen.py
Inventory item operations DEBUG inventory.py
Map image updates INFO/ERROR mapImageUpdater.py, mapImageGenerator.py
Entity lifecycle edge cases DEBUG worldScreen.py
Unrecoverable failures ERROR worldScreen.py, room.py, roam.py

Usage

from gameLogging.logger import getLogger

logger = getLogger(__name__)
logger.info("room saved", path=path, roomX=room.getX(), roomY=room.getY())
logger.warning("tick took too long", durationMs=elapsed, tickCount=tick)

Configure via environment:

Linux / macOS (bash):

LOG_LEVEL=DEBUG LOG_FORMAT=json python src/roam.py

Windows — Command Prompt (cmd.exe):

set LOG_LEVEL=DEBUG
python src\roam.py

Windows — PowerShell:

$env:LOG_LEVEL = "DEBUG"
python src\roam.py

Copilot AI and others added 3 commits April 19, 2026 20:13
- Add structlog==25.5.0 to requirements.txt
- Create src/gameLogging/logger.py with getLogger() and redact() helpers
- Register LoggerFactory singleton in DI container via bootstrap.py
- Add LOG_LEVEL and LOG_FORMAT config support in config.py
- Add example logging configuration to config.yml
- Replace all print() calls in source files with structured logger calls
- Add instrumentation for tick warnings, save/load, map image ops,
  entity lifecycle, and error handling
- Create LOGGING.md documentation
- Add tests for logger module (7 new tests)
- Update CHANGELOG.md

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/4b656504-ed85-437b-b9aa-7e486c19408c

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
- Remove Django==4.1.6 (unused, SQL injection + DoS vulnerabilities)
- Remove sqlparse==0.4.3 (unused Django dep, DoS vulnerability)
- Remove py==1.11.0 (deprecated, ReDoS vulnerability, no patch)
- Upgrade Pillow from 9.4.0 to 10.4.0 (fixes buffer overflow + DoS)

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/4b656504-ed85-437b-b9aa-7e486c19408c

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
…write vulnerabilities

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/4b656504-ed85-437b-b9aa-7e486c19408c

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copilot AI changed the title [WIP] Add structured logging with structlog across codebase Add structured logging with structlog across codebase Apr 19, 2026
Copilot AI requested a review from dmccoystephenson April 19, 2026 20:18
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot expand logging and audit existing log statements for proper log level usage

- Fix worldScreen.py: downgrade 2 log statements from ERROR to DEBUG
  for expected entity lifecycle edge cases (entity not found in room,
  could not find new location)
- Add logging to config.py: log all resolved config values at DEBUG
- Add logging to roam.py: screen transitions at INFO, shutdown at INFO
- Add logging to worldScreen.py: initialization and room transitions
  at INFO
- Add logging to map.py: room loading from file and generation at INFO
- Add logging to roomFactory.py: room creation at DEBUG, entity
  spawning (chickens/bears) at DEBUG
- Add logging to roomPreloader.py: preload success at DEBUG, failures
  at ERROR
- Add logging to stats.py: save/load at INFO
- Add logging to saveSelectionScreen.py: save selection, creation,
  and deletion at INFO
- Add logging to inventory.py: item placement and stacking at DEBUG
- Update CHANGELOG.md

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/a852a88a-11fa-4ac8-8099-205ab6d83136

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 19, 2026

@copilot expand logging and audit existing log statements for proper log level usage

Expanded logging and audited all existing log levels in commit 33ed66d.

Log level fixes:

  • worldScreen.py line 1659: "living entity not found in room" — ERROR → DEBUG (expected entity lifecycle edge case)
  • worldScreen.py line 1874: "could not find new location for entity" — ERROR → DEBUG (expected room boundary condition)

New logging added to 8 files:

  • config.py — All resolved config values logged at DEBUG on startup
  • roam.py — Screen transitions at INFO, shutdown at INFO
  • worldScreen.py — World screen initialization and room transitions at INFO
  • map.py — Room loading from file and generation at INFO
  • roomFactory.py — Room creation at DEBUG, entity spawning (chickens/bears) at DEBUG with counts
  • roomPreloader.py — Background preload success at DEBUG, failures at ERROR
  • stats.py — Save/load at INFO
  • saveSelectionScreen.py — Save selection, creation, and deletion at INFO
  • inventory.py — Item placement and stacking at DEBUG

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces structured logging (via structlog) across Roam to replace scattered print() statements and add consistent instrumentation for gameplay, saves, and background tasks.

Changes:

  • Added a central logging module (src/gameLogging/logger.py) with helpers and DI integration.
  • Replaced print() calls with structured log events in core world/screen/save/map-image/inventory flows.
  • Added logging configuration documentation (LOGGING.md) and config.yml keys, plus a new requirements.txt entry for structlog.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/gameLogging/test_logger.py Adds unit tests for getLogger, redact, and LoggerFactory.
src/gameLogging/logger.py New structlog setup, env parsing, redaction helper, and logger factory.
src/gameLogging/init.py Exposes getLogger/redact from the package.
src/bootstrap.py Registers LoggerFactory in the DI container.
src/config/config.py Adds logLevel/logFormat config keys and logs resolved config at DEBUG.
src/world/tickCounter.py Converts tick warnings/save/load prints into structured logs.
src/world/roomPreloader.py Adds debug/error logs for background preloading and failures.
src/world/roomJsonReaderWriter.py Logs room save/load operations.
src/world/roomFactory.py Logs room creation and entity spawn counts.
src/world/room.py Logs entity removal edge cases and missing locations.
src/world/map.py Logs room load/generation events.
src/stats/stats.py Logs stats save/load events.
src/screen/worldScreen.py Logs world init, room transitions, save/load operations, and lifecycle edge cases.
src/screen/saveSelectionScreen.py Logs save selection/creation/deletion.
src/roam.py Logs startup, shutdown, and screen transitions.
src/mapimage/mapImageUpdater.py Logs map-image update lifecycle and failures.
src/mapimage/mapImageGenerator.py Replaces debug prints with structured debug logs.
src/inventory/inventoryJsonReaderWriter.py Logs inventory save/load and validation failures.
src/inventory/inventory.py Logs inventory placement/stacking/full events at DEBUG.
requirements.txt Adds structlog and updates/pins dependency set.
config.yml Documents logging keys (commented).
LOGGING.md Documents logging config, levels, field naming, and redaction.
CHANGELOG.md Adds a changelog entry and a learning-log note about package naming conflicts.

Comment thread src/gameLogging/logger.py Outdated
Comment on lines +43 to +45
_LOG_LEVEL_NAME = os.environ.get("LOG_LEVEL", "INFO").upper()
_LOG_LEVEL = _VALID_LEVELS.get(_LOG_LEVEL_NAME, logging.INFO)
_LOG_FORMAT = os.environ.get("LOG_FORMAT", "pretty").lower()
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOG_LEVEL is parsed into _LOG_LEVEL, but _LOG_LEVEL is never used, so log-level filtering likely doesn't work (e.g., DEBUG logs may always be emitted). Apply _LOG_LEVEL in structlog configuration (e.g., filtering wrapper/logger or stdlib logging level) so runtime log verbosity is actually controlled by LOG_LEVEL.

Copilot uses AI. Check for mistakes.
Comment thread src/gameLogging/logger.py Outdated
Comment on lines +25 to +29
# Custom TRACE level (below DEBUG)
# ---------------------------------------------------------------------------
TRACE_LEVEL = 5
logging.addLevelName(TRACE_LEVEL, "TRACE")

Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A custom TRACE level is declared and documented, but there’s no logger.trace(...) API wired up (adding a level name alone doesn’t create a logging method). Either implement a trace() method (or expose a supported alternative like logger.log(TRACE_LEVEL, ...)) or remove TRACE from the supported levels/docs to avoid a misleading API.

Copilot uses AI. Check for mistakes.
Comment thread src/config/config.py Outdated
Comment on lines +206 to +214
# logging
self.logLevel = os.environ.get(
"LOG_LEVEL",
self.getStringValue(configValues, "logLevel", "INFO"),
)
self.logFormat = os.environ.get(
"LOG_FORMAT",
self.getStringValue(configValues, "logFormat", "pretty"),
)
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logLevel/logFormat are read from config.yml into Config, but nothing uses these values to configure structlog (logger setup happens from env vars at import time). Either reconfigure logging based on Config (with env taking precedence) or remove these config keys to avoid having non-functional configuration knobs.

Copilot uses AI. Check for mistakes.
Comment thread src/world/roomPreloader.py Outdated
Comment on lines +88 to +89
except Exception as e:
_logger.error("room preload failed", roomX=x, roomY=y, error=str(e))
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This catches a broad exception and logs only error=str(e), which drops the traceback. For background preload failures it’s hard to diagnose without stack info; prefer logger.exception(...) or include exc_info=True so the full error context is captured.

Suggested change
except Exception as e:
_logger.error("room preload failed", roomX=x, roomY=y, error=str(e))
except Exception:
_logger.exception("room preload failed", roomX=x, roomY=y)

Copilot uses AI. Check for mistakes.
Comment thread src/mapimage/mapImageUpdater.py Outdated
Comment on lines +62 to +63
except Exception as e:
print("Error updating map image: " + str(e))
_logger.error("error updating map image", error=str(e))
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On failure, this logs only error=str(e) and loses the traceback from the background thread. Use logger.exception(...) (or exc_info=True) so map image update failures are diagnosable from logs alone.

Copilot uses AI. Check for mistakes.
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot You are a coding agent tasked with resolving all open comments and review threads
on this pull request. Work through every comment systematically and apply the
appropriate code changes.


Instructions

1. Discover all comments

  • Read every review thread, inline comment, and general PR comment
  • Include comments from: Copilot, human reviewers, and any other bots
  • Do not skip comments marked as suggestions — apply them if they make sense

2. For each comment, do the following:

  • Understand what is being requested or flagged
  • Locate the relevant file(s) and line(s)
  • Apply the fix directly in code
  • If a Copilot suggestion diff is provided, apply it (or an equivalent fix)
  • If the comment is ambiguous, use your best judgment and reply in the PR thread or review comment explaining what you did; only add a code comment when explicitly requested or when future maintainers would benefit from it
  • After addressing a comment, reply to the thread summarising what you did and mark it as resolved if your environment supports it

3. Types of issues to handle:

  • Code quality / style issues (naming, formatting, readability)
  • Logic bugs or edge cases flagged by reviewers
  • Security concerns (e.g. input validation, secrets, injection risks)
  • Performance suggestions
  • Missing or incomplete error handling
  • Test coverage gaps
  • Documentation / comment improvements
  • Dependency or import issues

4. Do NOT:

  • Dismiss or ignore any comment without acting on it — note that "acting" can also mean replying to the thread with a rationale (e.g., won't fix, already addressed elsewhere) and leaving the code unchanged when appropriate
  • Leave TODO comments as a substitute for fixing the issue
  • Break existing tests while addressing comments
  • Change functionality beyond the scope of what the comment asks for

After making changes

  • Ensure all existing tests still pass
  • Add or update tests if a comment explicitly asks for them, or if a bug fix warrants it
  • Double-check that every open thread has been addressed, replied to, and resolved

Context

  • This PR may contain Copilot-generated review comments — treat these with the same priority as human comments
  • If two comments conflict with each other, prefer the human reviewer's intent and document the conflict and resolution in the PR conversation or commit message, not in a code comment
  • Commit changes in logical groups if there are many unrelated fixes

@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot You are a coding agent tasked with resolving all open comments and review threads
on this pull request. Work through every comment systematically and apply the
appropriate code changes.


Instructions

1. Discover all comments

  • Read every review thread, inline comment, and general PR comment
  • Include comments from: Copilot, human reviewers, and any other bots
  • Do not skip comments marked as suggestions — apply them if they make sense

2. For each comment, do the following:

  • Understand what is being requested or flagged
  • Locate the relevant file(s) and line(s)
  • Apply the fix directly in code
  • If a Copilot suggestion diff is provided, apply it (or an equivalent fix)
  • If the comment is ambiguous, use your best judgment and reply in the PR thread or review comment explaining what you did; only add a code comment when explicitly requested or when future maintainers would benefit from it
  • After addressing a comment, reply to the thread summarising what you did and mark it as resolved if your environment supports it

3. Types of issues to handle:

  • Code quality / style issues (naming, formatting, readability)
  • Logic bugs or edge cases flagged by reviewers
  • Security concerns (e.g. input validation, secrets, injection risks)
  • Performance suggestions
  • Missing or incomplete error handling
  • Test coverage gaps
  • Documentation / comment improvements
  • Dependency or import issues

4. Do NOT:

  • Dismiss or ignore any comment without acting on it — note that "acting" can also mean replying to the thread with a rationale (e.g., won't fix, already addressed elsewhere) and leaving the code unchanged when appropriate
  • Leave TODO comments as a substitute for fixing the issue
  • Break existing tests while addressing comments
  • Change functionality beyond the scope of what the comment asks for

After making changes

  • Ensure all existing tests still pass
  • Add or update tests if a comment explicitly asks for them, or if a bug fix warrants it
  • Double-check that every open thread has been addressed, replied to, and resolved

Context

  • This PR may contain Copilot-generated review comments — treat these with the same priority as human comments
  • If two comments conflict with each other, prefer the human reviewer's intent and document the conflict and resolution in the PR conversation or commit message, not in a code comment
  • Commit changes in logical groups if there are many unrelated fixes

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/310419b7-369a-43bb-be24-e15e41a67901

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 19, 2026

@copilot You are a coding agent tasked with resolving all open comments and review threads
on this pull request. Work through every comment systematically and apply the
appropriate code changes....

All 5 review comments were addressed in commit 341bebb:

  1. _LOG_LEVEL not applied — Now used via logging.basicConfig(level=_LOG_LEVEL) + structlog.stdlib.filter_by_level processor, so LOG_LEVEL env var actually controls log verbosity.
  2. TRACE level without API — Removed entirely from code and docs.
  3. Non-functional logLevel/logFormat config keys — Removed from config.py, config.yml, and LOGGING.md.
  4. roomPreloader.py dropped traceback — Now uses _logger.exception() to preserve full stack trace.
  5. mapImageUpdater.py dropped traceback — Now uses _logger.exception() to preserve full stack trace.

All 342 tests pass.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 2 comments.

Comment thread src/roam.py
Comment on lines 137 to +143
elif result == ScreenType.NONE:
_logger.info("shutting down")
self.quitApplication()
else:
print("unrecognized screen: " + result)
_logger.error("unrecognized screen", screen=result)
self.quitApplication()
_logger.info("screen transition", screen=str(result))
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quitApplication() ends the process via quit(), so the screen transition log after calling self.quitApplication() is unreachable for ScreenType.NONE and the unrecognized screen branch. Consider logging the transition before quitting and/or returning immediately after quitApplication() to make the control flow explicit and ensure the log is emitted.

Copilot uses AI. Check for mistakes.
Comment thread LOGGING.md Outdated
Comment on lines +56 to +57
from gameLogging.logger import redact

Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The redaction example uses logger.info(...) but the snippet doesn’t define logger. Add logger = getLogger(__name__) (or a short note that logger is assumed to already exist) so the example is copy/pasteable.

Suggested change
from gameLogging.logger import redact
from gameLogging.logger import getLogger, redact
logger = getLogger(__name__)

Copilot uses AI. Check for mistakes.
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot You are a coding agent tasked with resolving all open comments and review threads
on this pull request. Work through every comment systematically and apply the
appropriate code changes.


Instructions

1. Discover all comments

  • Read every review thread, inline comment, and general PR comment
  • Include comments from: Copilot, human reviewers, and any other bots
  • Do not skip comments marked as suggestions — apply them if they make sense

2. For each comment, do the following:

  • Understand what is being requested or flagged
  • Locate the relevant file(s) and line(s)
  • Apply the fix directly in code
  • If a Copilot suggestion diff is provided, apply it (or an equivalent fix)
  • If the comment is ambiguous, use your best judgment and reply in the PR thread or review comment explaining what you did; only add a code comment when explicitly requested or when future maintainers would benefit from it
  • After addressing a comment, reply to the thread summarising what you did and mark it as resolved if your environment supports it

3. Types of issues to handle:

  • Code quality / style issues (naming, formatting, readability)
  • Logic bugs or edge cases flagged by reviewers
  • Security concerns (e.g. input validation, secrets, injection risks)
  • Performance suggestions
  • Missing or incomplete error handling
  • Test coverage gaps
  • Documentation / comment improvements
  • Dependency or import issues

4. Do NOT:

  • Dismiss or ignore any comment without acting on it — note that "acting" can also mean replying to the thread with a rationale (e.g., won't fix, already addressed elsewhere) and leaving the code unchanged when appropriate
  • Leave TODO comments as a substitute for fixing the issue
  • Break existing tests while addressing comments
  • Change functionality beyond the scope of what the comment asks for

After making changes

  • Ensure all existing tests still pass
  • Add or update tests if a comment explicitly asks for them, or if a bug fix warrants it
  • Double-check that every open thread has been addressed, replied to, and resolved

Context

  • This PR may contain Copilot-generated review comments — treat these with the same priority as human comments
  • If two comments conflict with each other, prefer the human reviewer's intent and document the conflict and resolution in the PR conversation or commit message, not in a code comment
  • Commit changes in logical groups if there are many unrelated fixes

…d example

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/cd09fbf8-ce04-4f70-baca-54352013533f

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 19, 2026

@copilot You are a coding agent tasked with resolving all open comments and review threads
on this pull request. Work through every comment systematically and apply the
appropriate code changes....

Both open review comments addressed in ace899c:

  1. roam.py:137-143 — unreachable log after quitApplication(): Added return after both quitApplication() calls so the "screen transition" log is only reached for valid screen changes.
  2. LOGGING.md:56-57 — incomplete redaction example: Added getLogger import and logger = getLogger(__name__) so the example is copy-pasteable.

All 342 tests pass, CodeQL clean.

@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot It is not clear to me how to set the log level. Running set LOG_LEVEL DEBUG on Windows does not result in debug logs showing up. Resolve any potential issues and update documentation to make this clearer.

…setup

Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/4ef58052-529c-4106-a2c5-d7ba34a0192c

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 19, 2026

@copilot It is not clear to me how to set the log level. Running set LOG_LEVEL DEBUG on Windows does not result in debug logs showing up. Resolve any potential issues and update documentation to mak...

Fixed in 310d66c. Three issues addressed:

  1. CI failurestructlog was missing from the CI install step in tests.yml. Added it.

  2. Windows set syntaxset LOG_LEVEL DEBUG doesn't work because cmd.exe requires set LOG_LEVEL=DEBUG (with =, no spaces). In PowerShell, set creates a PS variable, not an env var — use $env:LOG_LEVEL = "DEBUG" instead.

  3. Whitespace robustness — Added .strip() to env var parsing in logger.py so trailing/leading whitespace in the value won't silently cause the level to be ignored.

LOGGING.md now has a "Setting environment variables by platform" section with copy-pasteable examples for bash, cmd.exe, and PowerShell, including warning callouts for the common pitfalls.

@dmccoystephenson dmccoystephenson merged commit 6904b0b into main Apr 20, 2026
1 check passed
@dmccoystephenson dmccoystephenson deleted the copilot/add-structured-logging-using-structlog branch April 20, 2026 00:24
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.

Add Structured Logging with structlog Across Codebase

3 participants