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_logger
fromstreamlit.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 theemit
method. This method is called whenever a log message is sent to the handler - In the
emit
method, the logs are formatted into a message string, and then passed to thewidget_update_func
, which in this case isst.empty().code
- By adding
StreamlitLogHandler
to 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?