Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 配置第三方脚本的日志记录_Python_Logging - Fatal编程技术网

Python 配置第三方脚本的日志记录

Python 配置第三方脚本的日志记录,python,logging,Python,Logging,我有一个第三方python控制台脚本,我不想修改它的源代码 但是我想配置由脚本及其库完成的日志记录。该脚本使用标准python日志记录,但不支持对其进行配置 脚本使用以下模式: import logging logger=logging.getLogger(__name__) 用例: 我希望忽略foo.py文件的信息消息 我想在日志消息中包括PID 如果我不想修改控制台脚本的源代码,如何配置日志记录 通过cron调用脚本 如果使用此脚本,如何配置日志记录 重要的 对我来说,创建类似中的包装

我有一个第三方python控制台脚本,我不想修改它的源代码

但是我想配置由脚本及其库完成的日志记录。该脚本使用标准python日志记录,但不支持对其进行配置

脚本使用以下模式:

import logging
logger=logging.getLogger(__name__)
用例:

  • 我希望忽略foo.py文件的信息消息
  • 我想在日志消息中包括PID
如果我不想修改控制台脚本的源代码,如何配置日志记录

通过
cron
调用脚本

如果使用此脚本,如何配置日志记录

重要的 对我来说,创建类似中的包装器脚本不是一个解决方案

linux进程层次结构如下所示:

Cron -> third_party_script
cron和
第三方脚本之间应该有任何“胶水”、“包装”或“肮脏的黑客”脚本

为什么要突兀/网络采摘? 我想练习“关注点分离”。我希望能够一次性在一个地方配置日志记录。virtualenv的所有python代码都应该使用此配置。编写包装器将是一项工作。我想要一个解决方案

更新
几个月后,我认为pth文件将是一个简单的答案。

您可以更改该记录器的最低日志级别

logging.getLogger(__name__).setLevel(logging.WARNING)
现在,只会显示警告及以上内容。没有信息,也没有调试

此外,您还可以更改格式<代码>%(进程)d
为PID

log_format = logging.Formatter('%(asctime)s %(levelname)s %(name)s %(process)d: %(message)s', '%H:%M:%S')
logging.getLogger(__name__).setFormatter(log_format)
总而言之:

log_format = logging.Formatter('%(asctime)s %(levelname)s %(name)s %(process)d: %(message)s', '%H:%M:%S')
log_handle = logging.getLogger(__name__)
log_handle.setLevel(logging.WARNING)
log_handle.setFormatter(log_format)

注意:您应该用相关的日志处理程序替换代码中的
\uuuu name\uuuu

库不应该配置日志记录-这取决于应用程序开发人员。Inbar Rose的答案并不完全正确。如果您正在引用的模块被称为
foo
,那么在其
getLogger
调用中对
\uuuu name\uuuu
的引用将传入
foo
。因此,在配置代码中,您需要执行与

logging.getLogger('foo').setLevel(logging.WARNING)
要在日志中包含PID,只需确保为格式化程序使用适当的格式字符串,即包含
%(进程)d
。一个简单的例子是:

logging.basicConfig(format='%(process)d %(message)s')

注意,您不能同时从多个进程写入同一个日志文件——如果您想这样做,您可能需要考虑。 更新:应用程序开发人员是编写Python代码的人,该代码不是库,而是由用户或其他脚本通过命令行或其他创建Python进程的方式调用的

要使用我上面发布的代码,不需要包装或修改第三方代码,只要它是一个库。例如,在调用第三方库的主脚本中:

if __name__ == '__main__':
    # configure logging here
    # sets the third party's logger to do WARNING or greater
    # replace 'foo' with whatever the top-level package name your
    # third party package uses
    logging.getLogger('foo').setLevel(logging.WARNING)
    # set any other loggers to use INFO or greater,
    # unless otherwise configured explicitly
    logging.basicConfig(level=logging.INFO, format='%(process)d %(message)s')
    # now call the main function (or else inline code here)
    main()

如果第三方代码是通过cron运行的,那么它不是库代码——它是一个应用程序,您可能运气不好。

几个月前我问过这个问题。不幸的是,我没有得到令我满意的答案

使用日志和设置日志之间的区别对我来说很重要

这是我的解决方案:在我们的上下文中,我们在
usercustomize.py
中调用的方法中设置日志记录

这样,可选插件就可以使用日志,而无需进行设置

这几乎解决了我所有的需要

到目前为止,我还没有找到比
usercustomize.py
更好的方法。我的完美解决方案是调用
virtualenvcustomize.py
:如果解释器加载virtualenv,就会运行一些初始化代码。到目前为止,我还没有找到这样一个钩子。如果您有解决方案,请告诉我。

几种可能性:

包装器

如果您可以编辑cron表,您可以用python创建一个小脚本来获取lib logger,删除现有的日志处理程序,并将自定义处理程序挂在上面:

# Assumes the lib defines a logger object
from third_party_lib import *

# Note this assumes only one handler was defined by the lib
logger.removeHandler(logger.handlers[0])

# Then we can hook our custom format handler
custom_handler = logging.StreamHandler(sys.stdout)
custom_handler.setFormatter(logging.Formatter(format = '%(asctime)s %(levelname)s %(name)s %(process)d: %(message)s', None))
logger.addHandler(custom_handler)
logger.setLevel(logging.WARNING)
还要记住,假设lib没有在途中重新声明记录器

动态代码编辑

如果无法修改cron调用,则可以进行动态代码编辑,但这相当于手动编辑文件(hacky):

  • 获取包含记录器配置的第三方文件
  • 修改并保存修改后的版本
  • cron作业使用第三方代码启动任务
  • 执行cron作业后,将文件恢复到原始状态
tl;博士 简而言之,我们要做的是在执行主代码之前插入python解释器执行的代码

实现这一点的最佳方法是创建一个virtualenv并添加 virtualenv的站点包中的
sitecustomize.py

$ cat my_venv/lib/python3.7/site-packages/sitecustomize.py

import logging

# Setup logging for my_app
# We will only setup a console handler
logger = logging.getLogger("my_app")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setFormatter(
    logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
)
logger.addHandler(ch)
示范 假设我们要运行的应用程序名为
my_app.py
,并且 记录器具有相同的名称

$ cat my_app.py

import logging
logger = logging.getLogger("my_app")

logger.debug("A debug message")
logger.info("An info message")
logger.warning("A warning message")
logger.error("An error message")
运行
my_app.py
应仅显示严重性为>
警告的消息(其中
是python日志记录中的默认行为)

现在让我们创建一个虚拟环境

python3 -m venv my_venv
让我们将
sitecustomize.py
添加到virtualenv的站点包中

$ cat my_venv/lib/python3.7/site-packages/sitecustomize.py

import logging

# Setup logging for my_app
# We will only setup a console handler
logger = logging.getLogger("my_app")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setFormatter(
    logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
)
logger.addHandler(ch)
现在,让我们尝试使用virtualenv运行
my_app.py

$/my\u venv/bin/python my\u app.py
2019-01-25 16:03:16815-我的应用程序-调试-调试消息
2019-01-25 16:03:16815-我的应用程序-信息-信息消息
2019-01-25 16:03:16815-my_应用程序-警告-警告消息
2019-01-25 16:03:16815-我的应用程序-错误-错误消息
(仅此而已) 我们获得了正确的日志记录,而无需修改
my_app.py
或编写包装器

现在,如果你想知道为什么这是最佳方法,请继续阅读

(真的)很长的回答 在理解为什么使用virtualenv+
sitecustomize.py是正确的方法之前
对于这个问题,我们需要做一个不那么简短的介绍

注:我假设y
~/.local/lib/python3.7/site-packages/sitecustomize.py
/usr/lib/python3.7/site-packages/sitecustomize.py
$ python3 -s -msite

sys.path = [
    '/tmp/test',
    '/usr/lib/python37.zip',
    '/usr/lib/python3.7',
    '/usr/lib/python3.7/lib-dynload',
    '/usr/lib/python3.7/site-packages',
]
USER_BASE: '/home/username/.local' (exists)
USER_SITE: '/home/username/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: False
$ python3 -S -msite

sys.path = [
    '/tmp/test',
    '/usr/lib/python37.zip',
    '/usr/lib/python3.7',
    '/usr/lib/python3.7/lib-dynload',
]
USER_BASE: '/home/username/.local' (exists)
USER_SITE: '/home/username/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: None
$ ./venv_no_system/bin/python -msite

/tmp/test/venv_no_system/lib/python3.7/site-packages/sitecustomize.py
sys.path = [
    '/tmp/test',
    '/usr/lib/python37.zip',
    '/usr/lib/python3.7',
    '/usr/lib/python3.7/lib-dynload',
    '/tmp/test/venv_no_system/lib/python3.7/site-packages',
]
USER_BASE: '/home/username/.local' (exists)
USER_SITE: '/home/username/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: False
$ ./venv_system/bin/python -msite

-> /home/username/.local/lib/python3.7/site-packages/sitecustomize.py
-> /home/username/.local/lib/python3.7/site-packages/usercustomize.py
sys.path = [
    '/tmp/test',
    '/usr/lib/python37.zip',
    '/usr/lib/python3.7',
    '/usr/lib/python3.7/lib-dynload',
    '/tmp/test/venv_system/lib/python3.7/site-packages',
    '/home/username/.local/lib/python3.7/site-packages',
    '/usr/lib/python3.7/site-packages',
]
USER_BASE: '/home/username/.local' (exists)
USER_SITE: '/home/username/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: True
# remove the virtualenvs
rm -rf my_venv
rm -rf venv_system
rm -rf venv_no_system

# remove our usercustomize.py and sitecustomize.py
sudo rm /usr/lib/python3.7/site-packages/sitecustomize.py
sudo rm /usr/lib/python3.7/site-packages/usercustomize.py
rm ~/.local/lib/python3.7/site-packages/sitecustomize.py
rm ~/.local/lib/python3.7/site-packages/usercustomize.py

# remove the modules
rm foo.py
rm my_app.py