python - Python:登录到通用文件
问题描述
我有一个带有各种嵌套模块的 python 项目。我想要一个setup_logger
函数,在每个文件的开头调用它来设置记录器
from _base import setup_logger
logger = setup_logger()
并在主调用脚本的文件名之后自动生成日志文件的名称。例如,我希望能够在终端中执行脚本myscript.py,这应该记录到名为myscript_<proc_id>.log的文件中。在该日志文件中应该由将在执行期间调用的所有模块写入。也就是说,我想要的输出是单个日志文件(以主调用者命名,例如myscript_45469.log为myscript.py)和日志字符串如下:
2021-05-15 21:06:15: myscript[45469] INFO : A log message from myscript.py
2021-05-15 21:06:16: submodule_1[45469] INFO : A log message from submodule_1.py
2021-05-15 21:06:17: submodule_2[45469] INFO : A log message from submodule_2.py
在我的终端中,这正是我得到的。但是,输出仍然写入单独的文件,每个文件中只有相应模块的消息:
$ ls
myscript_45469.log submodule_1_45469.log submodule_2_45469.log
$ cat submodule_1_45469.log
2021-05-15 21:06:16: submodule_1[45469] INFO : A log message from submodule_1.py
到目前为止,我的setup_logger
函数如下所示:
# _base.py
from pathlib import Path
import logging
import os
def setup_logger(name=None, level="INFO", logfile=True):
frame = inspect.stack()[1]
caller_filename = frame[0].f_code.co_filename
caller_filename = Path(caller_filename).stem
if not name:
name = caller_filename
logger = logging.getLogger(name)
logger.setLevel(os.getenv('LOGLEVEL', 'INFO').upper())
formatter = logging.Formatter('%(asctime)s: %(name)s[%(process)d] %(levelname)-8s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
if logfile:
logfile = f'{name}_{os.getpid()}.log'
fh = logging.FileHandler(logfile)
fh.setFormatter(formatter)
fh.setLevel(os.getenv('LOGLEVEL', 'INFO').upper())
logger.addHandler(fh)
ch = logging.StreamHandler()
ch.setFormatter(formatter)
logger.addHandler(ch)
return logger
然后在每个(子)模块的开头调用该函数:
# submodule_1 or submodule_2, etc
from _base import *
logger = setup_logger()
logger.info("A log message from submodule_1")
如何在不对记录器设置中的文件名进行硬编码的情况下实现我想要的目标?我已经在 stackoverflow 和许多日志记录教程上浏览了相当多的帖子,但到目前为止我找不到解决方案。提前感谢您的任何意见!
解决方案
当你处理的时候logging
,你应该依赖层次结构。
假设您的项目的树结构设置如下:
project/
├─ myscript.py
├─ package/
│ ├─ submodule.py
在您的子模块中,您需要获取模块名称记录器;在这种情况下是package.submodule
。
# submodule.py
import logging
logger = logging.getLogger(__name__) # package.submodule
之后,前往myscript
,您需要按照您希望的工作方式设置记录器。
# myscript.py
import logging
logger = logging.getLogger("package") # intercept all "package" loggers
logger.setLevel("<your_level>")
formatter = logging.Formatter("<your_format>")
sh = logging.StreamHandler()
fh = logging.FileHandler("package.log")
for handler in (sh, fh):
handler.setFormatter(formatter)
logger.addHandler(handler)
像这样设置您的环境,执行中引用的所有记录器都会像您希望的那样运行,因此使用通用格式和通用日志级别记录到控制台和(相同)日志文件。
如果您的子模块处于模块级别(因此没有package
),您应该getLogger()
- 它会选择根记录器。无论哪种情况,它都会按预期工作。
推荐阅读
- c++ - 对多维数组中的 .csv 进行排序
- swift - 如何在swift xcode中设置框填充颜色值
- c# - 如何在 Microsoft 图表控件的中心仅显示 Y 轴的一条虚线?
- hive - DynamoDB EMR Hive 连接器一次写入 1 个项目
- java - Apache Spark - 'LeftAnti' 加入不明确的列错误
- selenium - 在 browserstack 上运行测试会抛出“无法读取 null 的属性‘功能’”
- uilabel - UILabel 是字符换行而不是正确换行
- json - 在 Bot 模拟器中打印表,其字段包含类对象值
- angular - 获取文本值
- 点击后的元素
- paypal - 贝宝订阅:批准终身?