Есть ли способ указать выходную ячейку, в которой функция должна печатать свои выходные данные?
В моем конкретном случае у меня запущено несколько потоков, каждый из которых имеет регистратор. Выходные данные регистратора печатаются в любой работающей ячейке, мешая предполагаемому выводу этой ячейки. Есть ли способ заставить регистратор печатать, например, только на cell #1
?
перенаправить логи в файл или отключить регистратор
Это общий вопрос; подробности не нужны. Как указано, у меня работает несколько потоков; Я хотел бы перенаправить их вывод в определенную ячейку, если это возможно. Меня не интересует использование файлов журналов. Я знаю, что могу записать все в файлы журналов, но я хочу, чтобы выходные данные печатались непосредственно в определенной ячейке.
Вы можете использовать следующий подход:
getLogger()
) в QueueHandler, чтобы накопить сообщения журнала в queue.Queue
.QueueListener
, как следует из названия, будет прослушивать новые элементы в очереди регистрации. Он передаст новые элементы в StreamHandler
, который их фактически распечатает.Предполагая, что мы хотим напечатать ниже ячейки 1, это может выглядеть следующим образом:
# 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()
В ячейке 2 мы смоделируем некоторую деятельность:
# 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()
И аналогично в ячейке 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()
Вывод будет происходить, по сути, в режиме реального времени, под ячейкой, содержащей вызов listener.start()
, то есть в ячейке 1 (и только там) в нашем случае. Это будет выглядеть так, как и ожидалось: для каждого зарегистрированного «Действия 2» мы будем видеть зарегистрированное «Действие 1» попеременно и примерно в два раза чаще, поскольку мы спим 2 секунды в первом случае и 1 секунду во втором:
После завершения обработки мы можем остановить QueueListener
(программно или вручную) с помощью listener.stop()
— точнее, мы должны остановить прослушиватель таким образом, следуя его документации: если вы не вызовете [stop()
] до выхода приложения , в очереди могут остаться записи, которые не будут обработаны.
Это не работает так, как я ожидал. В моем случае выходные данные по-прежнему отображаются в активной ячейке, а не в ячейке прослушивателя.
@alec_djinn Если вы говорите «это не работает», вы имеете в виду: (1) с моим кодом, опубликованным выше, без изменений или (2) с вашим собственным кодом, адаптированным, как предложено выше? Кроме того: вы говорите только о выходных данных журнала (которые должен обрабатывать приведенный выше код) или также об обычных выходных данных print()
(которые код выше не обрабатывает)?
С вашим кодом. Я получаю вывод в активной ячейке, а не в ячейке прослушивателя.
Проверьте это asteboard.co/UbsIRLY7mklt.png
Спасибо, что поделились, попробую воспроизвести.
Как видите, как только я print()
попадаю в другую ячейку, выходные данные логгера передаются в эту ячейку. Вместо этого оно должно было попасть в камеру слушателя.
Это странно. У меня не происходит. Возможно, это зависит от системы (что, я согласен, не было бы хорошим решением). Я здесь на Linux.
Я тоже на Linux. Но я использую ноутбук Jupyter, а не лабораторию. Возможно, это и есть виновник.
Я только что попробовал и в лаборатории, и в блокноте. Никакой разницы.
Я не знаю, тогда...
Я тоже не знаю, извини. Я также попробовал два браузера (Chromium и Firefox), и у меня оба работают. В таком случае, я думаю, вам следует оставить награду :)
Последняя попытка: может быть, это мешает вашей теме Jupyter? На скриншоте выше я видел, что вы использовали темный режим, но по умолчанию в Jupyter нет темного режима. Можете ли вы попробовать отключить темы/тему по умолчанию?
Сброс темы на стандартную ничего не изменил. Я бегу Jupyter Notebook 6.4.12
. На какой версии вы находитесь?
Jupyter Notebook 7.2.1 здесь (на Python 3.11.9)
Я только что попробовал использовать блокнот Jupyter 6.4.12 (Python 3.9.19, Ipython 7.33.0) в Firefox. У меня все еще работает.
На новой установке работает. Я принял решение. Спасибо!
Так рад это слышать! Хотя очень странное явление. В любом случае: я рад, что в итоге все получилось!
Вы можете создать оболочку, которая будет перенаправлять все напечатанное в другую ячейку.
# Cell 1
import logging
from io import StringIO
from IPython.display import display, HTML
import sys
# Set up a StringIO object to capture output
output_capture = StringIO()
ch = logging.StreamHandler(output_capture)
ch.setLevel(logging.INFO)
# Configure the logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(ch)
# Create a display area
display_id = display(HTML(''), display_id=True)
# Function to update the display
def update_display():
output_contents = output_capture.getvalue()
display_id.update(HTML(f"<pre>{output_contents}</pre>"))
def capture_output(func):
def wrapper(*args, **kwargs):
# Redirect stdout to our StringIO object
old_stdout = sys.stdout
sys.stdout = output_capture
try:
# Call the original function
result = func(*args, **kwargs)
finally:
# Restore stdout
sys.stdout = old_stdout
# Update the display
update_display()
return result
return wrapper
В следующей ячейке:
# Cell 2
@capture_output
def my_function():
print('Hello world!')
# Now when you call my_function(), anything printed within the function will be displayed in the first cell
my_function()
Это красивое решение, но оно не работает, когда функция сталкивается с потоками. Это требование.
Я бы сказал, что проще использовать
ipywidget
и отправлять туда изменения регистратора. См.: Виджет вывода.