2009-06-01 9 views
14

Donc maintenant j'ai besoin de créer et implémenter une extension du module de journalisation Python qui sera utilisé pour se connecter à notre base de données. Fondamentalement, nous avons plusieurs applications python (qui s'exécutent toutes en arrière-plan) qui se connectent actuellement à un mashmash aléatoire de fichiers texte. Ce qui rend presque impossible de savoir si une application a échoué ou non. Le problème que l'on m'a donné est de déplacer ladite journalisation vers des fichiers texte vers un DB d'oracle. Les tables ont déjà été définies, et là où les choses doivent être enregistrées mais maintenant, je cherche à ajouter un autre gestionnaire de journalisation qui se connectera à la base de données. J'utilise python 2.5.4 et cx_Oracle et les applications en général peuvent être exécutées en tant que service/démon ou une application directe.Création d'un gestionnaire de journalisation pour se connecter à Oracle?

Je suis surtout curieux de savoir quelle serait la meilleure façon d'y parvenir. Quelques questions:

  1. En cas d'erreur avec cx_Oracle, où ces erreurs doivent-elles être consignées? Si son down serait-il préférable de simplement aller et avoir le logger retraite vers le fichier texte par défaut? Pendant ce temps, nous avons commencé à faire en sorte que les gens utilisent sys.stderr/stdout.write au lieu d'imprimer, donc dans le pire des cas, nous ne rencontrerions aucun problème avec l'impression devenant obsolète. Existe-t-il un moyen de faire en sorte que tous les appels sys.std soient acheminés de manière transparente directement dans l'enregistreur, et que l'enregistreur prenne le relais?

  2. Après chaque message enregistré, le script doit-il automatiquement effectuer une validation? (il y en aura plusieurs dizaines par seconde.)

  3. Quelle est la meilleure façon d'implémenter un nouveau gestionnaire pour le système de journalisation? Hériter de la classe de base Handler semble être le plus facile.

Toutes les idées/suggestions seraient super.

+0

Ajouter ceci comme commentaire que je ne considère pas une « réponse » - si vous voulez passer à l'enregistrement de base de données afin d'interroger et de faire rapport sur les erreurs, avez-vous envisagé de continuer à écrire les fichiers texte et juste lier les définitions de table externes Oracle aux fichiers?À bien des égards, c'est le meilleur des deux mondes - vous n'avez pas besoin de modifier le code de journalisation et vous avez la possibilité de traiter les fichiers comme des tables Oracle. Cela fonctionne évidemment mieux s'il existe une structure cohérente pour les fichiers qui peuvent être mappés sur une structure de table. – dpbradley

Répondre

20
  1. Si des erreurs surviennent avec cx_Oracle, il est probablement préférable de les enregistrer dans un fichier texte.
  2. Vous pouvez essayer de rediriger sys.stdout et sys.stderr vers des objets de type fichier qui enregistrent tout ce qui leur est écrit dans un enregistreur.
  3. Je suppose que vous voulez commettre après chaque événement, sauf si vous avez de bonnes raisons de ne pas le faire. Vous pouvez également mettre en mémoire tampon plusieurs événements et les écrire tous en une seule fois. Voici un exemple qui utilise mx.ODBC, vous pouvez probablement adapter ceci à cx_Oracle sans trop de problèmes. C'est censé être compatible avec Python DB-API 2.0, je pense.

La distribution de l'enregistrement Python autonome (avant l'enregistrement a été ajouté à Python) est à http://www.red-dove.com/python_logging.html et bien que le paquet d'enregistrement en Python est beaucoup plus à jour, la distribution autonome contient un répertoire de test qui a beaucoup d'exemples utiles des classes de gestionnaire dérivées.

#!/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") 
Questions connexes