有人可以解释导入的库中记录行为的行为吗?该日志包含一个名为
trace_id
的所谓全局变量。
我有以下库:
my_library/
__init__.py
folder1/
__init_.py
helper.py
helper.py
看起来像:
import logging
logger = logging.getLogger(__name__)
def helper():
logger.info('LOG IN HELPER')
我的主程序,导入这个库,看起来像这样:
import logging
trace_id = 1
class CustomLogger(logging.Logger):
def _log(self, level, msg, args, exc_info=None, extra=None):
extra = {'trace_id': trace_id}
super(CustomLogger, self)._log(level, msg, args, exc_info, extra)
logger = logging.getLogger(__name__)
def config_logger():
helper_logger = logging.getLogger("folder1")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(trace_id)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
handler.setLevel(logging.INFO)
helper_logger.addHandler(handler)
helper_logger.setLevel(logging.INFO)
def program():
logger.info('main start')
# <--- SET LOGGER CLASS FIRST ---> #
logging.setLoggerClass(CustomLogger)
from folder1.helper import helper
config_logger()
helper()
global trace_id
trace_id += 1
helper()
logging.setLoggerClass(logging.Logger)
logger.info('main end')
我的
test_program.py
看起来像这样:
import logging
import program
logger = logging.getLogger(__name__)
class TestProgram:
def test_helper(self):
logger.info('LOG IN TEST')
program.program()
这是我的问题。如果我首先设置记录器类,
test_program
会以预期的输出运行:
-------------------------------- live log call ---------------------------------
INFO test_program:test_program.py:9 LOG IN TEST
INFO program:program.py:30 main start
2024-01-14 22:42:50,521 - folder1.helper - INFO - LOG IN HELPER - 1
INFO folder1.helper:helper.py:5 LOG IN HELPER
2024-01-14 22:42:50,522 - folder1.helper - INFO - LOG IN HELPER - 2
INFO folder1.helper:helper.py:5 LOG IN HELPER
INFO program:program.py:40 main end
但是,如果我先import,如下图:
...
logger.info('main start')
# <--- IMPORT FIRST ---> #
from folder1.helper import helper
logging.setLoggerClass(CustomLogger)
config_logger()
...
它给了我一个错误:
-------------------------------- live log call ---------------------------------
INFO test_program:test_program.py:9 LOG IN TEST
INFO program:program.py:30 main start
--- Logging error ---
Traceback (most recent call last):
File "/opt/bb/lib/python3.8/logging/__init__.py", line 435, in format
return self._format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 431, in _format
return self._fmt % record.__dict__
KeyError: 'trace_id'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/bb/lib/python3.8/logging/__init__.py", line 1084, in emit
msg = self.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 928, in format
return fmt.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 666, in format
s = self.formatMessage(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 635, in formatMessage
return self._style.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 437, in format
raise ValueError('Formatting field not found in record: %s' % e)
ValueError: Formatting field not found in record: 'trace_id'
Call stack:
File "/opt/bb/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/opt/bb/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/opt/bb/lib/python3.8/site-packages/pytest/__main__.py", line 5, in <module>
raise SystemExit(pytest.console_main())
File "/opt/bb/lib/python3.8/site-packages/_pytest/config/__init__.py", line 192, in console_main
code = main()
File "/opt/bb/lib/python3.8/site-packages/_pytest/config/__init__.py", line 169, in main
ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 318, in pytest_cmdline_main
return wrap_session(config, _main)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 271, in wrap_session
session.exitstatus = doit(config, session) or 0
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 325, in _main
config.hook.pytest_runtestloop(session=session)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 350, in pytest_runtestloop
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 114, in pytest_runtest_protocol
runtestprotocol(item, nextitem=nextitem)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 133, in runtestprotocol
reports.append(call_and_report(item, "call", log))
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 222, in call_and_report
call = call_runtest_hook(item, when, **kwds)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 261, in call_runtest_hook
return CallInfo.from_call(
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 341, in from_call
result: Optional[TResult] = func()
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 262, in <lambda>
lambda: ihook(item=item, **kwds), when=when, reraise=reraise
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 169, in pytest_runtest_call
item.runtest()
File "/opt/bb/lib/python3.8/site-packages/_pytest/python.py", line 1792, in runtest
self.ihook.pytest_pyfunc_call(pyfuncitem=self)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/python.py", line 194, in pytest_pyfunc_call
result = testfunction(**testargs)
File "/mnt/c/playground/tests/test_program.py", line 10, in test_helper
program.program()
File "/mnt/c/playground/program.py", line 35, in program
helper()
File "/mnt/c/my_library/folder1/helper.py", line 5, in helper
logger.info('LOG IN HELPER')
Message: 'LOG IN HELPER'
Arguments: ()
self_logger class is <class 'logging.Logger'>
INFO folder1.helper:helper.py:5 LOG IN HELPER
--- Logging error ---
Traceback (most recent call last):
File "/opt/bb/lib/python3.8/logging/__init__.py", line 435, in format
return self._format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 431, in _format
return self._fmt % record.__dict__
KeyError: 'trace_id'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/bb/lib/python3.8/logging/__init__.py", line 1084, in emit
msg = self.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 928, in format
return fmt.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 666, in format
s = self.formatMessage(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 635, in formatMessage
return self._style.format(record)
File "/opt/bb/lib/python3.8/logging/__init__.py", line 437, in format
raise ValueError('Formatting field not found in record: %s' % e)
ValueError: Formatting field not found in record: 'trace_id'
Call stack:
File "/opt/bb/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/opt/bb/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/opt/bb/lib/python3.8/site-packages/pytest/__main__.py", line 5, in <module>
raise SystemExit(pytest.console_main())
File "/opt/bb/lib/python3.8/site-packages/_pytest/config/__init__.py", line 192, in console_main
code = main()
File "/opt/bb/lib/python3.8/site-packages/_pytest/config/__init__.py", line 169, in main
ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 318, in pytest_cmdline_main
return wrap_session(config, _main)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 271, in wrap_session
session.exitstatus = doit(config, session) or 0
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 325, in _main
config.hook.pytest_runtestloop(session=session)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/main.py", line 350, in pytest_runtestloop
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 114, in pytest_runtest_protocol
runtestprotocol(item, nextitem=nextitem)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 133, in runtestprotocol
reports.append(call_and_report(item, "call", log))
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 222, in call_and_report
call = call_runtest_hook(item, when, **kwds)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 261, in call_runtest_hook
return CallInfo.from_call(
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 341, in from_call
result: Optional[TResult] = func()
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 262, in <lambda>
lambda: ihook(item=item, **kwds), when=when, reraise=reraise
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/runner.py", line 169, in pytest_runtest_call
item.runtest()
File "/opt/bb/lib/python3.8/site-packages/_pytest/python.py", line 1792, in runtest
self.ihook.pytest_pyfunc_call(pyfuncitem=self)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_hooks.py", line 493, in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_manager.py", line 115, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File "/opt/bb/lib/python3.8/site-packages/pluggy/_callers.py", line 77, in _multicall
res = hook_impl.function(*args)
File "/opt/bb/lib/python3.8/site-packages/_pytest/python.py", line 194, in pytest_pyfunc_call
result = testfunction(**testargs)
File "/mnt/c/playground/tests/test_program.py", line 10, in test_helper
program.program()
File "/mnt/c/playground/program.py", line 38, in program
helper()
File "/mnt/c/my_library/folder1/helper.py", line 5, in helper
logger.info('LOG IN HELPER')
Message: 'LOG IN HELPER'
Arguments: ()
INFO folder1.helper:helper.py:5 LOG IN HELPER
INFO program:program.py:40 main end
我不确定我的知识差距是否在于Python日志模块、Python全局变量、导入库,还是以上所有。任何帮助将不胜感激。
setLoggerClass
设置未来 getLogger
调用使用的类。如果在设置自定义类之前导入 helper.py
,则其模块级别 getLogger
会获取默认的 Logger
类,而不是 CustomLogger
,因此没有 trace_id
。您的格式化程序假设 trace_id
存在,并且对于设置自定义类之前获取的记录器将失败。
显而易见的解决方案是确保您的脚本在导入之前设置其自定义记录器,就像您的第一个示例一样。但这并没有涵盖所有基础。假设其他代码决定需要不同的记录器并直接实例化它。
另一个解决方案是在创建格式化程序时添加默认值
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(trace_id)s',
defaults={"trace_id":trace_id})
如果您想要更多地控制输出,您可以创建自己的自定义格式化程序。