Skip to content

Instantly share code, notes, and snippets.

@snower
Created May 31, 2023 01:27
Show Gist options
  • Save snower/adcf300f3daff99549dbe1949982a5dc to your computer and use it in GitHub Desktop.
Save snower/adcf300f3daff99549dbe1949982a5dc to your computer and use it in GitHub Desktop.
logging_file_lock_handler
# -*- coding: utf-8 -*-
# 14-8-20
# create by: snower
import os
import time
import struct
import fcntl
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
class RotatingFileHandler(RotatingFileHandler):
def __init__(self, *args, **kwargs):
super(RotatingFileHandler, self).__init__(*args, **kwargs)
self._lock_fd = 0
self._lock_version = 0
self._version = 0
self.init_lock()
def init_lock(self):
try:
self.acquire_lock()
self._version = self._lock_version
finally:
self.release_lock()
def acquire_lock(self):
if self._lock_fd == 0:
self._lock_fd = os.open(self.baseFilename + ".lock", os.O_CREAT | os.O_RDWR)
fcntl.flock(self._lock_fd, fcntl.LOCK_EX)
v = os.read(self._lock_fd, 4)
if len(v) == 4:
self._lock_version, = struct.unpack("!I", v)
os.lseek(self._lock_fd, 0, os.SEEK_SET)
def release_lock(self):
if self._lock_fd:
os.fsync(self._lock_fd)
fcntl.flock(self._lock_fd, fcntl.LOCK_UN)
os.close(self._lock_fd)
self._lock_fd = 0
def doRollover(self):
"""
Do a rollover, as described in __init__().
"""
if self.stream:
self.stream.close()
self.stream = None
try:
self.acquire_lock()
if self._lock_version == self._version:
if self.backupCount > 0:
for i in range(self.backupCount - 1, 0, -1):
sfn = "%s.%d" % (self.baseFilename, i)
dfn = "%s.%d" % (self.baseFilename, i + 1)
if os.path.exists(sfn):
# print "%s -> %s" % (sfn, dfn)
if os.path.exists(dfn):
os.remove(dfn)
os.rename(sfn, dfn)
dfn = self.baseFilename + ".1"
if os.path.exists(dfn):
os.remove(dfn)
# Issue 18940: A file may not have been created if delay is True.
if os.path.exists(self.baseFilename):
os.rename(self.baseFilename, dfn)
os.write(self._lock_fd, struct.pack("!I", self._lock_version + 1))
self._version += 1
finally:
self.release_lock()
if not self.delay:
self.stream = self._open()
class TimedRotatingFileHandler(TimedRotatingFileHandler):
def __init__(self, *args, **kwargs):
super(TimedRotatingFileHandler, self).__init__(*args, **kwargs)
self._lock_fd = 0
self._lock_version = 0
self._version = 0
self.init_lock()
def init_lock(self):
try:
self.acquire_lock()
self._version = self._lock_version
finally:
self.release_lock()
def acquire_lock(self):
if self._lock_fd == 0:
self._lock_fd = os.open(self.baseFilename + ".lock", os.O_CREAT | os.O_RDWR)
fcntl.flock(self._lock_fd, fcntl.LOCK_EX)
v = os.read(self._lock_fd, 4)
if len(v) == 4:
self._lock_version, = struct.unpack("!I", v)
os.lseek(self._lock_fd, 0, os.SEEK_SET)
def release_lock(self):
if self._lock_fd:
os.fsync(self._lock_fd)
fcntl.flock(self._lock_fd, fcntl.LOCK_UN)
os.close(self._lock_fd)
self._lock_fd = 0
def rename_file(self):
# get the time that this sequence started at and make it a TimeTuple
t = self.rolloverAt - self.interval
if self.utc:
timeTuple = time.gmtime(t)
else:
timeTuple = time.localtime(t)
dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
if os.path.exists(dfn):
os.remove(dfn)
os.rename(self.baseFilename, dfn)
if self.backupCount > 0:
# find the oldest log file and delete it
#s = glob.glob(self.baseFilename + ".20*")
# if len(s) > self.backupCount:
# s.sort()
# os.remove(s[0])
for s in self.getFilesToDelete():
os.remove(s)
def doRollover(self):
if self.stream:
self.stream.close()
self.stream = None
try:
self.acquire_lock()
if self._lock_version == self._version:
self.rename_file()
os.write(self._lock_fd, struct.pack("!I", self._lock_version + 1))
self._version += 1
finally:
self.release_lock()
# print "%s -> %s" % (self.baseFilename, dfn)
self.mode = 'a'
self.stream = self._open()
currentTime = int(time.time())
newRolloverAt = self.computeRollover(currentTime)
while newRolloverAt <= currentTime:
newRolloverAt = newRolloverAt + self.interval
# If DST changes and midnight or weekly rollover, adjust for this.
if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
dstNow = time.localtime(currentTime)[-1]
dstAtRollover = time.localtime(newRolloverAt)[-1]
if dstNow != dstAtRollover:
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
newRolloverAt = newRolloverAt - 3600
else: # DST bows out before next rollover, so we need to add an hour
newRolloverAt = newRolloverAt + 3600
self.rolloverAt = newRolloverAt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment