9f9e2a8f20
### Changelog
- Added traces for Python and JavaScript SDK.
- Added methods for stack trace collection, stack trace context
- Updated file upload mechanism for tracing
- Changed API handling to support throwing API errors with traces
> **Note**
> For functions like `aptInstall`, `fromRegistry` which call `.run` and
`.fromImage`, the stack trace has to be replaced so it throws correctly
from parent.
> **Note**
> There are no build logs in the trace, we can add this at later point.
### Examples
Keep in mind that the way the traces are rendered entirely depends on
environment (Bun, Node, Deno, Vitest, Pytest)
**Standard Python**
```
Traceback (most recent call last):
File "/Users/mish/Documents/Projects/E2B/E2B/packages/python-sdk/tests/sync/template_sync/test_stacktrace.py", line 17, in <module>
Template.build(
~~~~~~~~~~~~~~^
template,
^^^^^^^^^
...<2 lines>...
memory_mb=1024,
^^^^^^^^^^^^^^^
)
^
File "/Users/mish/Documents/Projects/E2B/E2B/packages/python-sdk/e2b/template_sync/main.py", line 157, in build
wait_for_build_finish(
~~~~~~~~~~~~~~~~~~~~~^
api_client,
^^^^^^^^^^^
...<4 lines>...
stack_traces=template._template._stack_traces,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/Users/mish/Documents/Projects/E2B/E2B/packages/python-sdk/e2b/template_sync/build_api.py", line 199, in wait_for_build_finish
raise BuildException(error_message).with_traceback(stack_trace)
File "/Users/mish/Documents/Projects/E2B/E2B/packages/python-sdk/tests/sync/template_sync/test_stacktrace.py", line 12, in <module>
.run_cmd("cat non_existing_file.txt")
~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
e2b.template.exceptions.BuildException: failed to run command: exit status 1
```
**Pytest**
```
[gw0] darwin -- Python 3.13.3 /Users/mish/Library/Caches/pypoetry/virtualenvs/e2b-e6GdLxLZ-py3.13/bin/python
@pytest.mark.skip_debug()
def test_build():
template = (
Template()
.from_image("ubuntu:22.04")
.run_cmd("cat non_existing_file.txt")
.set_workdir("/app")
.set_start_cmd("echo 'Hello, world!'", wait_for_timeout(10_000))
)
# try:
> Template.build(
template,
alias=str(uuid4()),
cpu_count=1,
memory_mb=1024,
)
tests/sync/template_sync/test_stacktrace.py:18:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
e2b/template_sync/main.py:157: in build
wait_for_build_finish(
e2b/template_sync/build_api.py:199: in wait_for_build_finish
raise BuildException(error_message).with_traceback(stack_trace)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
@pytest.mark.skip_debug()
def test_build():
template = (
Template()
.from_image("ubuntu:22.04")
> .run_cmd("cat non_existing_file.txt")
.set_workdir("/app")
.set_start_cmd("echo 'Hello, world!'", wait_for_timeout(10_000))
)
E e2b.template.exceptions.BuildException: failed to run command: exit status 1
tests/sync/template_sync/test_stacktrace.py:12: BuildException
========================================================== short test summary info ==========================================================
FAILED tests/sync/template_sync/test_stacktrace.py::test_build - e2b.template.exceptions.BuildException: failed to run command: exit status 1
```
**Node**
```
node:internal/modules/run_main:104
triggerUncaughtException(
^
at file:///Users/mish/Documents/Projects/E2B/E2B/packages/js-sdk/tests/template/trace.test.mts:8:4
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:98:5) {
name: 'BuildError'
}
Node.js v23.11.0
```
**Bun**
```
1 | export class BuildError extends Error {
2 | constructor(message: string, stackTrace?: string) {
3 | super(message)
^
BuildError: failed to run command: exit status 1
at /Users/mish/Documents/Projects/E2B/E2B/packages/js-sdk/src/template/errors.ts:3:5
Bun v1.2.4 (macOS arm64)
```
**Vitest**
```
BuildError: failed to run command: exit status 1
❯ tests/template/trace.test.ts:8:6
6| const template = Template()
7| .fromImage('ubuntu:22.04')
8| .runCmd('cat folder/test.txt')
| ^
9| .setWorkdir('/app')
10| .setStartCmd('echo "Hello, world!"', waitForTimeout(10_000))
```
---------
Co-authored-by: Jakub Dobry <jakub.dobry8@gmail.com>