2012-06-11 48 views
65

我想了解一個應用程序的工作原理。爲此,我將調試命令作爲每個函數正文的第一行插入,其目的是記錄函數的名稱以及將消息發送到日誌輸出的行號(代碼內)。最後,由於此應用程序包含許多文件,因此我想創建一個日誌文件,以便我可以更好地瞭解應用程序的控制流。Python日誌記錄(函數名稱,文件名,行號)使用單個文件

這是我所知道的:

用於獲取函數名
  1. ,我可以使用function_name.__name__,但我不希望使用的函數名(這樣我就可以迅速複製和粘貼在一個通用的Log.info("Message")所有功能的主體)。我知道這可以用C使用__func__宏來完成,但我不確定python。

  2. 用於獲取文件名和行號,我已經看到了(我相信)我的應用程序使用Python locals()功能,但在我沒有完全意識到例如語法:options = "LOG.debug('%(flag)s : %(flag_get)s' % locals()),我嘗試了使用像LOG.info("My message %s" % locals())它產生類似{'self': <__main__.Class_name object at 0x22f8cd0>}。對此有任何意見?

  3. 我知道如何使用日誌記錄並添加處理程序來記錄到文件,但我不確定是否可以使用單個文件以正確的順序記錄項目中的函數調用。

我將不勝感激任何幫助。

謝謝!

+0

你可以通過使用'import pdb; pdb.set_trace()',然後以交互方式遍歷代碼。這可能會幫助您追蹤程序流程。 –

+0

好主意!謝謝馬特。如問題中提到的那樣獲取日誌仍然有幫助,這樣我就不必每次都進行調試。另外,你是否知道一個用於python的IDE,它和Eclipse for Java一樣好(ctrl + click會帶你到函數定義),我可以利用它來使調試更容易? – user1126425

回答

17

這裏有幾個勉強相關的問題。 (3)。我將從最簡單的開始:(3)。使用logging,您可以將所有調用聚合到單個日誌文件或其他輸出目標:它們將按照它們在過程中發生的順序進行。

接下來:(2)。 locals()提供了當前範圍的字典。因此,在沒有其他參數的方法中,您的作用域中包含self,其中包含對當前實例的引用。正在使用的訣竅是使用字典作爲%運算符的RHS的字符串格式。 "%(foo)s" % bar將被替換爲bar["foo"]的值。

最後,你可以使用一些內省技巧,類似於那些pdb使用的可以登錄詳細信息:

def autolog(message): 
    "Automatically log the current function details." 
    import inspect, logging 
    # Get the previous frame in the stack, otherwise it would 
    # be this function!!! 
    func = inspect.currentframe().f_back.f_code 
    # Dump the message + the name of this function to the log. 
    logging.debug("%s: %s in %s:%i" % (
     message, 
     func.co_name, 
     func.co_filename, 
     func.co_firstlineno 
    )) 

這將記錄傳入的消息,再加上(原件)函數名,文件名在其中出現該定義以及該文件中的行。有關詳細信息,請參閱inspect - Inspect live objects

正如我在前面的評論中提到的那樣,您也可以隨時插入import pdb; pdb.set_trace()行並重新運行程序,以便隨時插入pdb交互式調試提示符。這使您能夠瀏覽代碼,根據您的選擇檢查數據。

+0

謝謝馬特!我會嘗試這個自動功能。我對使用字典作爲%運算符的RHS存在一些疑惑:'%(foo)s:%(bar)s''是否也會打印出'bar [「foo」]的值?或者它與你的例子有所不同? – user1126425

+0

基本上,'%()s'形式的所有內容都被替換爲字典中由''引用的對象的值。 http://docs.python.org/library/stdtypes.html#string-formatting –

+0

@synthesizerpatel的答案更有幫助。 – Jan

276

這樣做的正確的答案是使用已經提供funcName變量

import logging 
logger = logging.getLogger('root') 
FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s" 
logging.basicConfig(format=FORMAT) 
logger.setLevel(logging.DEBUG) 

然後你想要的任何地方,只需添加:從腳本我工作的正確

logger.debug('your message') 

輸出示例現在:

[invRegex.py:150 -   handleRange() ] ['[A-Z]'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03050>, '{', '1', '}']] 
[invRegex.py:197 -   handleMacro() ] ['\\d'] 
[invRegex.py:155 -  handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03950>, '{', '1', '}']] 
[invRegex.py:210 -  handleSequence() ] [[<__main__.GroupEmitter object at 0x10b9fedd0>, <__main__.GroupEmitter object at 0x10ba03ad0>]] 
+20

這應該是答案! – user3885927

+1

很好.. 有一點要補充,我們可以將日誌文件命名爲與代碼文件動態相同嗎? 例如: 我試過 logging.basicConfig(filename =「%(filename)」,format = FORMAT) 動態地取文件名,但它取得了靜態值。任何建議? – Outlier

+2

@Outlier不,推薦的方法是通過'getLogger(__ name __)' – farthVader

相關問題