我有一个旧项目,我只使用了打印语句,我想开始使用日志记录模块。 这是项目的结构:
执行时,我得到用户输入,然后我转到 TASK.py 和 LOG_SERIAL.py(线程)。
示例: 流\文件
DATE - NAME - SYSTEM - "....."
DATE - NAME - SYSTEM - "....."
DATE - NAME - TASKS - "...."
DATE - NAME - TASKS - "...."
这是我目前所做的:
# main.py
import TASKS
def get_logger():
FORMAT = logging.Formatter('%(asctime)s-%(name)s-[%(levelname)s]-%(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(FORMAT)
file_handler = logging.FileHandler('console.log', mode='w')
file_handler.setFormatter(FORMAT)
logging.addLevelName(logging.DEBUG, 'SYSTEM')
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
return logger
然后我在 MAIN.py 上使用它:
logger = get_logger()
logger.debug("...")
# tasks.py
def get_logger():
FORMAT = logging.Formatter('%(asctime)s-%(name)s-[%(levelname)s]-%(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(FORMAT)
file_handler = logging.FileHandler('console.log', mode='a+')
file_handler.setFormatter(FORMAT)
logging.addLevelName(logging.INFO, 'TASKS')
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
return logger
然后我打电话:
logger = get_logger()
logger.info("...")
这是我为两个处理程序得到的:
2021-06-14 19:35:42,253-__main__-[SYSTEM]-"..."
2021-06-14 19:35:49,576-clients-[TASKS]-"...."
我相信没有 tasks.py 上的样板代码可以做得更好。
答案 0 :(得分:0)
我认为你混淆了很多东西,所以这里是一个回顾:
您的 FORMAT 指定要包含在日志输出中的记录器名称 (%(name)s
),在这里不是最佳选择,您可以使用其他名称 (参见 doc):
%(filename)s
会给你 main.py
%(module)s
会给你 main
__name__
是模块名,不是文件名(参见 doc,搜索 __file__
)
import os.path
,那么 os.path
将是此模块中 __name__
的值__name__
将是 __main__
(参见 doc )__file__
是文件的绝对路径,例如 C:/PycharmProjects/stack_overflow/q67975119/main.py
在我的情况下
您将日志级别别名为“SYSTEM”,以便将其写入输出中。不建议将日志级别用于日志(严重性)级别以外的其他事项。
您的函数 get_logger
执行配置然后返回一个实例。但是日志配置是全局,所以第二次调用它会产生讨厌的副作用(特别是addHandler
),所以不建议混合实际的设置强大> 获取实例的日志基础架构。
这里是您问题的解决方案:
SYSTEM
显示为记录器的名称,您可以:
FORMAT
中:'%(asctime)s-SYSTEM-[%(levelname)s]-%(message)s'
SYSTEM
,因此将您创建的记录器替换为 logger = logging.getLogger("SYSTEM")
get_logger
函数中的日志设置提取到另一个函数中,该函数仅在程序启动时调用一次(最好在 if __name__ == "__main__":
块中)。我的建议是不要使用 __file__
或 __name__
作为您的记录器名称,只需将它们命名为 "main"
和 "tasks"
。如果您不打算重命名源文件,这是一种更简单、更灵活的解决方案。
提示:将您的 FileHandler
模式更改为 w+
或 a
,这样每次新的程序运行时,日志都会附加到上次运行的日志中,而不是覆盖(丢失) 他们。
这是一个完整的例子:
# main.py
import logging
from q67975119 import serial, tasks
def setup_main_logging():
FORMAT = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(FORMAT)
file_handler = logging.FileHandler('console.log', mode='w')
file_handler.setFormatter(FORMAT)
system_logger.setLevel(logging.DEBUG)
system_logger.addHandler(console_handler)
system_logger.addHandler(file_handler)
system_logger = logging.getLogger("SYSTEM")
if __name__ == '__main__':
setup_main_logging() # before using the logger for the first time !
tasks.setup_tasks_logging() # before using the logger for the first time !
system_logger.debug(f"__file__={__file__!r}")
system_logger.debug(f"__name__={__name__!r}")
tasks.do_task()
serial.do_serial()
# serial.py
def do_serial():
import main # to prevent circular imports
system_logger = main.system_logger
system_logger.info(f"__file__={__file__!r}")
system_logger.info(f"__name__={__name__!r}")
# tasks.py
import logging
def setup_tasks_logging():
FORMAT = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(FORMAT)
file_handler = logging.FileHandler('console.log', mode='a+')
file_handler.setFormatter(FORMAT)
tasks_logger.setLevel(logging.INFO)
tasks_logger.addHandler(console_handler)
tasks_logger.addHandler(file_handler)
tasks_logger = logging.getLogger("TASKS")
def do_task():
tasks_logger.info(f"__file__={__file__!r}")
tasks_logger.info(f"__name__={__name__!r}")
运行时,我在标准输出和文件中得到同样的结果:
2021-06-17 11:50:19,661 - SYSTEM - [DEBUG] - __file__='C:/Users/PycharmProjects/stack_overflow/q67975119/main.py'
2021-06-17 11:50:19,661 - SYSTEM - [DEBUG] - __name__='__main__'
2021-06-17 11:50:19,661 - TASKS - [INFO] - __file__='C:/Users/PycharmProjects/stack_overflow/q67975119/tasks.py'
2021-06-17 11:50:19,661 - TASKS - [INFO] - __name__='q67975119.tasks'
2021-06-17 11:50:19,663 - SYSTEM - [INFO] - __file__='C:/Users/PycharmProjects/stack_overflow/q67975119/serial.py'
2021-06-17 11:50:19,663 - SYSTEM - [INFO] - __name__='q67975119.serial'
如果您想减少样板文件,您可以使用 logging.config
,它允许您将配置放在文本文件或 Python 字典中,并按原样提供给日志库。
使用文件的示例:
# main.py
import logging.config
from q67975119 import serial, tasks
system_logger = logging.getLogger("SYSTEM")
if __name__ == '__main__':
logging.config.fileConfig("logging.config")
system_logger.debug(f"__file__={__file__!r}")
system_logger.debug(f"__name__={__name__!r}")
tasks.do_task()
serial.do_serial()
和 logging.config
文件:
[loggers]
keys=root,system,tasks
[handlers]
keys=console,file
[formatters]
keys=formatter
[logger_root]
level=NOTSET
handlers=console,file
[logger_system]
level=DEBUG
handlers=console,file
propagate=0
qualname=SYSTEM
[logger_tasks]
level=INFO
handlers=console,file
propagate=0
qualname=TASKS
[handler_console]
class=StreamHandler
level=NOTSET
formatter=formatter
args=(sys.stdout,)
[handler_file]
class=FileHandler
level=NOTSET
formatter=formatter
args=('console.log', 'w+')
[formatter_formatter]
format=%(asctime)s - %(name)s - [%(levelname)s] - %(message)s
datefmt=
class=logging.Formatter
它产生与通过代码指定所有内容完全相同的输出(标准输出和文件)。