feat(python-sdk): add logger option for request/debug logging#1409
Conversation
Add a `logger` option (standard library `logging.Logger`) to `Sandbox.create`/`connect` and `AsyncSandbox.create`/`connect`, wired into the API client, envd client, volume content client, and the RPC (ConnectRPC) path. Mirrors the JS SDK: `logger` is a construction-time option (not a per-request ApiParams field), and logging is emitted only when a logger is supplied. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: ed5e520 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
PR SummaryMedium Risk Overview HTTP logging moves to shared Breaking observability change: always-on Also guards Reviewed by Cursor Bugbot for commit ed5e520. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from 288f9d7. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.30.7-mishushakov-python-logger-connection-option.0.tgzCLI ( npm install ./e2b-cli-2.13.1-mishushakov-python-logger-connection-option.0.tgzPython SDK ( pip install ./e2b-2.29.6+mishushakov.python.logger.connection.option-py3-none-any.whl |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25416ed3cc
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
`get_api_params` now carries the sandbox's stored logger so the throwaway ConnectionConfig that instance control-plane methods (kill, pause, set_timeout, get_info, connect) rebuild keeps logging with the construction-time logger. Also drop the misleading `logger` arg from instance `connect()` — the returned instance is unchanged, so it could never adopt a new logger; `logger` remains on `create` and the static `connect(sandbox_id, ...)` construction paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the off-schema dict mutation with an internal `ApiParamsWithLogger` TypedDict (ApiParams + logger), so the construction-time logger is propagated through a typed structure rather than an untyped key assignment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gger-connection-option # Conflicts: # packages/python-sdk/e2b/api/client_async/__init__.py # packages/python-sdk/e2b/api/client_sync/__init__.py # packages/python-sdk/e2b/connection_config.py # packages/python-sdk/e2b/sandbox_sync/commands/command.py # packages/python-sdk/e2b/sandbox_sync/commands/pty.py # packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py # packages/python-sdk/e2b/sandbox_sync/main.py
Filesystem rebuilds a per-thread envd httpx.Client via `_create_envd_api`; attach the logging event hooks there too so file upload/download requests on worker threads honor the sandbox's `logger` instead of going unlogged after transport-level logging was removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gger-connection-option # Conflicts: # packages/python-sdk/e2b/api/__init__.py # packages/python-sdk/e2b/sandbox_sync/main.py
…gger-connection-option # Conflicts: # packages/python-sdk/e2b/api/client_async/__init__.py # packages/python-sdk/e2b/volume/client_async/__init__.py # packages/python-sdk/e2b/volume/client_sync/__init__.py
…gger-connection-option # Conflicts: # packages/python-sdk/e2b/sandbox_async/main.py # packages/python-sdk/e2b/sandbox_sync/main.py
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 96c1322. Configure here.
…ents Sync Commands and Pty build their own thread-local httpx.Client instances for envd HTTP traffic (health checks, etc.), but unlike the sync filesystem client they were missing make_logging_event_hooks. As a result envd requests on those clients were not logged even when the sandbox was created with a logger. Mirror the filesystem client so all sync envd traffic respects the configured logger. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gger-connection-option # Conflicts: # packages/python-sdk/e2b/connection_config.py
|
@matthewlouisbrockman was the two commits added on purpose? if it's not related to the PR, i'd move that |
|
apparently that's what happens when u click the copilot link next to review at top of github ui, lemme figure out how to undo those lol |
| return {} | ||
|
|
||
| def on_request(request) -> None: | ||
| log.info(f"Request {request.method} {request.url}") |
There was a problem hiding this comment.
should we sanitize these? used to be
def handle_request(self, request):
url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
logger.info(f"Request: {request.method} {url}")
response = super().handle_request(request)
# data = connect.GzipCompressor.decompress(response.read()).decode()
logger.info(f"Response: {response.status_code} {url}")
return response
now it's the raw url
There was a problem hiding this comment.
I will merge this one and then implement the sanitization in both SDKs, as JS also appears to be lacking.

Adds a
loggeroption (a standard librarylogging.Logger) toSandbox.create/AsyncSandbox.createand the staticSandbox.connect(sandbox_id, ...), wired into the API client, the envd client, the volume content client, and the RPC (ConnectRPC) path. The logger is stored on the sandbox and propagates to all of its later operations — including control-plane calls likekill/pause/set_timeout/get_info(viaget_api_params) — so logging keeps working after construction; mirroring the JS SDK,loggeris a construction-time option and not a public per-request parameter those methods accept from the caller, and nothing is logged unless a logger is supplied. The stdliblogging.Loggeris used directly as the adapter (no ported JSLoggerinterface), and log levels match JS: requests atINFO, successful API and unary RPC responses atINFO, streamed RPC messages atDEBUG, failed API responses (status >= 400) atERROR. The always-on module-level (e2b.*) request logging at the transport layer was removed in favor of this opt-in client-layer logging, and volume content operations continue to acceptloggerper call viaVolumeApiParamsto match the JS Volume API. Includes a changeset and unit tests intests/test_logging_option.py.Usage
🤖 Generated with Claude Code