print - Python logging to database
python logging output to console (5)
Estoy buscando una manera de dejar que el módulo del registrador de Python se registre en la base de datos y vuelva al sistema de archivos cuando la base de datos está inactiva.
Básicamente, 2 cosas: cómo dejar que el registrador se registre en la base de datos y cómo hacer que caiga en el registro de archivos cuando la base de datos no funciona.
¿Has visto la librería log4mongo? https://pypi.python.org/pypi/log4mongo/ Proporciona un identificador para Mongo. El respaldo no está allí, pero supongo que sería relativamente fácil de agregar.
Caramba ... pasó mucho tiempo, pero recientemente logré escribir mi propio registrador de base de datos en Python. Como no pude encontrar ningún ejemplo, pensé que publico el mío aquí. Quizás a alguien le resulte útil :) Trabaja con MS SQL.
La tabla de base de datos podría verse así:
CREATE TABLE [db_name].[log](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[log_level] [int] NULL,
[log_levelname] [char](32) NULL,
[log] [char](2048) NOT NULL,
[created_at] [datetime2](7) NOT NULL,
[created_by] [char](32) NOT NULL,
) ON [PRIMARY]
La propia clase:
class LogDBHandler(logging.Handler):
''''''
Customized logging handler that puts logs to the database.
pymssql required
''''''
def __init__(self, sql_conn, sql_cursor, db_tbl_log):
logging.Handler.__init__(self)
self.sql_cursor = sql_cursor
self.sql_conn = sql_conn
self.db_tbl_log = db_tbl_log
def emit(self, record):
# Set current time
tm = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.created))
# Clear the log message so it can be put to db via sql (escape quotes)
self.log_msg = record.msg
self.log_msg = self.log_msg.strip()
self.log_msg = self.log_msg.replace(''/''', ''/'/''')
# Make the SQL insert
sql = ''INSERT INTO '' + self.db_tbl_log + '' (log_level, '' + /
''log_levelname, log, created_at, created_by) '' + /
''VALUES ('' + /
'''' + str(record.levelno) + '', '' + /
''/''' + str(record.levelname) + ''/', '' + /
''/''' + str(self.log_msg) + ''/', '' + /
''(convert(datetime2(7), /''' + tm + ''/')), '' + /
''/''' + str(record.name) + ''/')''
try:
self.sql_cursor.execute(sql)
self.sql_conn.commit()
# If error - print it out on screen. Since DB is not working - there''s
# no point making a log about it to the database :)
except pymssql.Error as e:
print sql
print ''CRITICAL DB ERROR! Logging to database not possible!''
Y ejemplo de uso:
import pymssql
import time
import logging
db_server = ''servername''
db_user = ''db_user''
db_password = ''db_pass''
db_dbname = ''db_name''
db_tbl_log = ''log''
log_file_path = ''C://Users//Yourname//Desktop//test_log.txt''
log_error_level = ''DEBUG'' # LOG error level (file)
log_to_db = True # LOG to database?
class LogDBHandler(logging.Handler):
[...]
# Main settings for the database logging use
if (log_to_db):
# Make the connection to database for the logger
log_conn = pymssql.connect(db_server, db_user, db_password, db_dbname, 30)
log_cursor = log_conn.cursor()
logdb = LogDBHandler(log_conn, log_cursor, db_tbl_log)
# Set logger
logging.basicConfig(filename=log_file_path)
# Set db handler for root logger
if (log_to_db):
logging.getLogger('''').addHandler(logdb)
# Register MY_LOGGER
log = logging.getLogger(''MY_LOGGER'')
log.setLevel(log_error_level)
# Example variable
test_var = ''This is test message''
# Log the variable contents as an error
log.error(''This error occurred: %s'' % test_var)
Arriba se registrará tanto en la base de datos como en el archivo. Si el archivo no es necesario, omita la línea ''logging.basicConfig (filename = log_file_path)''. Todo lo registrado usando ''log'' - será registrado como MY_LOGGER. Si aparece algún error externo (es decir, en el módulo importado o algo así), el error aparecerá como "raíz", ya que el registrador "raíz" también está activo y está utilizando el controlador de la base de datos.
Escriba usted mismo un handler que dirija los registros a la base de datos en cuestión. Cuando falla, puede eliminarlo de la lista de manejadores del registrador. Hay muchas maneras de lidiar con los modos de falla.
Estoy cavando esto de nuevo.
Hay una solución con SqlAlchemy ( no se requiere Pirámide para esta receta ):
https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/logging/sqlalchemy_logger.html
Y podría mejorar el registro agregando campos adicionales, aquí hay una guía: https://.com/a/17558764/1115187
Fallback a FS
No estoy seguro de que esto sea correcto al 100%, pero podría tener 2 controladores:
- manejador de base de datos (escribir en la base de datos)
- manejador de archivos (escribir en un archivo o secuencia)
Simplemente envuelva el DB-commit con un try-except
. Pero tenga en cuenta: el archivo contendrá TODAS las entradas de registro, pero no solo las entradas para las cuales no se pudo guardar la base de datos.
Vieja pregunta, pero dejando esto para otros. Si desea utilizar el registro de Python, puede agregar dos controladores. Uno para escribir en el archivo, un controlador de archivos giratorio. Esto es robusto, y se puede hacer sin importar si el dB está arriba o no. El otro puede escribir en otro servicio / módulo, como una integración pymongo.
Busque logging.config sobre cómo configurar sus controladores desde el código o json.