2013-08-20 49 views
9

我試圖找到導致我們的python腳本崩潰的原因。找不到異常的來源

主要結構是這樣的:

def main() 
    try: 
     dostuff 
    except Exception as ex: 
     import traceback 
     tb = traceback.format_exc() 
     import platform 
     node = platform.node() 
     sendMail([DEBUG_EMAIL], "Alarm exception on %s" % node, str(tb), []) 

我得到這個堆棧跟蹤在我們的主要錯誤處理,中我應該爲錯誤的電子郵件。

Traceback (most recent call last): 
    File "/usr/lib/python2.6/logging/__init__.py", line 799, in emit 
    stream.write(fs % msg.encode("UTF-8")) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 66: ordinal not in range(128) 

從我看到所有的寫調用記錄的是在try塊裏面,但因爲它不是抓在我的電子郵件發送看來我錯過了什麼異常塊處理。我已經檢查過,sendMail函數完全不使用日誌記錄模塊。所以這個異常不應該出現在我的except塊中。

我嘗試添加

sys.tracebacklimit = 10 

在文件的頂部看到異常起源,但沒有造成任何影響。現在我對如何找到問題的起源有什麼想法。

該腳本每小時運行一次,每週大約一次崩潰,這使得我認爲它與輸入數據有關,但只能由dostuff()處理。

UPDATE:

我已經想通了,爲什麼我只得到堆棧跟蹤的一行。在emit()裏面我發現了這個。

 try: 
      ... doing stuff, something goes boom with encoding... 
     except UnicodeError: 
      stream.write(fs % msg.encode("UTF-8")) Here it goes Boom again 
     self.flush() 
    except (KeyboardInterrupt, SystemExit): 
     raise 
    except: 
     self.handleError(record) Which means it ends up here 

而且功能的HandleError的相關部分看起來是這樣的:

ei = sys.exc_info() 
try: 
    traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) 

哪隻打印堆棧跟蹤的最後一部分。

+0

我不確定你的意思。 – dutt

+0

異常似乎發生在日誌包的'__init __。py'腳本中,所以在腳本加載時也會發生異常,並且無法在輸入try塊之前導入'logging', – val

+0

@ValentinCLEMENT添加了有關使用情況的信息和崩潰頻率。 – dutt

回答

3

基本上你的問題是雙重的

  1. 一個日誌流不接受擴展字符8位字符串,並拋出UnicodeError
  2. 沒有在日誌模塊一個愚蠢的錯誤,這使它失去了原有的回溯

異常的確切原因是這樣的:

>>> 'ä'.encode('UTF-8') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) 

但這個例外不是真正的問題。這是2.6日誌記錄代碼的一部分; 799是該塊的最後一行。最後一行是導致問題的原因。基本上,東西以8位字節字符串記錄消息,UTF-8編碼,包含Latin-1擴展字母;但是流不喜歡那樣,並且在try塊中拋出一個UnicodeError;

try: 
    if (isinstance(msg, unicode) and 
     getattr(stream, 'encoding', None)): 

     # .... the string is NOT an unicode instance, so ignored 
     # for brevity 
    else: 
     # this line throws the original exception 
     # fs is a bytestring "%s\n", and msg is a bytestring 
     # with extended letters, most probably Latin 1. 
     # stream.write spits out an UnicodeError on these values 
     stream.write(fs % msg) 
except UnicodeError: 
    # now we get a useless exception report from this code 
    stream.write(fs % msg.encode("UTF-8")) 

所以調試這一點,你會希望建立在上述線路799斷點,並嘗試所有記錄,如果他們接受以下字符串:

logging.getLogger(name).critical('Testing logger: ä') 

如果碰到線799則得到異常的回溯,它可以揭示發生了什麼...

+0

好的答案:)除了這種情況每週只發生一次,我真的想改進堆棧跟蹤以查看代碼中問題發生的位置。我目前的計劃是複製和修改日誌記錄模塊以修復堆棧跟蹤打印輸出。然後,當我知道錯誤來自何處時,我可以回到使用標準模塊。 – dutt