Skip to content

feat(envd): persist command stdout/stderr to the log pipeline#2935

Open
mishushakov wants to merge 23 commits into
mainfrom
mishushakov/command-logs-method
Open

feat(envd): persist command stdout/stderr to the log pipeline#2935
mishushakov wants to merge 23 commits into
mainfrom
mishushakov/command-logs-method

Conversation

@mishushakov

@mishushakov mishushakov commented Jun 5, 2026

Copy link
Copy Markdown
Member

Commands started via envd previously had their stdout/stderr discarded once no client was streaming. This persists each non-PTY command's output through the existing envd → Loki log pipeline as process_output log lines, stamped with the command's pid and capped per command (with a truncation marker) to protect the exporter buffer and downstream storage. Output is captured even when no client is attached. The envd version is bumped (0.6.1 → 0.6.2) for the behavioral change; PTY/interactive sessions are out of scope. Includes unit tests for the output line-buffering and per-command cap.

Retrieval is handled separately in #2963 (a query LogQL filter on the sandbox logs endpoint); with both, a caller fetches one command's output via query=| json | pid="<pid>" | event_type="process_output". This PR is independently useful — persisted output already shows up in the existing sandbox logs (search/level).

🤖 Generated with Claude Code

Commands started via envd now get a unique cid that is returned in the
StartEvent and stamped on every stdout/stderr log line, so their output is
persisted through the existing Loki pipeline and capped per command. Adds
GET /v2/sandboxes/{sandboxID}/commands/{cid}/logs to retrieve a single
command's output, with the cid filter threaded through the local Loki query
and the remote edge contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cla-bot cla-bot Bot added the cla-signed label Jun 5, 2026
@cursor

cursor Bot commented Jun 5, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Increases log volume and changes sandbox logs API behavior across API, Edge, and Loki; pid on remote clusters depends on Edge version compatibility checks.

Overview
This extends sandbox logs so callers can request stdout/stderr for a single command via an optional pid query parameter on the v2 sandbox logs API (and the Edge API), with level filtering dropped for those queries because command output is stored at info. Queries flow through cluster providers into Loki LogQL scoped to process_output lines for that pid. envd now always records non-PTY command streams as structured log lines (pid, stream, per-command byte/record caps and a truncation marker), with pid published safely before output goroutines read it. Remote clusters refuse pid-scoped requests when Edge does not advertise pid filtering, so older Edge cannot silently return unfiltered logs.

Reviewed by Cursor Bugbot for commit ae853a1. Bugbot is set up for automated code reviews on this repo. Configure here.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

In packages/api/internal/handlers/command_logs.go, the expression new(time.UnixMilli(*params.Cursor)) is invalid Go syntax because new expects a type rather than a value. This will cause a compilation error, which can be resolved by converting the timestamp to a time.Time value first and then taking its address.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/api/internal/handlers/command_logs.go Outdated
Comment thread packages/shared/pkg/logs/loki/provider.go
@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
2794 3 2791 7
View the full list of 4 ❄️ flaky test(s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/sandboxes::TestSandboxListPaginationRunningLargerLimit

Flake rate in main: 38.21% (Passed 1001 times, Failed 619 times)

Stack Traces | 91.5s run time
=== RUN   TestSandboxListPaginationRunningLargerLimit
    sandbox_list_test.go:327: Created sandbox 1/12: ip7pj4nr08d9h0lwjvaud
    sandbox_list_test.go:327: Created sandbox 2/12: i1hk75cymgwowbc291ed4
    sandbox_list_test.go:327: Created sandbox 3/12: ixoym48kl6mi7bbqm1vzl
    sandbox_list_test.go:327: Created sandbox 4/12: i83ri892uzuhmfk5i84im
    sandbox_list_test.go:327: Created sandbox 5/12: i5av7pq1vdoxoqfwm3gql
    sandbox_list_test.go:327: Created sandbox 6/12: ioairjnbv6to9ezt8c86u
    sandbox_list_test.go:327: Created sandbox 7/12: i9ifkrjwr9be2nh4oowr5
    sandbox_list_test.go:327: Created sandbox 8/12: ixq6eeqzwco86kq4hajms
    sandbox_list_test.go:327: Created sandbox 9/12: igermeeiu8erbmv5cpfhs
    sandbox_list_test.go:327: Created sandbox 10/12: i22bkb7ljqsjm9fs639w8
    sandbox_list_test.go:327: Created sandbox 11/12: iuahwrvquelnxycp20vl5
    sandbox_list_test.go:327: Created sandbox 12/12: ihvbvf6xy4e48oah2zsvk
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:340
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	"[]" should have 12 item(s), but has 0
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:330
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxListPaginationRunningLargerLimit
--- FAIL: TestSandboxListPaginationRunningLargerLimit (91.47s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity

Flake rate in main: 53.00% (Passed 994 times, Failed 1121 times)

Stack Traces | 72s run time
=== RUN   TestSandboxMemoryIntegrity
=== PAUSE TestSandboxMemoryIntegrity
=== CONT  TestSandboxMemoryIntegrity
    sandbox_memory_integrity_test.go:27: Build completed successfully
--- FAIL: TestSandboxMemoryIntegrity (71.96s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity/tmpfs_hash

Flake rate in main: 53.01% (Passed 984 times, Failed 1110 times)

Stack Traces | 202s run time
=== RUN   TestSandboxMemoryIntegrity/tmpfs_hash
=== PAUSE TestSandboxMemoryIntegrity/tmpfs_hash
=== CONT  TestSandboxMemoryIntegrity/tmpfs_hash
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{start:{pid:1270}}
Executing command bash in sandbox inapy8bhdh0hz5rb8qkdl (user: root)
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Total memory: 985 MB\nUsed memory before tmpfs mount: 189 MB\nFree memory before tmpfs mount: 795 MB\nMemory to use in integrity test (60% of free, min 64MB): 477 MB\n"}}
Executing command bash in sandbox inapy8bhdh0hz5rb8qkdl (user: root)
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"477+0 records in\n477+0 records out\n500170752 bytes (500 MB, 477 MiB) copied, 2.74358 s, 182 MB/s\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\tCommand being timed: \"dd if=/dev/urandom of=/mnt/testfile bs=1M count=477\"\n\tUser time (seconds): 0.00\n\tSystem time (seconds): 2.73\n\tPercent of CPU this job got: 99%\n\tElapsed (wall clock) time (h:mm:ss or m:ss): 0:02.75\n\tAverage shared text size (kbytes): 0\n\tAverage unshared data size (kbytes): 0\n\tAverage stack size (kbytes): 0\n\tAverage total size (kbytes)"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:": 0\n\tMaximum resident set size (kbytes): 2700\n\tAverage resident set size (kbytes): 0\n\tMajor (requiring I/O) page faults: 2\n\tMinor (reclaiming a frame) page faults: 346\n\tVoluntary context switches: 3\n\tInvoluntary context switches: 74\n\tSwaps: 0\n\tFile system inputs: 176\n\tFile system outputs: 0\n\tSocket messages sent: 0\n\tSocket messages received: 0\n\tSignals delivered: 0\n\tPage size (bytes): 4096\n\tExit status: 0\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Used memory after tmpfs mount and file fill: 670 MB\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{end:{exited:true status:"exit status 0"}}
    sandbox_memory_integrity_test.go:70: Command [bash] completed successfully in sandbox ip6uwkbcbob3k9ui2ibnk
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1286}}
Executing command bash in sandbox ixcfi1k3643cmrfgx5g4p (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{data:{stdout:"0f6faab690c8ae43b313aaadfbeef246f2201f697eedb81ab33f8db9bd0bff5d\n"}}
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{end:{exited:true status:"exit status 0"}}
    sandbox_memory_integrity_test.go:80: Command [bash] completed successfully in sandbox ip6uwkbcbob3k9ui2ibnk
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1289}}
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
Executing command bash in sandbox ip6uwkbcbob3k9ui2ibnk (user: root)
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:81
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	Received unexpected error:
        	            	failed to execute command bash in sandbox ip6uwkbcbob3k9ui2ibnk: unavailable: HTTP status 502 Bad Gateway
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:78
        	            				.../tests/orchestrator/sandbox_memory_integrity_test.go:110
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxMemoryIntegrity/tmpfs_hash
--- FAIL: TestSandboxMemoryIntegrity/tmpfs_hash (202.07s)
github.com/e2b-dev/infra/tests/integration/internal/tests/proxies::TestSandboxAutoResumeViaProxy

Flake rate in main: 38.52% (Passed 988 times, Failed 619 times)

Stack Traces | 13.1s run time
=== RUN   TestSandboxAutoResumeViaProxy
=== PAUSE TestSandboxAutoResumeViaProxy
=== CONT  TestSandboxAutoResumeViaProxy
    auto_resume_test.go:116: 
        	Error Trace:	.../tests/proxies/auto_resume_test.go:116
        	Error:      	Received unexpected error:
        	            	Get "http://localhost:3002": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
        	Test:       	TestSandboxAutoResumeViaProxy
--- FAIL: TestSandboxAutoResumeViaProxy (13.11s)
Executing command ls in sandbox i0ghxty8mvc9wc25ow0lo

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

github-actions Bot and others added 2 commits June 5, 2026 19:58
The cid is stamped on process_start/process_end lifecycle lines too, so
filtering by cid alone returned them alongside output. Add an
event_type=process_output filter so the command-logs endpoint returns only
stdout/stderr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread packages/envd/internal/services/process/handler/output_log.go
Drop the envd-assigned cid (and its proto changes); commands are already
identified by the pid returned in StartEvent. Output lines are now stamped
with pid, and the retrieval endpoint becomes
GET /v2/sandboxes/{sandboxID}/commands/{pid}/logs with start/end query params.
The time window disambiguates a reused pid: within [start, end] a pid maps to
a single command execution. Filter stays scoped to event_type=process_output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread packages/envd/internal/services/process/handler/output_log.go
github-actions Bot and others added 3 commits June 6, 2026 14:23
Drop the dedicated /v2/sandboxes/{sandboxID}/commands/{pid}/logs route in
favor of an optional pid query param on the existing
/v2/sandboxes/{sandboxID}/logs endpoint. Callers scope to a single command's
output by passing pid (filtered to event_type=process_output), bounding the
window with the existing cursor/direction params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Swap the pid query param on /v2/sandboxes/{sandboxID}/logs for a `query`
field that is appended verbatim as LogQL pipeline stages after the
server-built selector ({teamID, sandboxID, category!="metrics"} | json).
Because LogQL cannot reopen a stream selector mid-pipeline, the team/sandbox
scoping is always enforced and the client expression can only narrow within
the caller's own logs. A length cap (1024) bounds abuse. Callers fetch a
single command's output via `| pid="<pid>" | event_type="process_output"`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread packages/shared/pkg/logs/loki/provider.go Outdated
mishushakov and others added 2 commits June 9, 2026 22:12
Previously the server forced a `| json` stage before the client query, so a
line-filter query like `|= "error"` produced the invalid `| json |= "error"`.
Now the server contributes only the enforced stream selector and the client
supplies the entire LogQL pipeline (including its own parser stage). Tenant
scoping still holds since LogQL cannot reopen a selector mid-pipeline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ogs-method

# Conflicts:
#	packages/api/internal/api/api.gen.go
Move the /v2/sandboxes/{sandboxID}/logs `query` field and its supporting
provider/resources/edge changes out to a separate PR (#2963). This branch now
contains only the envd command-output persistence: stdout/stderr is written to
the log pipeline (stamped with pid, capped per command).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mishushakov mishushakov changed the title feat(envd): persist command output and add per-command log retrieval feat(envd): persist command stdout/stderr to the log pipeline Jun 9, 2026
mishushakov and others added 4 commits June 10, 2026 18:03
Add GET /sandboxes/{sandboxID}/logs/command/{pid}, which returns the
persisted output (stdout/stderr) of a single command by reusing the
sandbox logs pipeline with a pid + event_type=process_output filter.
A start/end time window disambiguates reused pids.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the dedicated /sandboxes/{sandboxID}/logs/command/{pid} route in favor
of an optional pid query param on the existing /v2/sandboxes/{sandboxID}/logs
endpoint. Callers scope to a single command's output by passing pid (filtered
to event_type=process_output), bounding the window with the existing
cursor/direction params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mishushakov mishushakov marked this pull request as ready for review June 10, 2026 17:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 069a09341d

ℹ️ 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".

Comment thread packages/api/internal/handlers/sandbox_logs.go Outdated
Comment thread packages/envd/internal/services/process/handler/output_log.go Outdated
Comment thread packages/envd/internal/services/process/handler/output_log.go
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c4476183f1

ℹ️ 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".

Comment thread packages/envd/internal/services/process/handler/output_log.go
The budget only subtracted message payload bytes, so commands emitting tiny
lines (e.g. `yes`) could produce ~2M individual log records — each with
~200 bytes of field/JSON framing overhead — before tripping the 2 MiB cap,
flooding the exporter the cap was meant to protect. Charge a fixed
per-event overhead per record so the budget also bounds record count
(~8k records worst case).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ca9fbbace

ℹ️ 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".

Comment thread packages/envd/internal/services/process/handler/output_log.go Outdated
mishushakov and others added 2 commits June 10, 2026 20:06
…rd cap

Charging synthetic overhead bytes per record silently taxed every command's
payload budget — typical ~100-200 byte log lines would truncate at ~0.6-0.9 MiB
of real output instead of the advertised 2 MiB. Keep the byte budget honest
(payload only) and bound the tiny-line flood case (e.g. `yes`) directly with
a per-command record cap of 10k, shared across stdout/stderr like the byte cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The marker only set event_type, so the pid-scoped retrieval filter
(| pid = ... | event_type = process_output) dropped it — command-specific
queries lost the only indication that output was truncated. Emit it with the
same pid/stream fields as regular output lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit aad63dc. Configure here.

Comment thread packages/shared/pkg/logs/loki/provider.go
mishushakov and others added 2 commits June 10, 2026 20:12
Completed empty lines (e.g. printf 'a\n\nb\n' or test runners separating
sections) are part of the command's real output and are delivered on the live
stream, but emitLine discarded them, making pid-filtered retrieval diverge
from actual stdout/stderr. Emit them as records with an empty message. The
guard was only ever reachable for blank lines: the over-long segment path
can't produce an empty slice and flush() is guarded by len(buf) > 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The stdout/stderr reader goroutines are launched in New, but cmd.Start() runs
later in Start: a non-PTY command that writes immediately on startup can
deliver output (and trigger Handler.Pid -> cmd.Process.Pid) before Start has
published cmd.Process — a nil dereference that panics envd, and an
unsynchronized read even after publication. Publish the pid via an atomic and
a ready channel closed after cmd.Start() succeeds; the loggers block on it
instead of touching cmd.Process. Output implies the process started, so the
wait can't deadlock on a failed Start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d952a5e21

ℹ️ 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".

Comment thread packages/api/internal/clusters/resources_remote.go
mishushakov and others added 3 commits June 10, 2026 20:16
Command output lines are always persisted at info (the truncation marker at
warn), so combining pid with a minimum level of warn/error built a LogQL
pipeline that filtered out every output line — pid-scoped retrieval returned
empty despite the output being persisted. Drop the level stage when pid is
set and document the behavior on the pid params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An Edge deployment that predates the pid query param ignores it and
returns unfiltered sandbox logs, which the caller would mistake for
command-scoped output. Unlike level/search (where degrading to
unfiltered logs is acceptable and only logged), pid scoping is a
correctness contract, so return 501 unless the Edge response advertises
support via the new X-E2B-Edge-Feature-Sandbox-Logs-Pid-Filtering-Enabled
header.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae853a10b1

ℹ️ 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".

Comment thread packages/api/internal/clusters/resources_remote.go
@mishushakov mishushakov force-pushed the mishushakov/command-logs-method branch from b357648 to ae853a1 Compare June 10, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant