Как я могу регистрировать текущую строку и информацию о стеке с помощью Python?

У меня есть функция регистрации следующим образом.

logging.basicConfig(
    filename = fileName,
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def printinfo(string):
    if DEBUG:
        logging.info(string)

def printerror(string):
    if DEBUG:
        logging.error(string)
    print string

Мне нужно ввести номер строки, информацию о стеке. Например:

1: def hello():
2:    goodbye()
3:
4: def goodbye():
5:    printinfo()

---> Line 5: goodbye()/hello()

Как я могу сделать это с помощью Python?

решаемые

def printinfo(string):
    if DEBUG:
        frame = inspect.currentframe()
        stack_trace = traceback.format_stack(frame)
        logging.debug(stack_trace[:-1])
    if LOG:
        logging.info(string)

дает мне эту информацию, которая именно то, что мне нужно.

DEBUG      2011-02-23 10:09:13,500 [
  '  File "/abc.py", line 553, in <module>\n    runUnitTest(COVERAGE, PROFILE)\n', 
  '  File "/abc.py", line 411, in runUnitTest\n    printinfo(string)\n']

Ответы

Ответ 1

Текущее имя функции, модуль и номер строки, которую вы можете сделать, просто изменив строку формата, чтобы включить их.

logging.basicConfig(
    filename = fileName,
    format = "%(levelname) -10s %(asctime)s %(module)s:%(lineno)s %(funcName)s %(message)s",
    level = logging.DEBUG
)

Большинство людей хотят только стек при регистрации исключения, а модуль журнала делает это автоматически, если вы вызываете logging.exception(). Если вам действительно нужна информация о стеке в другое время, вам нужно будет использовать модуль трассировки для извлечения дополнительной информации, которая вам нужна.

Ответ 2

import inspect
import traceback

def method():
   frame = inspect.currentframe()
   stack_trace = traceback.format_stack(frame)
   print ''.join(stack_trace)

Используйте stack_trace [: - 1], чтобы избежать включения метода /printinfo в трассировку стека.

Ответ 3

Как и в случае с Python 3.2, это можно упростить, передав флаг stack_info=True в протоколирование вызовов. Однако для любой более ранней версии вам понадобится один из вышеперечисленных ответов.

Ответ 4

Поздний ответ, но хорошо.

Другое решение состоит в том, что вы можете создать свой собственный форматировщик с фильтром, как указано в документах здесь. Это действительно замечательная функция, так как теперь вам больше не нужно использовать вспомогательную функцию (и вам нужно помещать вспомогательную функцию везде, где вы хотите трассировку стека). Вместо этого пользовательский отформатированный реализует его непосредственно в самих журналах.

import logging
class ContextFilter(logging.Filter):
    def __init__(self, trim_amount)
        self.trim_amount = trim_amount
    def filter(self, record):
        import traceback
        record.stack = ''.join(
            str(row) for row in traceback.format_stack()[:-self.trim_amount]
        )
        return True

# Now you can create the logger and apply the filter.
logger = logging.getLogger(__name__)
logger.addFilter(ContextFilter(5))

# And then you can directly implement a stack trace in the formatter.    
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s \n %(stack)s')

Примечание. В приведенном выше коде я обрезаю последние 5 кадров стека. Это просто для удобства и чтобы мы не отображали фреймы стека из самого пакета протоколов python (его также можно было бы скорректировать для разных версий пакета регистрации)

Ответ 5

Вот пример, который я надеюсь, что он может вам помочь:

import inspect
import logging

logging.basicConfig(
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def test():

    caller_list = []
    frame = inspect.currentframe()
    this_frame = frame  # Save current frame.

    while frame.f_back:
        caller_list.append('{0}()'.format(frame.f_code.co_name))
        frame = frame.f_back

    caller_line = this_frame.f_back.f_lineno
    callers =  '/'.join(reversed(caller_list))

    logging.info('Line {0} : {1}'.format(caller_line, callers))

def foo():
    test()

def bar():
    foo()

bar()

Результат:

INFO       2011-02-23 17:03:26,426 Line 28 : bar()/foo()/test()

Ответ 6

Используйте модуль traceback.

logging.error(traceback.format_exc())

Ответ 7

Посмотрите на модуль трассировки

>>> import traceback
>>> def test():
>>>     print "/".join( str(x[2]) for x in traceback.extract_stack() )
>>> def main():
>>>     test()
>>> main()
<module>/launch_new_instance/mainloop/mainloop/interact/push/runsource/runcode/<module>/main/test