Log Streaming
When executing long-running processes in a sandbox, you’ll often want to access and process their logs in real time.
The Daytona SDK supports both:
Fetching log snapshot
— retrieve all logs up to a certain point.Log streaming
— stream logs as they are being produced, while the process is still running.
This guide covers how to use log streaming in both asynchronous and synchronous modes. Real-time streaming is especially useful for debugging, monitoring, or integrating with observability tools.
Asynchronous
If your sandboxed process is part of a larger system and is expected to run for an extended period (or indefinitely), you can process logs asynchronously in the background, while the rest of your system continues executing.
This is ideal for:
- Continuous monitoring
- Debugging long-running jobs
- Live log forwarding or visualizations
import asynciofrom daytona_sdk import Daytona, SessionExecuteRequest
async def main(): daytona = Daytona() sandbox = daytona.create()
try: session_id = "exec-session-1" sandbox.process.create_session(session_id)
command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest( command='for i in {1..10}; do echo "Processing step $i..."; sleep 1; done', var_async=True, ), )
logs_task = asyncio.create_task( sandbox.process.get_session_command_logs_async( session_id, command.cmd_id, lambda chunk: print(f"Log chunk: {chunk}") ) )
print("Continuing execution while logs are streaming...") await asyncio.sleep(1) print("Other operations completed!")
print("At the end wait for any asynchronous task to complete and clean up resources...") await logs_task except Exception as e: print(f"Error: {e}") finally: print("Cleaning up sandbox...") daytona.remove(sandbox)
if __name__ == "__main__": asyncio.run(main())
import { Daytona, Sandbox } from '@daytonaio/sdk'
async function main() { const daytona = new Daytona() const sandbox = await daytona.create()
try { const sessionId = 'exec-session-async-logs' await sandbox.process.createSession(sessionId)
const command = await sandbox.process.executeSessionCommand(sessionId, { command: 'for i in {1..10}; do echo "Processing step $i..."; sleep 1; done', async: true, })
const logTask = sandbox.process.getSessionCommandLogs(sessionId, command.cmdId!, (chunk) => { console.log('Log chunk:', chunk) })
console.log('Continuing execution while logs are streaming...') sleep(1) console.log('Other operations completed!')
console.log('At the end wait for any asynchronous task to complete and clean up resources...') await logTask } catch (error) { console.error('Error:', error) } finally { console.log('Cleaning up sandbox...') await daytona.remove(sandbox) }}
main()
Synchronous
If the command has a predictable duration, or if you don’t need to run it in the background, you can process log stream synchronously. For example, you can write logs to a file or some other storage.
import asyncioimport osfrom daytona_sdk import Daytona, SessionExecuteRequest
async def main(): daytona = Daytona() sandbox = daytona.create()
try: session_id = "exec-session-1" sandbox.process.create_session(session_id)
command = sandbox.process.execute_session_command( session_id, SessionExecuteRequest( command='counter=1; while (( counter <= 5 )); do echo "Count: $counter"; ((counter++)); sleep 2; done', var_async=True, ), )
log_file_path = f"./logs/logs-session_{session_id}-command_{command.cmd_id}.log" os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
with open(log_file_path, "w") as log_file: def handle_chunk(chunk: str): # remove null bytes clean_chunk = chunk.replace("\x00", "") # write to file log_file.write(clean_chunk) log_file.flush()
await sandbox.process.get_session_command_logs_async( session_id, command.cmd_id, handle_chunk ) except Exception as e: print(f"Error: {e}") finally: print("Cleaning up sandbox...") daytona.remove(sandbox)
if __name__ == "__main__": asyncio.run(main())
import { Daytona, Sandbox } from '@daytonaio/sdk'
async function main() { const daytona = new Daytona() const sandbox = await daytona.create()
try { const sessionId = 'exec-session-async-logs' await sandbox.process.createSession(sessionId)
const command = await sandbox.process.executeSessionCommand(sessionId, { command: 'counter=1; while (( counter <= 5 )); do echo "Count: $counter"; ((counter++)); sleep 2; done', async: true, })
const logFilePath = `./logs/logs-session-${sessionId}-command-${command.cmdId}.log` const logsDir = path.dirname(logFilePath) if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }) }
const stream = fs.createWriteStream(logFilePath) await sandbox.process.getSessionCommandLogs(sessionId, command.cmdId!, (chunk) => { const cleanChunk = chunk.replace(/\x00/g, '') stream.write(cleanChunk) }) stream.end() await logTask } catch (error) { console.error('Error:', error) } finally { console.log('Cleaning up sandbox...') await daytona.remove(sandbox) }}
main()