2009-06-01 59 views
14

所以現在我需要創建並實現將用於登錄到我們的數據庫的Python日誌模塊的擴展。基本上我們有幾個Python應用程序(都在後臺運行),它們當前登錄到文本文件的隨機混雜。這使得幾乎不可能找出某個應用程序是否失敗。創建一個日誌處理程序來連接到Oracle?

給我的問題是將所述日誌記錄移動到文本文件到oracle數據庫。這些表已經被定義了,並且現在需要記錄的東西,但現在我正在尋找添加另一個日誌處理程序來登錄到數據庫。

我使用的是python 2.5.4和cx_Oracle,一般的應用程序可以作爲服務/守護進程或直接應用程序運行。

我只是主要好奇什麼是最好的方式去做這件事。幾個問題:

  1. 如果cx_Oracle出現任何錯誤,應將這些錯誤記錄到哪裏?如果它停下來最好只是去讓記錄器撤回到默認的文本文件?

  2. 一段時間後,我們開始強制人們使用sys.stderr/stdout.write而不是print,所以最壞的情況是,我們不會遇到打印成爲棄用的任何問題。有沒有辦法讓所有的數千個sys.std調用直接傳送到記錄器中,並讓記錄器拾取冗餘?

  3. 在每個記錄的消息之後,腳本是否應該自動執行提交? (將會有幾十秒。)

  4. 實現日誌記錄系統的新處理程序的最佳方式是什麼?繼承基本的Handler類似乎是最簡單的。

任何意見/建議將是巨大的。

+0

將此添加爲註釋,因爲我不認爲它是「答案」 - 如果要移動到數據庫日誌記錄以便查詢和報告錯誤,是否考慮繼續寫入文本文件只是將Oracle外部表定義綁定到這些文件?在很多方面,這是兩全其美的 - 你不必修改日誌代碼,就可以將文件視爲Oracle表格。如果對可以映射到表結構的文件有一些一致的結構,這顯然是最好的。 – dpbradley 2009-06-02 15:56:45

回答

20
  1. 如果cx_Oracle發生錯誤,最好將它們記錄到文本文件中。
  2. 您可以嘗試將sys.stdout和sys.stderr重定向到類似文件的對象,這些對象將寫入它們的內容記錄到記錄器中。
  3. 我猜你想在每個事件後提交,除非你有強烈的理由不這樣做。或者,您可以緩衝多個事件並每隔一段時間將其全部寫入單個事務中。
  4. 下面是一個使用mx.ODBC的例子,你可以很容易地將它適配到cx_Oracle中,而不會有太多的麻煩。它的意思是Python DB-API 2.0兼容,我想。

單機Python記錄分佈(前測井加入到Python)爲http://www.red-dove.com/python_logging.html並且儘管日誌包在Python得多最新的,獨立的分佈包含具有很多有用的例子一個測試目錄的派生處理程序類。

#!/usr/bin/env python 
# 
# Copyright 2001-2009 by Vinay Sajip. All Rights Reserved. 
# 
# Permission to use, copy, modify, and distribute this software and its 
# documentation for any purpose and without fee is hereby granted, 
# provided that the above copyright notice appear in all copies and that 
# both that copyright notice and this permission notice appear in 
# supporting documentation, and that the name of Vinay Sajip 
# not be used in advertising or publicity pertaining to distribution 
# of the software without specific, written prior permission. 
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
# 
# This file is part of the standalone Python logging distribution. See 
# http://www.red-dove.com/python_logging.html 
# 
""" 
A test harness for the logging module. An example handler - DBHandler - 
which writes to an Python DB API 2.0 data source. You'll need to set this 
source up before you run the test. 

Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved. 
""" 
import sys, string, time, logging 

class DBHandler(logging.Handler): 
    def __init__(self, dsn, uid='', pwd=''): 
     logging.Handler.__init__(self) 
     import mx.ODBC.Windows 
     self.dsn = dsn 
     self.uid = uid 
     self.pwd = pwd 
     self.conn = mx.ODBC.Windows.connect(self.dsn, self.uid, self.pwd) 
     self.SQL = """INSERT INTO Events (
         Created, 
         RelativeCreated, 
         Name, 
         LogLevel, 
         LevelText, 
         Message, 
         Filename, 
         Pathname, 
         Lineno, 
         Milliseconds, 
         Exception, 
         Thread 
        ) 
        VALUES (
         %(dbtime)s, 
         %(relativeCreated)d, 
         '%(name)s', 
         %(levelno)d, 
         '%(levelname)s', 
         '%(message)s', 
         '%(filename)s', 
         '%(pathname)s', 
         %(lineno)d, 
         %(msecs)d, 
         '%(exc_text)s', 
         '%(thread)s' 
        ); 
        """ 
     self.cursor = self.conn.cursor() 

    def formatDBTime(self, record): 
     record.dbtime = time.strftime("#%m/%d/%Y#", time.localtime(record.created)) 

    def emit(self, record): 
     try: 
      #use default formatting 
      self.format(record) 
      #now set the database time up 
      self.formatDBTime(record) 
      if record.exc_info: 
       record.exc_text = logging._defaultFormatter.formatException(record.exc_info) 
      else: 
       record.exc_text = "" 
      sql = self.SQL % record.__dict__ 
      self.cursor.execute(sql) 
      self.conn.commit() 
     except: 
      import traceback 
      ei = sys.exc_info() 
      traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) 
      del ei 

    def close(self): 
     self.cursor.close() 
     self.conn.close() 
     logging.Handler.close(self) 

dh = DBHandler('Logging') 
logger = logging.getLogger("") 
logger.setLevel(logging.DEBUG) 
logger.addHandler(dh) 
logger.info("Jackdaws love my big %s of %s", "sphinx", "quartz") 
logger.debug("Pack my %s with five dozen %s", "box", "liquor jugs") 
try: 
    import math 
    math.exp(1000) 
except: 
    logger.exception("Problem with %s", "math.exp")