为什么日志记录在一次调用中起作用,而不是从 main 函数中起作用?
Why logging works in a single call but not from main function?
我有一个名为 setup_logger()
的函数可以为我的应用程序设置日志系统,它位于 controllers.py
文件中。
它工作得很好。但有时当我 运行 来自 main.py
的函数时,日志记录没有被调用(我对某些函数使用 asyncio
)。
当我调用我的函数 get_browser()
本身时,logging
工作并将消息发送到 StreamHandler
和 FileHandler
,因为它应该这样做。
但是当我从我的文件 main.py
中调用相同的函数 get_browser()
时,日志记录没有做任何事情。
我想知道是什么阻止了调用日志记录功能,如果是 asyncio
或其他原因。
我的回购:https://github.com/guimatheus92/Bot_BombCrypto
我的项目:
└── Project
├── main.py # setup our app
├── controllers.py # this file contains setup_logger() and get_browser()
get_browser()
函数:
def get_browser():
logger = setup_logger(telegram_integration=True)
logger.info("Profiles selected: ...")
applications = []
website_browser = []
return applications, website_browser
setup_logger()
函数:
def setup_logger(telegram_integration=False, bot_name=''):
if bot_name != '':
formatter = logging.Formatter('%(levelname)s | Function: %(funcName)s | %(asctime)s: Bot (' + str(bot_name) + '): %(message)s', datefmt='%m/%d/%Y %H:%M:%S')
else:
formatter = logging.Formatter('%(levelname)s | Function: %(funcName)s | %(asctime)s: %(message)s', datefmt='%m/%d/%Y %H:%M:%S')
level = logging.INFO
consolehandler = logging.StreamHandler(sys.stdout)
consolehandler.setFormatter(formatter)
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
else:
logger.setLevel(level)
logger.addHandler(consolehandler)
return logger
在 main.py
我刚打电话:
applications, website_browser = get_browser()
async def main():
logger = setup_logger(telegram_integration=True)
logger.info('------------------- New Execution ----------------\n')
logger.info('Starting Bot..... Bot started!')
applications, website_browser = get_browser()
logger.info('Number of accounts that the bot will run: %s' % (len(applications)))
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()
except Exception as e:
print("Exception: " + str(e))
exit()
main()
调用 setup_logger()
两次:
main()
→setup_logger()
main()
→get_browser()
→setup_logger()
setup_logger
删除所有已配置的处理程序,仅在未配置的情况下进行配置:
def setup_logger(telegram_integration=False, bot_name=''):
# Prepare handlers
# ...
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
else:
logger.setLevel(level)
logger.addHandler(consolehandler)
解决方案
将配置移出 else
块:
def setup_logger(telegram_integration=False, bot_name=''):
# Prepare handlers
# ...
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
logger.setLevel(level)
logger.addHandler(consolehandler)
理想情况下,日志记录工具应该只配置一次,除非您无法承受应用程序的冷重载。
您是否考虑过使用标准 logging.config.dictConfig
而不是所有 setup_logger
?只需使用您需要的任何参数化动态制作字典配置,并发出配置一次,甚至在启动事件循环之前。稍后,直接使用 logging.getLogger
获取配置的记录器
我认为这会帮助您组织代码。
class TelegramHandler(logging.Handler):
def __init__(self, bot_name=''):
super().__init__()
self.bot_name = bot_name
def emit(self, record):
message = self.format(record)
send_telegram_msg(message, self.bot_name)
def get_logging_cfg(telegram_integration=False, bot_name=''):
return {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format':
'%(levelname)s | Function: %(funcName)s | %(asctime)s: Bot (' + str(bot_name) + '): %(message)s'
if bot_name else
'%(levelname)s | Function: %(funcName)s | %(asctime)s: %(message)s',
'datefmt': '%m/%d/%Y %H:%M:%S',
},
},
'handlers': {
'file': {
'formatter': 'default',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join(pathlib.Path(__file__).parent.resolve(), 'logs', 'myapp.log'),
'when': 'D',
},
'telegram': {
'formatter': 'default',
'class': 'import.path.to.you.module.TelegramHandler',
'bot_name': bot_name,
},
'null': {
'formatter': 'default',
'class': 'logging.handlers.NullHandler',
}
},
'loggers': {
'logs': {
'handlers':
(['file'] if create_logfiles else [])
+ (['telegram'] if telegram_integration and telegram_token else [])
}
},
'root': {
# consider something else, for the sake of the logging happening beyond your own code
'handlers': ['null'],
'level': 'INFO',
},
}
async def main():
logger = logging.getLogger('logs')
logger.info('start')
applications, website_browser = get_browser()
# ...
def get_browser():
logger = logging.getLogger('logs')
logger.info('whatever')
# ...
if __name__ == "__main__":
logging.config.dictConfig(
get_logging_cfg(
telegram_integration=True,
bot_name='foo',
)
)
loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()
奖励:使用 TimedRotatingFileHandler 而不是所有手动路径制作。
Python 的 logging 是一个美丽的图书馆,如果你阅读它 docs thoroughly
你会更开心
我有一个名为 setup_logger()
的函数可以为我的应用程序设置日志系统,它位于 controllers.py
文件中。
它工作得很好。但有时当我 运行 来自 main.py
的函数时,日志记录没有被调用(我对某些函数使用 asyncio
)。
当我调用我的函数 get_browser()
本身时,logging
工作并将消息发送到 StreamHandler
和 FileHandler
,因为它应该这样做。
但是当我从我的文件 main.py
中调用相同的函数 get_browser()
时,日志记录没有做任何事情。
我想知道是什么阻止了调用日志记录功能,如果是 asyncio
或其他原因。
我的回购:https://github.com/guimatheus92/Bot_BombCrypto
我的项目:
└── Project
├── main.py # setup our app
├── controllers.py # this file contains setup_logger() and get_browser()
get_browser()
函数:
def get_browser():
logger = setup_logger(telegram_integration=True)
logger.info("Profiles selected: ...")
applications = []
website_browser = []
return applications, website_browser
setup_logger()
函数:
def setup_logger(telegram_integration=False, bot_name=''):
if bot_name != '':
formatter = logging.Formatter('%(levelname)s | Function: %(funcName)s | %(asctime)s: Bot (' + str(bot_name) + '): %(message)s', datefmt='%m/%d/%Y %H:%M:%S')
else:
formatter = logging.Formatter('%(levelname)s | Function: %(funcName)s | %(asctime)s: %(message)s', datefmt='%m/%d/%Y %H:%M:%S')
level = logging.INFO
consolehandler = logging.StreamHandler(sys.stdout)
consolehandler.setFormatter(formatter)
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
else:
logger.setLevel(level)
logger.addHandler(consolehandler)
return logger
在 main.py
我刚打电话:
applications, website_browser = get_browser()
async def main():
logger = setup_logger(telegram_integration=True)
logger.info('------------------- New Execution ----------------\n')
logger.info('Starting Bot..... Bot started!')
applications, website_browser = get_browser()
logger.info('Number of accounts that the bot will run: %s' % (len(applications)))
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()
except Exception as e:
print("Exception: " + str(e))
exit()
main()
调用setup_logger()
两次:main()
→setup_logger()
main()
→get_browser()
→setup_logger()
setup_logger
删除所有已配置的处理程序,仅在未配置的情况下进行配置:
def setup_logger(telegram_integration=False, bot_name=''):
# Prepare handlers
# ...
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
else:
logger.setLevel(level)
logger.addHandler(consolehandler)
解决方案
将配置移出 else
块:
def setup_logger(telegram_integration=False, bot_name=''):
# Prepare handlers
# ...
logger = logging.getLogger('logs')
if logger.hasHandlers():
# Logger is already configured, remove all handlers
logger.handlers = []
logger.setLevel(level)
logger.addHandler(consolehandler)
理想情况下,日志记录工具应该只配置一次,除非您无法承受应用程序的冷重载。
您是否考虑过使用标准 logging.config.dictConfig
而不是所有 setup_logger
?只需使用您需要的任何参数化动态制作字典配置,并发出配置一次,甚至在启动事件循环之前。稍后,直接使用 logging.getLogger
我认为这会帮助您组织代码。
class TelegramHandler(logging.Handler):
def __init__(self, bot_name=''):
super().__init__()
self.bot_name = bot_name
def emit(self, record):
message = self.format(record)
send_telegram_msg(message, self.bot_name)
def get_logging_cfg(telegram_integration=False, bot_name=''):
return {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format':
'%(levelname)s | Function: %(funcName)s | %(asctime)s: Bot (' + str(bot_name) + '): %(message)s'
if bot_name else
'%(levelname)s | Function: %(funcName)s | %(asctime)s: %(message)s',
'datefmt': '%m/%d/%Y %H:%M:%S',
},
},
'handlers': {
'file': {
'formatter': 'default',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join(pathlib.Path(__file__).parent.resolve(), 'logs', 'myapp.log'),
'when': 'D',
},
'telegram': {
'formatter': 'default',
'class': 'import.path.to.you.module.TelegramHandler',
'bot_name': bot_name,
},
'null': {
'formatter': 'default',
'class': 'logging.handlers.NullHandler',
}
},
'loggers': {
'logs': {
'handlers':
(['file'] if create_logfiles else [])
+ (['telegram'] if telegram_integration and telegram_token else [])
}
},
'root': {
# consider something else, for the sake of the logging happening beyond your own code
'handlers': ['null'],
'level': 'INFO',
},
}
async def main():
logger = logging.getLogger('logs')
logger.info('start')
applications, website_browser = get_browser()
# ...
def get_browser():
logger = logging.getLogger('logs')
logger.info('whatever')
# ...
if __name__ == "__main__":
logging.config.dictConfig(
get_logging_cfg(
telegram_integration=True,
bot_name='foo',
)
)
loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_forever()
奖励:使用 TimedRotatingFileHandler 而不是所有手动路径制作。
Python 的 logging 是一个美丽的图书馆,如果你阅读它 docs thoroughly
你会更开心