Jupyter notebook. How to direct the output to a specific cell?
Is there a way to specify the output cell where a function should print its output?
In my specific case, I have some threads running, each with a logger. The logger output is printed on any running cell, interfering with that cell's intended output. Is there a way I can force the logger to print only on cell #1
, for example?
Answer
You could use the following approach:
- Redirect all log messages in the root logger (which you will get by calling
getLogger()
) to aQueueHandler
to accumulate the log messages in aqueue.Queue
. - In the intended output cell, start a
QueueListener
that wraps aStreamHandler
. TheQueueListener
, as its name implies, will listen to new items on the logging queue. It will pass new items to theStreamHandler
, which will actually print them.
Assuming we want to print below cell 1, this could look as follows:
# Cell 1
import logging, queue, threading, time
from logging.handlers import QueueHandler, QueueListener
log_queue = queue.Queue(-1)
logging.getLogger().addHandler(QueueHandler(log_queue))
listener = QueueListener(log_queue, logging.StreamHandler())
listener.start()
In cell 2, we will simulate some activity:
# Cell 2
def log_activity_1():
while True:
logging.getLogger().warning("Activity 1")
time.sleep(1)
threading.Thread(target=log_activity_1, daemon=True).start()
And likewise, in cell 3:
# Cell 3
def log_activity_2():
while True:
logging.getLogger().warning("Activity 2")
time.sleep(2)
threading.Thread(target=log_activity_2, daemon=True).start()
The output will happen, basically in real time, under the cell that contains the listener.start()
call, thus under cell 1 (and only there) in our case. It will look as expected: For each logged "Activity 2", we will see "Activity 1" logged in alternation and approximately twice as often, as we sleep 2 seconds in the former, and 1 second in the latter:
Once processing has finished, we can stop the QueueListener
(either programmatically or manually) via listener.stop()
– or rather, we should stop the listener this way, following here: if you don’t call [stop()
] before your application exits, there may be some records still left on the queue, which won’t be processed.