[英]how to logging debug level to file but only info level on screen in python
[英]Python INFO to CONSOLE and DEBUG to FILE Logging
所以我几天来一直在尝试为我的问题找到解决方案......
我有以下结构
main.py
-> module1.py
-> task (Threadable Class)
-> module2.py
-> task (Threadable Class)
在我的主要用户中,用户可以选择一个模块以及在该模块中启动的任务数量。 每次发生新事情时,我都会打印()他们的状态。 来自 web 服务器的示例有效响应。 但是这样做会导致 output 变得混乱,因为多个线程同时调用 print。 即使 flush=True 在这里也没有帮助。
据我所知,实现良好输出的唯一解决方案是使用日志记录。 日志记录已经实现,因为程序在启动时创建一个带有调试信息的日志,并在运行时不断写入。 这是为了更好的错误跟踪和东西。
我尝试过以下独奏:
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler(f'log/{CURR_LOGFILE}.txt'),
logging.StreamHandler()
]
)
但这对我没有帮助,因为我希望将 logging.info() 打印到控制台,同时将 logging.debug() 打印到日志文件。
我将如何 go 使这项工作和线程安全? 或者是否有更好的方法让每个线程发出它们的状态?
Lock 不会起作用,因为它会临时锁定线程并且在此用例中每毫秒都很重要。
从技术上讲,使用logging
并不是唯一的解决方案。 您正确识别了问题:多个线程共享同一个标准输出缓冲区,它们在其中同时写入。 标准日志库恰好是线程安全的,但没有它你也可以这样做1 。
您可以创建一个threading.Lock
并重写您的一些代码,以便线程只能在持有锁时print
。
您的工作负载似乎并不繁重,因此性能应该不是问题。
1我认为这是一个XY 问题的情况:您实际上并不想使用logging
,如果我理解正确,您真正想要的只是同步您的输出,以便最后的显示不会混乱。
使用日志记录是有效的,因为它在内部也使用了锁。 所以说
我已经尝试过使用
threading.Lock
但由于代码必须在不停止运行的情况下执行 100 个线程会导致其他线程必须等到它们持有锁
是错误的。
这是一个简单的基准测试,我并不打算让它防弹,只是为了向您展示两种方法的工作方式相似:
import logging
import time
import threading
import random
import sys
logger = logging.getLogger("so70643825")
logger.addHandler(logging.StreamHandler(sys.stdout))
logger.setLevel(logging.INFO)
lock = threading.Lock()
def lock_print(*args, **kwargs):
with lock:
print(*args, **kwargs)
def task_creator(task_number: int, display_function):
def actual_task(x: int):
for i in range(x):
display_function(f"Task {task_number}, {i=}")
time.sleep(random.random() / 10) # sleep up to 0.1s
return actual_task
def run_tasks(number_of_threads: int, number_of_iterations: int, display_function):
threads = []
for thread_number in range(number_of_threads):
thread = threading.Thread(target=task_creator(task_number=thread_number, display_function=display_function),
args=(number_of_iterations,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
def main():
N_THREADS = 100
N_LOOPS = 10
N_MEASURES = 10
times = []
for i in range(N_MEASURES):
time_before_logging_tasks = time.time()
run_tasks(N_THREADS, N_LOOPS, logger.info)
time_after_logging_tasks = time.time()
time_before_locking_tasks = time.time()
run_tasks(N_THREADS, N_LOOPS, lock_print)
time_after_locking_tasks = time.time()
time_logging = time_after_logging_tasks - time_before_logging_tasks
time_locking = time_after_locking_tasks - time_before_locking_tasks
times.append((time_logging, time_locking,))
for time_logging, time_locking in times:
print(f"logging: {time_logging} locking: {time_locking} best={'LOG' if time_logging < time_locking else 'LOCK'}")
if __name__ == "__main__":
main()
结果:
logging: 0.7429051399230957 locking: 0.7113175392150879 best=LOCK
logging: 0.7250735759735107 locking: 0.6937775611877441 best=LOCK
logging: 0.712653636932373 locking: 0.691455602645874 best=LOCK
logging: 0.7124729156494141 locking: 0.6672348976135254 best=LOCK
logging: 0.7507524490356445 locking: 0.7678782939910889 best=LOG
logging: 0.690934419631958 locking: 0.7111172676086426 best=LOG
logging: 0.7271988391876221 locking: 0.7642250061035156 best=LOG
logging: 0.7295012474060059 locking: 0.7794029712677002 best=LOG
logging: 0.7717809677124023 locking: 0.7706160545349121 best=LOCK
logging: 0.7927803993225098 locking: 0.7397556304931641 best=LOCK
这是 LOG 和 LOCK 的混合获胜,但每次它们之间的差异很小。
消除随机sleep
使 LOCK 成为明显的赢家(至少快十倍)。 我认为这是因为睡眠使所有日志记录机器引入的开销相形见绌,而 lock_print 并不需要这些开销。
如果表演对问题非常重要(我是认真的),那么您最初应该说出来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.