mirror of
https://github.com/gryf/wicd.git
synced 2025-12-21 05:18:02 +01:00
201 lines
5.7 KiB
Python
201 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
#
|
|
# Copyright (C) 1999-2006 Keith Dart <keith@kdart.com>
|
|
# Copyright (C) 2008-2009 Dan O'Reilly <oreilldf@gmail.com>
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
|
|
"""
|
|
|
|
Managing logfile rotation. A ManagedLog object is a file-like object that
|
|
rotates itself when a maximum size is reached.
|
|
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import time
|
|
import io
|
|
|
|
class SizeError(IOError):
|
|
""" Custom error class. """
|
|
pass
|
|
|
|
class LogFile(io.FileIO):
|
|
"""LogFile(name, [mode="w"], [maxsize=360000])
|
|
|
|
Opens a new file object. After writing <maxsize> bytes a SizeError
|
|
will be raised.
|
|
|
|
"""
|
|
def __init__(self, name, mode="a", maxsize=360000, *args, **kwargs):
|
|
super(LogFile, self).__init__(name, mode, maxsize, *args, **kwargs)
|
|
self.maxsize = maxsize
|
|
self.eol = True
|
|
try:
|
|
self.written = os.fstat(self.fileno())[6]
|
|
except OSError:
|
|
self.written = 0
|
|
|
|
def write(self, data):
|
|
self.written += len(data)
|
|
|
|
data = data.encode('utf-8')
|
|
if len(data) <= 0:
|
|
return
|
|
if self.eol:
|
|
super(LogFile, self).write(self.get_time().encode("utf-8") + b' :: ')
|
|
self.eol = False
|
|
|
|
if data[-1] == '\n':
|
|
self.eol = True
|
|
data = data[:-1]
|
|
|
|
super(LogFile, self).write(data.replace(
|
|
b'\n', b'\n' + self.get_time().encode("utf-8") + b' :: '))
|
|
if self.eol:
|
|
super(LogFile, self).write('\n')
|
|
|
|
self.flush()
|
|
if self.written > self.maxsize:
|
|
raise SizeError
|
|
|
|
def get_time(self):
|
|
""" Return a string with the current time nicely formatted.
|
|
|
|
The format of the returned string is yyyy/mm/dd HH:MM:SS
|
|
|
|
"""
|
|
x = time.localtime()
|
|
return ''.join([
|
|
str(x[0]).rjust(4, '0'), '/', str(x[1]).rjust(2, '0'), '/',
|
|
str(x[2]).rjust(2, '0'), ' ', str(x[3]).rjust(2, '0'), ':',
|
|
str(x[4]).rjust(2, '0'), ':', str(x[5]).rjust(2, '0')])
|
|
|
|
def rotate(self):
|
|
""" Rotate logfile. """
|
|
return rotate(self)
|
|
|
|
def note(self, text):
|
|
"""Writes a specially formated note text to the file.
|
|
|
|
The note starts with the string '\\n#*=' so you can easily filter them.
|
|
|
|
"""
|
|
self.write("\n#*===== %s =====\n" % (text,))
|
|
|
|
|
|
class ManagedLog(object):
|
|
"""ManagedLog(name, [maxsize=360000], [maxsave=9])
|
|
|
|
A ManagedLog instance is a persistent log object. Write data with the
|
|
write() method. The log size and rotation is handled automatically.
|
|
|
|
"""
|
|
def __init__(self, name, maxsize=360000, maxsave=3):
|
|
if not os.path.exists(os.path.dirname(name)):
|
|
os.makedirs(os.path.dirname(name))
|
|
self._lf = LogFile(name, "a", maxsize)
|
|
self.maxsave = maxsave
|
|
|
|
def __repr__(self):
|
|
return "%s(%r, %r, %r)" % (self.__class__.__name__, self._lf.name,
|
|
self._lf.maxsize, self.maxsave)
|
|
|
|
def write(self, data):
|
|
""" Write logfile. """
|
|
try:
|
|
self._lf.write(data)
|
|
except SizeError:
|
|
self._lf = rotate(self._lf, self.maxsave)
|
|
|
|
def note(self, data):
|
|
""" Write a note to the logfile. """
|
|
try:
|
|
self._lf.note(data)
|
|
except SizeError:
|
|
self._lf = rotate(self._lf, self.maxsave)
|
|
|
|
def written(self):
|
|
""" Return whether the logfile was written. """
|
|
return self._lf.written
|
|
|
|
def rotate(self):
|
|
""" Rotate logfile. """
|
|
self._lf = rotate(self._lf, self.maxsave)
|
|
|
|
# auto-delegate remaining methods (but you should not read or seek an open
|
|
# log file).
|
|
def __getattr__(self, name):
|
|
return getattr(self._lf, name)
|
|
|
|
|
|
# useful for logged stdout for daemon processes
|
|
class ManagedStdio(ManagedLog):
|
|
""" Manage stdout/stderr. """
|
|
def write(self, data):
|
|
""" Write logfile to disk. """
|
|
try:
|
|
self._lf.write(data)
|
|
except SizeError:
|
|
sys.stdout.flush()
|
|
sys.stderr.flush()
|
|
self._lf = rotate(self._lf, self.maxsave)
|
|
fd = self._lf.fileno()
|
|
os.dup2(fd, 1)
|
|
os.dup2(fd, 2)
|
|
sys.stdout = sys.stderr = self
|
|
|
|
|
|
def rotate(fileobj, maxsave=9):
|
|
""" Rotate fileobj. """
|
|
name = fileobj.name
|
|
mode = fileobj.mode
|
|
maxsize = fileobj.maxsize
|
|
fileobj.close()
|
|
shiftlogs(name, maxsave)
|
|
return LogFile(name, mode, maxsize)
|
|
|
|
|
|
# assumes basename logfile is closed.
|
|
def shiftlogs(basename, maxsave):
|
|
""" Shift logfiles. """
|
|
topname = "%s.%d" % (basename, maxsave)
|
|
if os.path.isfile(topname):
|
|
os.unlink(topname)
|
|
|
|
for i in range(maxsave, 0, -1):
|
|
oldname = "%s.%d" % (basename, i)
|
|
newname = "%s.%d" % (basename, i+1)
|
|
try:
|
|
os.rename(oldname, newname)
|
|
except OSError:
|
|
pass
|
|
try:
|
|
os.rename(basename, "%s.1" % (basename))
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
def open(name, maxsize=360000, maxsave=9):
|
|
""" Open logfile. """
|
|
return ManagedLog(name, maxsize, maxsave)
|
|
|
|
def writelog(logobj, data):
|
|
""" Write logfile. """
|
|
try:
|
|
logobj.write(data)
|
|
except SizeError:
|
|
return rotate(logobj)
|
|
else:
|
|
return logobj
|