Python 更改配置后接收意外日志消息

Python 更改配置后接收意外日志消息,python,logging,Python,Logging,以前我使用过这种日志模式 log = logging.getLogger(__name__) log.setLevel(logging.DEBUG) fh = logging.FileHandler("logs.log", 'w', encoding="utf-8") formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) log.addHandle

以前我使用过这种日志模式

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
fh = logging.FileHandler("logs.log", 'w', encoding="utf-8")
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
log.addHandler(fh)
我的日志文件包含以下消息:

2019-08-21 11:08:08,271 - INFO - Started
2019-08-21 11:08:08,271 - INFO - Connecting to Google Sheets...
2019-08-21 11:08:11,857 - INFO - Successfuly connected to Google Sheet
2019-08-21 11:08:11,869 - ERROR - Not found: 'TG'
2019-08-21 11:08:11,869 - DEBUG - Getting values from Sheets...
2019-08-21 11:08:12,452 - DEBUG - Got new event row: "Flex - Flex"
2019-08-21 11:08:12,453 - DEBUG - Done. Values: 
...
它看起来很丑,我把它改成:

logging.basicConfig(
   level = logging.DEBUG,
   format = '%(asctime)s - %(levelname)s - %(message)s',
   filename = 'logs.log', filemode = 'w'
 )
log = logging.getLogger()
现在我的日志文件看起来是这样的

2019-08-21 11:14:02,374 - INFO - Started
2019-08-21 11:14:02,374 - INFO - Connecting to Google Sheets...
2019-08-21 11:14:02,406 - DEBUG - [b'eyJ0eX...jcifQ', b'eyJ...NvbSJ9', b'f7BQ...dE2w']
2019-08-21 11:14:02,407 - INFO - Refreshing access_token
2019-08-21 11:14:03,448 - DEBUG - Starting new HTTPS connection (1): www.googleapis.com:443
2019-08-21 11:14:04,447 - DEBUG - https://www.googleapis.com:443 "GET /drive/v3/files?q=mimeType%3D%27application%2Fvnd.google-apps.spreadsheet%27&pageSize=1000&supportsTeamDrives=True&includeTeamDriveItems=True HTTP/1.1" 200 None
2019-08-21 11:14:04,450 - DEBUG - Starting new HTTPS connection (1): sheets.googleapis.com:443
2019-08-21 11:14:05,782 - DEBUG - https://sheets.googleapis.com:443 "GET /v4/spreadsheets/1q6...cTI?includeGridData=false HTTP/1.1" 200 None
2019-08-21 11:14:05,899 - INFO - Successfuly connected to Google Sheet
2019-08-21 11:14:05,901 - ERROR - Not found: 'TG'
2019-08-21 11:14:05,902 - DEBUG - Getting values from Sheets...
2019-08-21 11:14:06,426 - DEBUG - https://sheets.googleapis.com:443 "GET /v4/spreadsheets/1q6...cTI/values/%D0%9B%D0%B8%D1%81%D1%821 HTTP/1.1" 200 None
2019-08-21 11:14:06,543 - DEBUG - Got new event row: xxx
2019-08-21 11:14:06,544 - DEBUG - Done. Values: xxx
2019-08-21 11:14:06,544 - DEBUG - Getting line...
2019-08-21 11:14:06,550 - DEBUG - Starting new HTTPS connection (1): api.site.com:443
2019-08-21 11:14:07,521 - DEBUG - https://api.site.com:443 "GET /v1/fix...?Id=33 HTTP/1.1" 200 6739
我收到了一些我在代码中没有使用的调试日志请求

如何关闭它?
我发现这是因为“请求”模块的缘故,您可以尝试以下代码。在这种情况下,您不需要更改日志模块的基本配置。您只能配置
logging.getLogger
的实例。如果您使用这个实现,它不应该对其他模块产生影响。此外,您还可以单独处理控制台和文件,因此此记录器可以更易于配置

代码:

import logging

# Create a custom logger
logger = logging.getLogger(__name__)

# Create handlers
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler("logs.log", "w", encoding="utf-8")
c_handler.setLevel(logging.INFO)
f_handler.setLevel(logging.DEBUG)

# Create formatters and add it to handlers
c_format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
f_format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)

# Add handlers to the logger
logger.addHandler(c_handler)
logger.addHandler(f_handler)

logger.warning("This is a warning")
logger.error("This is an error")
>>> python test.py 
2019-08-21 08:55:10,579 - WARNING - This is a warning
2019-08-21 08:55:10,580 - ERROR - This is an error
输出:

import logging

# Create a custom logger
logger = logging.getLogger(__name__)

# Create handlers
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler("logs.log", "w", encoding="utf-8")
c_handler.setLevel(logging.INFO)
f_handler.setLevel(logging.DEBUG)

# Create formatters and add it to handlers
c_format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
f_format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)

# Add handlers to the logger
logger.addHandler(c_handler)
logger.addHandler(f_handler)

logger.warning("This is a warning")
logger.error("This is an error")
>>> python test.py 
2019-08-21 08:55:10,579 - WARNING - This is a warning
2019-08-21 08:55:10,580 - ERROR - This is an error

来自requests模块的所有日志消息都是由于下面的代码

logging.basicConfig(
   level = logging.DEBUG   # This sets the root logger to DEBUG
 )
logging.basicConfig
更改程序中存在的根记录器的记录器配置

由于您在这里使用了
请求
模块,
请求
使用打印这些调试消息的
urlib3

修正: 您可以使用您的第一个记录器初始化代码来配置记录器。除此之外,您还可以使用以下代码

logging.basicConfig(
   format = '%(asctime)s - %(levelname)s - %(message)s',
   filename = 'logs.log', filemode = 'w'
 )
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)   # Here you are changing the level of your logger alone

正如@noufel13的回答中所述,显示额外日志消息的原因是您将根记录器的级别设置为DEBUG,并向其添加一个处理程序

默认情况下,导入
logging
将实例化一个
RootLogger
对象,该对象带有级别警告且未附加任何处理程序

导入
请求
会实例化一组库记录器,尤其是
urlib3.util.retry
urlib3.util
urlib3
urlib3.connection
urlib3.response
urlib3.connectionpool
urlib3.poolmanager
请求

这样做的目的是,使用这些库的开发人员可以轻松地启用调试输出来测试和排除代码故障,或者只需相应地配置根记录器,就可以在不修改第三方代码的情况下获得日志输出

所有这些记录器都是使用默认值创建的,相关级别为NOTSET、propagate True和disabled False

  • NOTSET(强调我的):
[…]当记录器为根记录器时,会处理所有消息;当记录器为非根记录器时,会将所有消息委派给父记录器

  • 正确:
[…]记录到此记录器的事件将传递给更高级别(祖先)记录器的处理程序[…]
构造函数将此属性设置为True

  • 禁用错误:
disabled是一种无证件的文件

在程序中导入
请求时,这些记录器始终存在。而且,它们总是发出日志消息。
默认情况下,这些消息不可见,因为所有这些记录器都只有一个附加的

此处理程序不执行任何操作。这是为了避免 “找不到记录器XXX的处理程序”一次性警告。这是 对于库代码很重要,其中可能包含用于记录事件的代码。如果用户 如果没有配置日志记录,则一次性警告可能为 产生;为了避免这种情况,库开发人员只需实例化 一个NullHandler,并将其添加到库模块或 包裹

。。。而且因为它们的最终祖先根记录器也没有任何处理程序,并且设置为每个默认值的警告级别

basicConfig
仅影响根记录器。按照您使用它的方式,将创建一个特定的
格式化程序
,并将其附加到新实例化的
文件处理程序
,该文件处理程序又附加到根记录器。此外,根记录器的级别设置为DEBUG

现在,来自
请求
urllib3
记录器的所有消息在遍历层次结构后都会到达根记录器,并被记录到根的
文件处理程序处理的文件中

如何阻止这种情况

按照您的原始配方,并按照@milanbalazs所述,继续为您的预期用途创建和配置专用记录器,而不使用根记录器。 您声明,您发现程序配置相当丑陋;我有点同意

该模块为您提供了多种配置日志的方法。
例如,您可以使用字典并通过字典提供配置,该字典可能会从另一个专用模块导入

以下配置名为test的记录器的方式与
basicConfig()
方法对根记录器的配置方式相同:

import logging.config

cfg_dict = {
    "version": 1,
    "formatters": {
        "default": {
            "format": '%(asctime)s - %(levelname)s - %(message)s',
        }
    },
    "handlers": {
        "file": {
            "class": "logging.FileHandler",
            "formatter": "default",
            "filename": "logs.log",
            "mode": "w",
        }
    },
    "loggers": {
        "test": {
            "level": "DEBUG",
            "handlers": ["file"],
        }
    }
}

logging.config.dictConfig(cfg_dict)
log = logging.getLogger("test")
logging.config
模块进一步支持通过和以适当格式配置dict和文件配置的配置数据的配置文件

如果您希望配置和使用根记录器,您可以禁用所有“不需要的”记录器或指示它们不要传播

import logging
import requests

for logger in logging.Logger.manager.loggerDict.values():
    logger.propagate = False
    # -- OR --
    logger.disabled = True

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='logs.log',
    filemode='w'
)

log = logging.getLogger()

注意:
Manager
loggerDict
Logger
禁用属性均未记录。虽然它们没有通过Python的约定明确标记为内部实现细节(即,前导下划线名称),我会毫不犹豫地把它们看作是官方的代码>日志记录< /COD> API,并期望它们成为可能改变的主题。

它们可能来自您在应用程序中使用的一些库。在我看来,您更改了日志的基本配置和“代码>请求/代码>模块也使用它,您得到了<代码>调试< /代码>。来自它的消息。如果您以
%(模块)s
%(文件名)s
的格式使用,您可能可以识别消息的位置。您使用什么模块来连接?@CristiFati I use
requests
module最近更新了我的问题,添加了