Python日志:FileHandler在模式'w'不工作但在模式'a'工作正常

WBA*_*BAR 2 python python-2.7

2.7.5Windows下的python中,当FileHandler处于模式时'w'(在写入之前截断文件)处理程序不会只写入最后一行.在模式下'a'一切都很好.

我的logging.conf档案:

[loggers]
keys=root

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=NOTSET
handlers=fileHandler

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('generator.log', 'a', 'utf8', 0)

[formatter_simpleFormatter]
format=[ %(asctime)s ] [ %(name)s ] [ %(levelname)-5s ] - %(message)s
datefmt=
Run Code Online (Sandbox Code Playgroud)

我的oracle.py档案:

__author__ = 'wbar'
import cx_Oracle
from contextlib import closing
import logging


class Connector(object):
    __connection__ = None
    __user_name__ = None
    __password__ = None
    __tns_name__ = None
    __logger__ = None

    def get_connection(self, auto_connect=True):
        if auto_connect and not self.__connection__:
            self.__logger__.info(u'Connecting into Oracle: %s@%s', self.__user_name__, self.__tns_name__)
            self.__connection__ = cx_Oracle.connect(
                u'%s/%s@%s' % (self.__user_name__, self.__password__, self.__tns_name__))
        return self.__connection__

    def __init__(self, user_name, password, tns_name):
        self.__user_name__ = user_name
        self.__password__ = password
        self.__tns_name__ = tns_name
        self.__logger__ = logging.getLogger('OracleConnector')
        self.__logger__.addHandler(logging.NullHandler())

    def __del__(self):
        self.close_connection()

    def close_connection(self):
        connection = self.get_connection(auto_connect=False)
        if connection:
            self.__logger__.info(u'Closing connection with Oracle: %s@%s', self.__user_name__, self.__tns_name__)
            connection.close()

    def execute(self, sql):
        with closing(self.get_connection().cursor()) as cursor:
            self.__logger__.debug(u'Executing: %s', sql)
            cursor.execute(sql)
            return cursor.fetchall()
Run Code Online (Sandbox Code Playgroud)

最后我的主要文件generator.py:

__author__ = 'wbar'
import logging
import logging.config

logging.FileHandler
logging.config.fileConfig('logging.conf')

from oracle import Connector as OracleConnector
DATABASE = OracleConnector(user_name=u'foo', password=u'bar', tns_name=u'db_local')

for line in DATABASE.execute('select * from dual'):
    print(line[0])

logger = logging.getLogger('root')

logger.debug('DEBUG')
logger.info('INFO')
logger.error('ERROR')
Run Code Online (Sandbox Code Playgroud)

在模式'a'日志文件中看起来像:

[ 2013-11-13 17:15:25,608 ] [ OracleConnector ] [ INFO  ] - Connecting into Oracle: pms_test@db_impaq_local
[ 2013-11-13 17:15:25,727 ] [ OracleConnector ] [ DEBUG ] - Executing: select * from dual
[ 2013-11-13 17:15:25,730 ] [ root ] [ DEBUG ] - DEBUG
[ 2013-11-13 17:15:25,730 ] [ root ] [ INFO  ] - INFO
[ 2013-11-13 17:15:25,730 ] [ root ] [ ERROR ] - ERROR
[ 2013-11-13 17:15:25,734 ] [ OracleConnector ] [ INFO  ] - Closing connection with Oracle: pms_test@db_impaq_local
Run Code Online (Sandbox Code Playgroud)

在模式'w'日志文件中看起来像:

[ 2013-11-13 17:06:24,239 ] [ OracleConnector ] [ INFO  ] - Closing connection with Oracle: pms_test@db_impaq_local
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 5

logging模块注册一个关闭所有处理程序的atexit关闭钩子.这会'w'在Python退出时关闭打开的文件对象.

但是,您的oracle.Connector()类有一个__del__方法,当Python退出时也会调用该方法.atexit清理全局变量之前的Python调用,因此这里的操作的确切顺序是:

  1. loggingatexit钩子被调用时,文件被关闭.
  2. oracle.Connector().__del__()被调用,调用self.__logger__.info().这将重新打开关闭的文件处理程序以记录,截断文件.

要防止这种情况,请退出Python 之前显式关闭连接器:

DATABASE.close_connection()
Run Code Online (Sandbox Code Playgroud)