Streamlit: How to live-capture both stdout and stderr from a running subprocess
This example showcases how to capture both stdout
and stderr
from a running subprocess in a Streamlit app. The output is displayed live in the Streamlit app, with combined output from both streams.
import streamlit as st
import asyncio
async def read_stream(stream, accumulated_output):
while True:
line = await stream.readline()
if not line:
break
line = line.decode().strip()
accumulated_output.append(line)
async def run_subprocess():
# Create placeholder for live output
output_placeholder = st.empty()
accumulated_output = []
process = await asyncio.create_subprocess_exec(
'bash', '-c',
'ping -c 3 1.1.1.1 && echo "Error message" >&2 && ping -c 3 1.1.1.1',
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
# Create tasks for reading both stdout and stderr
stdout_task = asyncio.create_task(read_stream(process.stdout, accumulated_output))
stderr_task = asyncio.create_task(read_stream(process.stderr, accumulated_output))
# Update display while streams are being read
while not stdout_task.done() or not stderr_task.done():
output_placeholder.code('\n'.join(accumulated_output))
await asyncio.sleep(0.1) # Small delay to prevent too frequent updates
# Wait for completion and ensure all output is captured
await asyncio.gather(stdout_task, stderr_task)
await process.wait()
# Final update of display
output_placeholder.code('\n'.join(accumulated_output))
# In your Streamlit app:
if st.button("Run Command"):
asyncio.run(run_subprocess())