在Python中使用funcName进行日志记录会影响性能吗?

0 投票
2 回答
1084 浏览
提问于 2025-04-17 06:59

我刚刚在看Python的日志文档,发现了一个叫funcName的参数,它在日志格式化的时候会用到。

这个功能看起来很方便,能清楚地看到日志是从哪里来的,但有人提出了一个担忧,可能是因为它需要生成一个堆栈跟踪,这样会影响性能。

我猜它可能使用了类似sys._getframe()的东西,而不是inspect模块,因为后者会对性能有影响。

那么,funcName这个功能在生产环境中可以用吗,还是说我们应该避免使用它呢?

2 个回答

1

这里有一个测试应用,它展示了在我的本地机器上,写入文件名和行号到一个文件大约需要1秒钟来处理500000个请求。

#!/usr/bin/env python

import traceback, sys, time

def writeinfo(f, on=True):

    # give the function something to do
    s=sum(range(1000))

    if on:
        fr = sys._getframe(1)
        s = "%s (line %s) " % (fr.f_code.co_filename, fr.f_lineno)
        f.write(s)

cnt = 50000

t1 = time.time()

f = open('tempfile.log','w')

for i in range(cnt):
    writeinfo(f)

f.close()

t2 = time.time()

for i in range(cnt):
    writeinfo(f, on=False)

t3 = time.time()

print "Test time with    file write: %s" % (t2-t1) 
print "Test time without file write: %s" % (t3-t2) 

结果:

Test time with    file write: 1.17307782173
Test time without file write: 1.08166718483
4

别急着猜,Python自带的日志记录功能的源代码你是可以找到的。

它是怎么找到函数名字的(在logging/__init__.py文件里):

#
# _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)

# next bit filched from 1.5.2's inspect.py
def currentframe():
    """Return the frame object for the caller's stack frame."""
    try:
        raise Exception
    except:
        return sys.exc_info()[2].tb_frame.f_back

if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
# done filching

然后后面会有:

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 = 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 = (filename, f.f_lineno, co.co_name)
        break
    return rv

另外,也不用担心性能问题:它会在判断你是否需要这个功能之前就找到函数名字,所以你可以放心使用。

撰写回答