import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'detailed',
},
},
'root': {
'handlers': ['console'],
'level': 'INFO',
},
}
logging.config.dictConfig(LOGGING_CONFIG)
# 配置日志
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# 创建控制台处理程序
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 创建滚动文件处理程序,每达到10M就滚动
# file_handler = RotatingFileHandler('my_log.log', maxBytes=10*1024*1024, backupCount=5)
# 确保日志目录存在
log_directory = '/log/'
if not os.path.exists(log_directory):
os.makedirs(log_directory)
# 创建按日期滚动的文件处理程序,每天生成新文件
date_file_handler = TimedRotatingFileHandler(os.path.join(log_directory, 'vncproject.log'), when='midnight', interval=1,
backupCount=5)
# 配置日志格式
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s')
console_handler.setFormatter(formatter)
# file_handler.setFormatter(formatter)
date_file_handler.setFormatter(formatter)
# 将处理程序添加到日志记录器
logger.addHandler(console_handler)
# logger.addHandler(file_handler)
logger.addHandler(date_file_handler)
# 记录日志
logger.info('This is an info message')
控制台上输出了两遍我项目的日志
在你的日志配置中,你添加了一个控制台处理程序 (console_handler
) 和一个按日期滚动的文件处理程序 (date_file_handler
)。因此,每个日志记录器 (logger
) 都会通过这两个处理程序进行处理,导致在控制台上和日志文件中都输出了相同的日志。
如果你希望控制台只输出一份日志,你可以在日志记录器 (logger
) 上添加一个处理程序,并设置不同的日志级别。例如,你可以设置控制台处理程序的级别为 DEBUG
,而文件处理程序的级别为 INFO
。这样,控制台处理程序将输出所有级别的日志,而文件处理程序只会输出 INFO
及以上级别的日志。
修改你的代码如下:
import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG', # 设置控制台处理程序的级别为 DEBUG
'formatter': 'detailed',
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join('/log/', 'vncproject.log'),
'when': 'midnight',
'interval': 1,
'backupCount': 5,
'level': 'INFO', # 设置文件处理程序的级别为 INFO
'formatter': 'detailed',
},
},
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
}
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
logger.info('This is an info message')
这样配置后,控制台上只会输出 DEBUG
及以上级别的日志,而文件中会输出 INFO
及以上级别的日志。
我想文件输出的只在文件,控制台只输出控制台自己的
你可以通过设置不同的日志记录器来实现这一点。以下是相应的修改:
import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'detailed',
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join('/log/', 'vncproject.log'),
'when': 'midnight',
'interval': 1,
'backupCount': 5,
'level': 'INFO',
'formatter': 'detailed',
},
},
'loggers': {
'console_logger': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False, # 防止日志传递给 root logger
},
'file_logger': {
'handlers': ['file'],
'level': 'INFO',
'propagate': False, # 防止日志传递给 root logger
},
},
'root': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
},
}
logging.config.dictConfig(LOGGING_CONFIG)
console_logger = logging.getLogger('console_logger')
file_logger = logging.getLogger('file_logger')
console_logger.info('This is an info message for console')
file_logger.info('This is an info message for file')
这样配置后,console_logger
只会将日志输出到控制台,而 file_logger
只会将日志输出到文件。
我还想过滤掉所有第三方工具库的除了error级别的任何日志
可以通过在相应的 logger 上设置级别来实现。以下是修改后的配置:
import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'detailed',
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join('/log/', 'vncproject.log'),
'when': 'midnight',
'interval': 1,
'backupCount': 5,
'level': 'INFO',
'formatter': 'detailed',
},
},
'loggers': {
'console_logger': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False, # 防止日志传递给 root logger
},
'file_logger': {
'handlers': ['file'],
'level': 'INFO',
'propagate': False, # 防止日志传递给 root logger
},
'twisted': { # twisted 的 logger
'handlers': ['file'],
'level': 'ERROR', # 设置级别为 ERROR
'propagate': False,
},
},
'root': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
},
}
logging.config.dictConfig(LOGGING_CONFIG)
console_logger = logging.getLogger('console_logger')
file_logger = logging.getLogger('file_logger')
console_logger.info('This is an info message for console')
file_logger.info('This is an info message for file')
# twisted 会被过滤掉,不会输出到 file_logger
logger_twisted = logging.getLogger('twisted')
logger_twisted.info('This is an info message for twisted') # 不会输出
logger_twisted.error('This is an error message for twisted') # 会输出
在这个例子中,我为 twisted 设置了级别为 ERROR,这样 INFO 级别的日志就会被过滤掉。其他的 logger(比如 console_logger
和 file_logger
)仍然按照原有的级别进行输出。
是任何第三方工具库,除了error级别外,在控台和文本都不要输出
如果你想过滤掉所有第三方工具库的非 ERROR 级别的日志,可以使用一个自定义的过滤器。以下是一种可能的实现:
import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
class NoThirdPartyInfoFilter(logging.Filter):
def filter(self, record):
# 如果是第三方模块的日志且级别为 INFO,则过滤掉
return not (record.name.startswith('your_project') or record.levelno == logging.INFO)
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'detailed',
'filters': ['no_third_party_info'],
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join('/log/', 'vncproject.log'),
'when': 'midnight',
'interval': 1,
'backupCount': 5,
'level': 'INFO',
'formatter': 'detailed',
'filters': ['no_third_party_info'],
},
},
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
'filters': {
'no_third_party_info': {
'()': NoThirdPartyInfoFilter,
},
},
}
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
logger.info('This is an info message for both console and file')
在这个例子中,NoThirdPartyInfoFilter
类继承自 logging.Filter
,它的 filter
方法控制是否允许特定的记录通过。在这里,我在过滤器中判断了日志记录的名称,如果是你的项目的日志或者是 ERROR 级别的日志,就允许通过,否则过滤掉。过滤器的名称 'no_third_party_info'
在 handlers
部分和 filters
部分都要配置。
PIL.PngImagePlugin 还是包含了这部分,这些也不是我要的
如果你想要过滤掉特定模块的日志,可以使用 logging.Logger
对象的 propagate
属性。这个属性控制日志消息是否传播给父级 logger。通过设置 propagate
为 False
,你可以阻止消息传播到父级 logger。
以下是如何修改配置来过滤掉 PIL.PngImagePlugin
模块的日志的例子:
import os
import logging.config
from logging.handlers import TimedRotatingFileHandler
class NoThirdPartyInfoFilter(logging.Filter):
def filter(self, record):
# 如果是第三方模块的日志且级别为 INFO,则过滤掉
return not (record.name.startswith('your_project') or record.levelno == logging.INFO)
LOGGING_CONFIG = {
'version': 1,
'formatters': {
'detailed': {
'class': 'logging.Formatter',
'format': '%(asctime)s [%(levelname)s] %(name)s.%(funcName)s:%(lineno)d - %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'detailed',
'filters': ['no_third_party_info'],
},
'file': {
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join('/log/', 'vncproject.log'),
'when': 'midnight',
'interval': 1,
'backupCount': 5,
'level': 'INFO',
'formatter': 'detailed',
'filters': ['no_third_party_info'],
},
},
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
'PIL.PngImagePlugin': {
'handlers': ['file'],
'level': 'ERROR',
'propagate': False, # 阻止消息传播到根 logger
},
},
'filters': {
'no_third_party_info': {
'()': NoThirdPartyInfoFilter,
},
},
}
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger(__name__)
logger.info('This is an info message for both console and file')
在这个例子中,我在 loggers
部分添加了一个针对 PIL.PngImagePlugin
模块的配置,将 propagate
设置为 False
。这样,该模块的日志就不会传播到根 logger。你可以根据需要添加其他模块的配置。