Skip to content

fix(logging): keep stdout clean and respect the configured log level - #9

Merged
Jeomon merged 2 commits into
Jeomon:mainfrom
hussainbiedouh:fix/stdout-safety-and-log-levels
Oct 27, 2026
Merged

Jeomon merged 2 commits into
Jeomon:mainfrom
hussainbiedouh:fix/stdout-safety-and-log-levels

Conversation

@hussainbiedouh

Copy link
Copy Markdown
Contributor

Two logging problems that bite anyone embedding windows-use in a stdout based protocol server (MCP servers, JSON-RPC agent harnesses, | jq pipelines).

1. The UIA watchdog printed to stdout

windows_use/agent/watchdog/event_handlers.py printed callback exceptions straight to stdout:

except Exception as e:
    print(f"Error in focus callback: {e}")

Those handlers fire on every focus change, so a callback that raised injected a bare sentence into the middle of the protocol stream and the client disconnected.

They now log through the module logger, which the package already routes to stderr. tests/test_watchdog_stdout_safety.py asserts that none of the three handlers write to stdout; it fails on the current code and passes with this change.

2. The desktop service forced DEBUG

agent/service.py configures the windows_use logger at INFO, but agent/desktop/service.py set its child logger to DEBUG, overriding it. Every step dumped the whole window list - name, status, bounding box and handle per window - to the console.

Removing the explicit setLevel lets the module inherit the package level. logging.getLogger("windows_use").setLevel(logging.DEBUG) brings the verbose output back for anyone who wants it.

Testing

  • pytest tests/ - 124 passed, 5 skipped (4 of the passed are the new ones)
  • ruff check and ruff format --check are clean on the changed files

The focus, structure and property event handlers printed their exceptions
straight to stdout. stdout is the transport for newline delimited JSON-RPC,
so a callback that raised while windows-use was embedded in an MCP server
injected a bare sentence into the middle of the protocol stream and killed
the connection.

Log through the module logger instead, and add a regression test asserting
that the handlers never write to stdout.
agent/service.py configures the "windows_use" logger at INFO, but
agent/desktop/service.py set its own child logger to DEBUG, which overrode
that. Every step therefore dumped the full window list - name, status,
bounding box and handle for each window - to the console.

Drop the explicit setLevel so the module inherits the package level. Set
"windows_use" to DEBUG to get the verbose output back.
@Jeomon
Jeomon merged commit cb35295 into Jeomon:main Oct 27, 2026
1 check passed
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.

2 participants