From what youâve described, it seems like your main objective is to display logs from task.py in your app as theyâre generated. What youâve tried involves redirecting stdout, which is a common strategy for capturing print statements. But it wonât work for capturing log messages directly, as Pythonâs logging module doesnât use stdout by default for its output.
Since Streamlitâs loggers donât write to stdout (the loggers are set up with a StreamHandler that writes to the console) and do not propagate their messages to the root logger (which was configured to redirect to stdout), log messages were not captured by your stdout_capture context manager.
As youâve suggested, writing your own log handler might be the way to go. You could extend Streamlitâs logger with a custom handler that routes logs to st.empty().code for display, like so:
# app.py
import logging
import task
import streamlit as st
from streamlit.logger import get_logger
class StreamlitLogHandler(logging.Handler):
def __init__(self, widget_update_func):
super().__init__()
self.widget_update_func = widget_update_func
def emit(self, record):
msg = self.format(record)
self.widget_update_func(msg)
logger = get_logger(task.__name__)
handler = StreamlitLogHandler(st.empty().code)
logger.addHandler(handler)
# Run your task
task.run()
# task.py
import logging
logger = logging.getLogger(__name__)
import time
import streamlit as st
def run(*args, **kwargs):
logger.info("đ Running task ")
time.sleep(2)
logger.info("đ„” Still running task")
time.sleep(2)
logger.info("â
Finished task")
Breakdown:
- Use
get_loggerfromstreamlit.logger, which retrieves a Streamlit-configured logger. Itâs already set up with Streamlitâs logging config such as format and level - Define
StreamlitLogHandlerâ a custom logging handler that overrides theemitmethod. This method is called whenever a log message is sent to the handler - In the
emitmethod, the logs are formatted into a message string, and then passed to thewidget_update_func, which in this case isst.empty().code - By adding
StreamlitLogHandlerto the Streamlit logger (logger.addHandler(handler)), youâre ensuring that any logs processed by this logger are also passed to the custom handler. And since the custom handler is designed to update a Streamlit element, you see the logs in your app

Does this help? ![]()