自定义python logging handler

1. 在实际操作中要考虑的点

  1. 在工作中,日志是必不可少的信息来源,特别是在排错的时候。在不同公司,有这不同的日志文件风格,有的是每个日志文件按照日期,放在同一个文件夹下面,有的是根据pid去区分,可能都有自己特殊的需求。总结起来,就是如何去分割日志文件。

  2. 在python中,logging模块只是线程安全的,并没有保证进程安全,因此,在实际的生产环境中,都是每个应用启动多个进程,实现longging的多进程安全是很有必要的。

2. 多进程安全

先安利一个开源库,concurrent-log-handler,地址是Preston-Landers: concurrent-log-handler

在这个库里面,通过文件锁实现了进程安全。

其进入日志的写操作核心是:

def emit(self, record):
        """
        Emit a record.

        Override from parent class to handle file locking for the duration of rollover and write.
        This also does the formatting *before* locks are obtained, in case the format itself does
        logging calls from within. Rollover also occurs while the lock is held.
        """
        # noinspection PyBroadException
        try:
            msg = self.format(record)
            try:
                self._do_lock()

                try:
                    if self.shouldRollover(record):
                        self.doRollover()
                except Exception as e:
                    self._console_log("Unable to do rollover: %s" % (e,), stack=True)
                    # Continue on anyway

                self.do_write(msg)

            finally:
                self._do_unlock()
        except Exception:
            self.handleError(record)

可以看到,先调用 self._do_lock(), 然后进行日志文件的写操作,然后调用self._do_unlock().


def _do_lock(self):
        self._open_lockfile()
        if self.stream_lock:
            lock(self.stream_lock, LOCK_EX)
        else:
            self._console_log("No self.stream_lock to lock", stack=True)


elif os.name == 'posix':
    def lock(file, flags):
        try:
            fcntl.flock(file, flags)
        except IOError as exc_value:
            # The exception code varies on different systems so we'll catch
            # every IO error
            raise LockException(str(exc_value))


    def unlock(file):
        fcntl.flock(file.fileno(), fcntl.LOCK_UN)
fcntl.flock:

https://docs.python.org/2/library/fcntl.html#fcntl.flock

fcntl.flock(fd, op)¶
Perform the lock operation op on file descriptor fd (file objects providing a fileno() method are accepted as well). See the Unix manual flock(2) for details. (On some systems, this function is emulated using fcntl().)

If the flock() fails, an IOError exception is raised.

可以看到,是调用unix中的flock实现了文件锁,op这个参数,用来规定了文件锁的类型:
* LOCK_UN – unlock
* LOCK_SH – acquire a shared lock, 共享锁,所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限。
* LOCK_EX – acquire an exclusive lock, 排它锁,除加锁进程外其他进程没有对已加锁文件读写访问权限。
使用LOCK_EX参数,就实现了进程安全。

进程安全的实现方式:fcntl.flock(file, LOCK_EX)

3. 实现对文件分割的需求

一般条件下,ConcurrentRotatingFileHandler基本可以满足我们的要求,但是,特殊情况,我们就需要对ConcurrentRotatingFileHandler来进行改造了。

以需要根据日期分文件夹,存储日志文件为例:

思路是:
1. 每天肯定是需要创建文件夹,这里就要考虑到多进程安全。
2. ConcurrentRotatingFileHandler是基于BaseRotatingHandler的,会涉及到baseFilename这个日志文件路径。

关于第1点考虑,参照文件锁的方法即可。第2点,修改日志文件路径baseFilename,对文件stream实例进行关闭后再进行打开即可。
这个需要重写方法shouldRollover, 并在重写的同时,创建新的文件夹目录,修改日志文件路径baseFilename

4. 总体思路

用文件锁实现进程安全,然后修改日志文件路径,正确地对日志文件流进行打开和关闭

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值