Sazabi
Log sourcesSend to an endpoint

E2B

Wire an OpenTelemetry log exporter into the host process that creates E2B sandboxes to capture stdout and stderr from sandbox code execution and forward them to Sazabi.

About

Capture stdout and stderr from E2B sandboxes and stream them to Sazabi as OTLP log records. The host application — the process that creates sandboxes via the E2B SDK — wires an OpenTelemetry log exporter and routes sandbox output callbacks through it. Each stdout or stderr line becomes one log record tagged with the sandbox ID and stream name.

Prerequisites

  • An application using @e2b/code-interpreter (TypeScript) or e2b_code_interpreter (Python) to create sandboxes
  • An OpenTelemetry SDK for your application runtime
  • Your Sazabi intake URL, shown above — open the log source and copy the Intake URL from its setup screen (the public key is embedded in the URL)

Set up in the dashboard

Set the intake URL environment variable

In the environment where your host application runs, set:

SAZABI_INTAKE_URL=<your intake URL>

Replace <your intake URL> with the intake URL shown above.

Instrument the host application

Add the OpenTelemetry SDK and wire sandbox output callbacks through a log emitter.

import { Sandbox } from "@e2b/code-interpreter";
import { LoggerProvider, BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
import { logs } from "@opentelemetry/api-logs";

const exporter = new OTLPLogExporter({ url: `${process.env.SAZABI_INTAKE_URL}/v1/logs`, });

const loggerProvider = new LoggerProvider(); loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(exporter)); logs.setGlobalLoggerProvider(loggerProvider);

const logger = logs.getLogger("e2b-sandbox");

const sandbox = await Sandbox.create();

try { await sandbox.runCode("print('hello from sandbox')", { onStdout: (output) => { logger.emit({ body: output.line, attributes: { stream: "stdout", sandboxId: sandbox.sandboxId }, }); }, onStderr: (output) => { logger.emit({ body: output.line, severityText: "ERROR", attributes: { stream: "stderr", sandboxId: sandbox.sandboxId }, }); }, }); } finally { await sandbox.kill(); await loggerProvider.shutdown(); }
import os
import logging
from e2b_code_interpreter import Sandbox
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter

exporter = OTLPLogExporter(endpoint=f"{os.environ['SAZABI_INTAKE_URL']}/v1/logs")
logger_provider = LoggerProvider()
logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
set_logger_provider(logger_provider)

handler = LoggingHandler(logger_provider=logger_provider)
logging.getLogger().addHandler(handler)
logger = logging.getLogger("e2b-sandbox")

sandbox = Sandbox()
try:
    execution = sandbox.run_code(
        "print('hello from sandbox')",
        on_stdout=lambda output: logger.info(output.line, extra={"stream": "stdout", "sandboxId": sandbox.sandbox_id}),
        on_stderr=lambda output: logger.error(output.line, extra={"stream": "stderr", "sandboxId": sandbox.sandbox_id}),
    )
finally:
    sandbox.kill()
    logger_provider.shutdown()

Set up with the CLI

You can also register the E2B log source with the Sazabi CLI (installed and authenticated — see CLI reference).

Registering the source mints the same intake URL the dashboard shows above (the public key is embedded in its hostname):

sazabi log-sources create e2b --mode connectionless

The command prints the intake URL for the new source — copy the whole URL and point your sender at it using the configuration shown above. Run sazabi log-sources get <log-source-id> at any time to reprint the endpoint, or sazabi log-sources list to see every log source in the project.

Verify

Run your host application so it creates a sandbox and executes code that produces stdout or stderr output. Open the Intake page in the Sazabi dashboard and confirm records from the E2B source appear within a minute or two.

Start a thread and filter by sandboxId to view output from a specific sandbox execution.

Troubleshooting

No records after running — Confirm SAZABI_INTAKE_URL is set in the process running the host application. Check for OTLP export errors printed by the SDK during shutdown (they surface during loggerProvider.shutdown()).

Shutdown not called — The BatchLogRecordProcessor buffers records and flushes on shutdown. If the host process exits without calling loggerProvider.shutdown(), buffered records may be lost. Always call shutdown in a finally block.

Incomplete output — Each stdout/stderr line is emitted as a separate log record. If sandbox code buffers output, some lines may not appear until the buffer flushes.

Further reading