Python
python2.6

Python2.6でTimedRotatingFileHandlerのログローテートが効かない問題への対処

TimedRotatingFileHandlerのログローテーション

RHEL6やCentOS6で標準のPythonのバージョンは2.6なのでPython2.6を使うことがあるのですが、2.7以降では見られない挙動がありました。

hoge.py
from logging import getLogger
from logging.handlers import TimedRotatingFileHandler

logger = getLogger(__name__)

handler = TimedRotatingFileHandler("hoge.log",'S')

logger.addHandler(handler)
logger.error("test")

上記のようなファイルを作って実行すると、Python2.7以降(3系含む)ならログローテートされてhoge.log.2018-01-31_02-04-27といったファイルが作られるかと思います。
しかし、Python2.6だとログローテートされずにhoge.logに追記され続けてしまいます。

ログローテートされない原因

原因を探ろうと公式サイトからソースコードを取ってみたら、TimedRotatingFileHandlerクラスのコンストラクタで設定されるrolloverAtの値に違いが有りました。

Python-2.6.9/Lib/logging/handlers.py
class TimedRotatingFileHandler(BaseRotatingHandler):
    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0):
# 略
        self.rolloverAt = self.computeRollover(int(time.time()))
Python-2.7/Lib/logging/handlers.py
class TimedRotatingFileHandler(BaseRotatingHandler):
    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0):
# 略
        if os.path.exists(filename):
            t = os.stat(filename)[ST_MTIME]
        else:
            t = int(time.time())
        self.rolloverAt = self.computeRollover(t)

computeRolloverは次にログローテートが必要な時刻を計算するメソッドです。
計算は引数の時刻にもとづいて行われます。
when="S",interval=5"ならtの5秒後、when="D",interval=5"ならtの5日後、when="MIDNIGHT"ならtの次の00:00、というように動作します。

2.6ではtの値がスクリプトを実行された時刻となるため、ログローテートする時間に達することがなかったということになります。
つまり、下記のようにsleepを入れるとログローテートしてくれそうです。

hoge_sleep.py
from logging import getLogger
from logging.handlers import TimedRotatingFileHandler
from time import sleep

logger = getLogger(__name__)

handler = TimedRotatingFileHandler("hoge.log",'S')

logger.addHandler(handler)
sleep(2)
logger.error("test")

解決策

1日毎にログローテートするために24時間sleepを入れるのは現実的ではないので、Python2.7のコードを移植したいと思います。
クラスを作らなくても直接書いても良い気もします。

hoge26.py
from logging import getLogger
from logging.handlers import TimedRotatingFileHandler
from time import sleep
from stat import ST_MTIME
import os

class TimedRotatingFileHandler26(TimedRotatingFileHandler):
    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0):
        super().__init__(filename, when, interval, backupCount, encoding, delay, utc)
        if os.path.exists(filename):
            t = os.stat(filename)[ST_MTIME]
            self.rolloverAt = self.computeRollover(t)

logger = getLogger(__name__)

handler = TimedRotatingFileHandler26("hoge.log",'S')

logger.addHandler(handler)
logger.error("test")

これでPython2.6でもログローテートするようになるかと思います。