python logging to database

后端 未结 4 816
面向向阳花
面向向阳花 2020-12-13 02:49

I\'m seeking a way to let the python logger module to log to database and falls back to file system when the db is down.

So basically 2 things: How to let the logger

相关标签:
4条回答
  • 2020-12-13 02:57

    Old question, but dropping this for others. If you want to use python logging, you can add two handlers. One for writing to file, a rotating file handler. This is robust, and can be done regardless if the dB is up or not. The other one can write to another service/module, like a pymongo integration.

    Look up logging.config on how to setup your handlers from code or json.

    0 讨论(0)
  • 2020-12-13 03:13

    I recently managed to write my own database logger in Python. Since I couldn't find any example I thought I post mine here. Works with MS SQL.

    Database table could look like this:

    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]
    

    The class itself:

    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!'
    

    And usage example:

    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)
    

    Above will log both to the database and to the file. If file is not needed - skip the 'logging.basicConfig(filename=log_file_path)' line. Everything logged using 'log' - will be logged as MY_LOGGER. If some external error appears (i.e. in the module imported or something) - error will appear as 'root', since 'root' logger is also active, and is using the database handler.

    0 讨论(0)
  • 2020-12-13 03:15

    I am digging this out again.

    There is a solution with SqlAlchemy (Pyramid is NOT required for this recipe):

    https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/logging/sqlalchemy_logger.html

    And you could improve logging by adding extra fields, here is a guide: https://stackoverflow.com/a/17558764/1115187

    Fallback to FS

    Not sure that this is 100% correct, but you could have 2 handlers:

    1. database handler (write to DB)
    2. file handler (write to file or stream)

    Just wrap the DB-commit with a try-except. But be aware: the file will contain ALL log entries, but not only entries for which DB saving was failed.

    0 讨论(0)
  • 2020-12-13 03:18

    Write yourself a handler that directs the logs to the database in question. When it fails, you can remove it from the handler list of the logger. There are many ways to deal with the failure-modes.

    0 讨论(0)
提交回复
热议问题