我想将Python logger封装在一个自定义类中,以嵌入一些特定于应用程序的功能,并向开发人员隐藏设置细节(设置文件输出、日志级别等)。为此,我使用以下API创建了一个类:
__init__(log_level, filename)
debug(msg)
info(msg)
warning(msg)
error(msg)
logger.debug/info/warning/etc调用通常在日志中写入进行日志调用的函数和行号。但是,使用我的自定义类,写入日志文件的函数和行号总是相同的(对应于自定义类中的debug()/info()/警告()/错误()函数)。我想让它保存记录msg的应用程序代码行。那有可能吗?
提前谢谢。
是:sys_getframe(NUM)
其中NUM表示当前函数之外的函数数量。返回的帧对象具有f_lineno
和f_code等属性。co_文件名
。
http://docs.python.org/library/sys.html#sys._getframe
基于威尔·威尔的回答。另一个选项是覆盖findCaller
方法并使用自定义类作为默认记录器:
class MyLogger(logging.Logger):
"""
Needs to produce correct line numbers
"""
def findCaller(self):
n_frames_upper = 2
f = logging.currentframe()
for _ in range(2 + n_frames_upper): # <-- correct frame
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == logging._srcfile:
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
logging.setLoggerClass(MyLogger)
logger = logging.getLogger('MyLogger') # init MyLogger
logging.setLoggerClass(logging.Logger) # reset logger class to default
如果您愿意重新实现一点标准日志模块,就可以生成日志包装器。诀窍是编写自己的findCaller()方法,该方法知道在解释回溯跟踪时如何忽略日志包装器源文件。
在logwrapper中。py:
import logging
import os
import sys
from logging import *
# This code is mainly copied from the python logging module, with minor modifications
# _srcfile is used when walking the stack to check when we've got the first
# caller stack frame.
#
if hasattr(sys, 'frozen'): #support for py2exe
_srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])
elif __file__[-4:].lower() in ['.pyc', '.pyo']:
_srcfile = __file__[:-4] + '.py'
else:
_srcfile = __file__
_srcfile = os.path.normcase(_srcfile)
class LogWrapper(object):
def __init__(self, logger):
self.logger = logger
def debug(self, msg, *args, **kwargs):
"""
Log 'msg % args' with severity 'DEBUG'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
"""
if self.logger.isEnabledFor(DEBUG):
self._log(DEBUG, msg, args, **kwargs)
def info(self, msg, *args, **kwargs):
"""
Log 'msg % args' with severity 'INFO'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
"""
if self.logger.isEnabledFor(INFO):
self._log(INFO, msg, args, **kwargs)
# Add other convenience methods
def log(self, level, msg, *args, **kwargs):
"""
Log 'msg % args' with the integer severity 'level'.
To pass exception information, use the keyword argument exc_info with
a true value, e.g.
logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
"""
if not isinstance(level, int):
if logging.raiseExceptions:
raise TypeError("level must be an integer")
else:
return
if self.logger.isEnabledFor(level):
self._log(level, msg, args, **kwargs)
def _log(self, level, msg, args, exc_info=None, extra=None):
"""
Low-level logging routine which creates a LogRecord and then calls
all the handlers of this logger to handle the record.
"""
# Add wrapping functionality here.
if _srcfile:
#IronPython doesn't track Python frames, so findCaller throws an
#exception on some versions of IronPython. We trap it here so that
#IronPython can use logging.
try:
fn, lno, func = self.findCaller()
except ValueError:
fn, lno, func = "(unknown file)", 0, "(unknown function)"
else:
fn, lno, func = "(unknown file)", 0, "(unknown function)"
if exc_info:
if not isinstance(exc_info, tuple):
exc_info = sys.exc_info()
record = self.logger.makeRecord(
self.logger.name, level, fn, lno, msg, args, exc_info, func, extra)
self.logger.handle(record)
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
f = logging.currentframe()
#On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == _srcfile:
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
还有一个使用它的例子:
import logging
from logwrapper import LogWrapper
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(filename)s(%(lineno)d): "
"%(message)s")
logger = logging.getLogger()
lw = LogWrapper(logger)
lw.info('Wrapped well, this is interesting')
看过本章第一节的同学应该还记得,log_by_lua* 是一个请求经历的最后阶段。由于记日志跟应答内容无关,Nginx 通常在结束请求之后才更新访问日志。由此可见,如果我们有日志输出的情况,最好统一到 log_by_lua* 阶段。如果我们把记日志的操作放在 content_by_lua* 阶段,那么将线性的增加请求处理时间。 在公司某个定制化项目中,Nginx 上的日志内容都要输送到 syslo
将PostSharp用于C#应用程序,我有以下场景: Namespace_ACustomLoggingMethod Namespace_B.DoThings thingMethod(实际上是几种不同的方法) DoMomthingMethod调用CustomLoggingMethod,它以所需的格式创建日志条目并且运行良好。正如预期的那样,日志条目将源记录为CustomLoggingMethod,我
使用JBOSS 6.2 EAP作为应用服务器开发web应用程序。正在尝试自定义日志记录。要为指定位置的不同模块创建不同的日志。 做了一些家庭作业并尝试添加 在standalone的profile部分中。xml 并在同一文件中添加了记录器 此外,无法找到log4j。jboss文件夹中的xml。刚接触JBoss的人,猜一下遗漏了什么或走错了方向。有人能帮忙吗。
问题内容: 我对jdk日志记录配置有疑问。我有一个使用JDK Logging输出消息的EJB(已部署到glassfish中)。因此,我使用具有以下代码的命名记录器: 我知道可以通过将以下行添加到Glassfish的logging.properties文件中来为记录器配置日志级别: 但是,如何为记录器指定输出文件?我想将来自名为“ org.imixs.workflow”的记录器的所有消息放入单独的文
目前在spring Boot1.3中,我们只能将访问日志记录到文件系统中的一个文件。有没有办法实际使用自定义记录器(像log4j2)来记录访问日志? 我目前正在使用undertow和spring boot,但是在检查spring boot源代码之后,undertow记录器是用DefaultAccessLogReceiver初始化的,它正在写入文件。如果可能的话,我希望使用AccessLogHand
我在为Oracle SOA套件开发自定义log4j2记录器方面处于中间位置。类是一个胖的或自包含的罐子。它有一个log4j2.xml配置文件,其中有一个记录器和附加器 null 运行JUnit测试时,记录器会按预期写入jsonLogger.json文件。 在我的weblogic服务器上,我部署了log4j2.xml配置文件,并将Java属性log4j.configurationfile设置到log