mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Make log rotation also limited by size and controllable from settings. Resolves #2041
This commit is contained in:
parent
f124b3510b
commit
ff16eb1bfe
13 changed files with 98 additions and 40 deletions
|
|
@ -46,6 +46,8 @@ without arguments starts a full interactive Python console.
|
|||
the new `raise_exception` boolean if ranting to raise KeyError on a missing key.
|
||||
- Moved behavior of unmodified `Command` and `MuxCommand` `.func()` to new
|
||||
`.get_command_info()` method for easier overloading and access. (Volund)
|
||||
- Removed unused `CYCLE_LOGFILES` setting. Added `SERVER_LOG_DAY_ROTATION`
|
||||
and `SERVER_LOG_MAX_SIZE` (and equivalent for PORTAL) to control log rotation.
|
||||
|
||||
|
||||
## Evennia 0.9 (2018-2019)
|
||||
|
|
|
|||
|
|
@ -1062,7 +1062,7 @@ class TestBuilding(CommandTest):
|
|||
# Test valid dbref ranges with no search term
|
||||
id1 = self.obj1.id
|
||||
id2 = self.obj2.id
|
||||
maxid = ObjectDB.objects.latest('id').id
|
||||
maxid = ObjectDB.objects.latest("id").id
|
||||
maxdiff = maxid - id1 + 1
|
||||
mdiff = id2 - id1 + 1
|
||||
|
||||
|
|
|
|||
|
|
@ -441,11 +441,11 @@ class TBBasicTurnHandler(DefaultScript):
|
|||
"""
|
||||
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||
character.db.combat_actionsleft = (
|
||||
0
|
||||
) # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
)
|
||||
character.db.combat_turnhandler = (
|
||||
self
|
||||
) # Add a reference to this turn handler script to the character
|
||||
self # Add a reference to this turn handler script to the character
|
||||
)
|
||||
character.db.combat_lastaction = "null" # Track last action taken in combat
|
||||
|
||||
def start_turn(self, character):
|
||||
|
|
|
|||
|
|
@ -438,11 +438,11 @@ class TBEquipTurnHandler(DefaultScript):
|
|||
"""
|
||||
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||
character.db.combat_actionsleft = (
|
||||
0
|
||||
) # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
)
|
||||
character.db.combat_turnhandler = (
|
||||
self
|
||||
) # Add a reference to this turn handler script to the character
|
||||
self # Add a reference to this turn handler script to the character
|
||||
)
|
||||
character.db.combat_lastaction = "null" # Track last action taken in combat
|
||||
|
||||
def start_turn(self, character):
|
||||
|
|
@ -553,8 +553,8 @@ class TBEWeapon(DefaultObject):
|
|||
self.db.damage_range = (15, 25) # Minimum and maximum damage on hit
|
||||
self.db.accuracy_bonus = 0 # Bonus to attack rolls (or penalty if negative)
|
||||
self.db.weapon_type_name = (
|
||||
"weapon"
|
||||
) # Single word for weapon - I.E. "dagger", "staff", "scimitar"
|
||||
"weapon" # Single word for weapon - I.E. "dagger", "staff", "scimitar"
|
||||
)
|
||||
|
||||
def at_drop(self, dropper):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -718,11 +718,11 @@ class TBItemsTurnHandler(DefaultScript):
|
|||
"""
|
||||
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||
character.db.combat_actionsleft = (
|
||||
0
|
||||
) # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
)
|
||||
character.db.combat_turnhandler = (
|
||||
self
|
||||
) # Add a reference to this turn handler script to the character
|
||||
self # Add a reference to this turn handler script to the character
|
||||
)
|
||||
character.db.combat_lastaction = "null" # Track last action taken in combat
|
||||
|
||||
def start_turn(self, character):
|
||||
|
|
|
|||
|
|
@ -470,11 +470,11 @@ class TBMagicTurnHandler(DefaultScript):
|
|||
"""
|
||||
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||
character.db.combat_actionsleft = (
|
||||
0
|
||||
) # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
)
|
||||
character.db.combat_turnhandler = (
|
||||
self
|
||||
) # Add a reference to this turn handler script to the character
|
||||
self # Add a reference to this turn handler script to the character
|
||||
)
|
||||
character.db.combat_lastaction = "null" # Track last action taken in combat
|
||||
|
||||
def start_turn(self, character):
|
||||
|
|
|
|||
|
|
@ -674,11 +674,11 @@ class TBRangeTurnHandler(DefaultScript):
|
|||
"""
|
||||
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||
character.db.combat_actionsleft = (
|
||||
0
|
||||
) # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||
)
|
||||
character.db.combat_turnhandler = (
|
||||
self
|
||||
) # Add a reference to this turn handler script to the character
|
||||
self # Add a reference to this turn handler script to the character
|
||||
)
|
||||
character.db.combat_lastaction = "null" # Track last action taken in combat
|
||||
|
||||
def start_turn(self, character):
|
||||
|
|
|
|||
|
|
@ -96,6 +96,12 @@ def check_errors(settings):
|
|||
"must now be either None or a dict "
|
||||
"specifying the properties of the channel to create."
|
||||
)
|
||||
if hasattr(settings, "CYCLE_LOGFILES"):
|
||||
raise DeprecationWarning(
|
||||
"settings.CYCLE_LOGFILES is unused and should be removed. "
|
||||
"Use PORTAL/SERVER_LOG_DAY_ROTATION and PORTAL/SERVER_LOG_MAX_SIZE "
|
||||
"to control log cycling."
|
||||
)
|
||||
|
||||
|
||||
def check_warnings(settings):
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,7 @@ def tail_log_files(filename1, filename2, start_lines1=20, start_lines2=20, rate=
|
|||
# this happens if the file was cycled or manually deleted/edited.
|
||||
print(
|
||||
" ** Log file {filename} has cycled or been edited. "
|
||||
"Restarting log. ".format(filehandle.name)
|
||||
"Restarting log. ".format(filename=filehandle.name)
|
||||
)
|
||||
new_linecount = 0
|
||||
old_linecount = 0
|
||||
|
|
|
|||
|
|
@ -213,7 +213,8 @@ application = service.Application("Portal")
|
|||
|
||||
if "--nodaemon" not in sys.argv:
|
||||
logfile = logger.WeeklyLogFile(
|
||||
os.path.basename(settings.PORTAL_LOG_FILE), os.path.dirname(settings.PORTAL_LOG_FILE)
|
||||
os.path.basename(settings.PORTAL_LOG_FILE), os.path.dirname(settings.PORTAL_LOG_FILE),
|
||||
day_rotation=settings.PORTAL_LOG_DAY_ROTATION, max_size=settings.PORTAL_LOG_MAX_SIZE
|
||||
)
|
||||
application.setComponent(ILogObserver, logger.PortalLogObserver(logfile).emit)
|
||||
|
||||
|
|
|
|||
|
|
@ -616,7 +616,8 @@ application = service.Application("Evennia")
|
|||
if "--nodaemon" not in sys.argv:
|
||||
# custom logging, but only if we are not running in interactive mode
|
||||
logfile = logger.WeeklyLogFile(
|
||||
os.path.basename(settings.SERVER_LOG_FILE), os.path.dirname(settings.SERVER_LOG_FILE)
|
||||
os.path.basename(settings.SERVER_LOG_FILE), os.path.dirname(settings.SERVER_LOG_FILE),
|
||||
day_rotation=settings.SERVER_LOG_DAY_ROTATION, max_size=settings.SERVER_LOG_MAX_SIZE
|
||||
)
|
||||
application.setComponent(ILogObserver, logger.ServerLogObserver(logfile).emit)
|
||||
|
||||
|
|
|
|||
|
|
@ -135,17 +135,19 @@ else:
|
|||
break
|
||||
os.chdir(os.pardir)
|
||||
|
||||
# Place to put log files
|
||||
# Place to put log files, how often to rotate the log and how big each log file
|
||||
# may become before rotating.
|
||||
LOG_DIR = os.path.join(GAME_DIR, "server", "logs")
|
||||
SERVER_LOG_FILE = os.path.join(LOG_DIR, "server.log")
|
||||
SERVER_LOG_DAY_ROTATION = 7
|
||||
SERVER_LOG_MAX_SIZE = 1000000
|
||||
PORTAL_LOG_FILE = os.path.join(LOG_DIR, "portal.log")
|
||||
PORTAL_LOG_DAY_ROTATION = 7
|
||||
PORTAL_LOG_MAX_SIZE = 1000000
|
||||
# The http log is usually only for debugging since it's very spammy
|
||||
HTTP_LOG_FILE = os.path.join(LOG_DIR, "http_requests.log")
|
||||
# if this is set to the empty string, lockwarnings will be turned off.
|
||||
LOCKWARNING_LOG_FILE = os.path.join(LOG_DIR, "lockwarnings.log")
|
||||
# Rotate log files when server and/or portal stops. This will keep log
|
||||
# file sizes down. Turn off to get ever growing log files and never
|
||||
# lose log info.
|
||||
CYCLE_LOGFILES = True
|
||||
# Number of lines to append to rotating channel logs when they rotate
|
||||
CHANNEL_LOG_NUM_TAIL_LINES = 20
|
||||
# Max size (in bytes) of channel log files before they rotate
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ log_typemsg(). This is for historical, back-compatible reasons.
|
|||
|
||||
import os
|
||||
import time
|
||||
import glob
|
||||
from datetime import datetime
|
||||
from traceback import format_exc
|
||||
from twisted.python import log, logfile
|
||||
|
|
@ -76,33 +77,78 @@ def timeformat(when=None):
|
|||
|
||||
class WeeklyLogFile(logfile.DailyLogFile):
|
||||
"""
|
||||
Log file that rotates once per week. Overrides key methods to change format
|
||||
Log file that rotates once per week by default. Overrides key methods to change format.
|
||||
|
||||
"""
|
||||
|
||||
day_rotation = 7
|
||||
def __init__(self, name, directory, defaultMode=None, day_rotation=7, max_size=1000000):
|
||||
"""
|
||||
Args:
|
||||
name (str): Name of log file.
|
||||
directory (str): Directory holding the file.
|
||||
defaultMode (str): Permissions used to create file. Defaults to
|
||||
current permissions of this file if it exists.
|
||||
day_rotation (int): How often to rotate the file.
|
||||
max_size (int): Max size of log file before rotation (regardless of
|
||||
time). Defaults to 1M.
|
||||
|
||||
"""
|
||||
self.day_rotation = day_rotation
|
||||
self.max_size = max_size
|
||||
self.size = 0
|
||||
logfile.DailyLogFile.__init__(self, name, directory, defaultMode=defaultMode)
|
||||
|
||||
def _openFile(self):
|
||||
logfile.DailyLogFile._openFile(self)
|
||||
self.size = self._file.tell()
|
||||
|
||||
def shouldRotate(self):
|
||||
"""Rotate when the date has changed since last write"""
|
||||
# all dates here are tuples (year, month, day)
|
||||
now = self.toDate()
|
||||
then = self.lastDate
|
||||
return now[0] > then[0] or now[1] > then[1] or now[2] > (then[2] + self.day_rotation)
|
||||
return (now[0] > then[0] or
|
||||
now[1] > then[1] or
|
||||
now[2] > (then[2] + self.day_rotation) or
|
||||
self.size >= self.max_size)
|
||||
|
||||
def suffix(self, tupledate):
|
||||
"""Return the suffix given a (year, month, day) tuple or unixtime.
|
||||
Format changed to have 03 for march instead of 3 etc (retaining unix file order)
|
||||
Format changed to have 03 for march instead of 3 etc (retaining unix
|
||||
file order)
|
||||
|
||||
If we get duplicate suffixes in location (due to hitting size limit),
|
||||
we append __1, __2 etc.
|
||||
|
||||
Examples:
|
||||
server.log.2020_01_29
|
||||
server.log.2020_01_29__1
|
||||
server.log.2020_01_29__2
|
||||
"""
|
||||
try:
|
||||
return "_".join(["{:02d}".format(part) for part in tupledate])
|
||||
except Exception:
|
||||
# try taking a float unixtime
|
||||
return "_".join(["{:02d}".format(part) for part in self.toDate(tupledate)])
|
||||
suffix = ""
|
||||
copy_suffix = 0
|
||||
while True:
|
||||
try:
|
||||
suffix = "_".join(["{:02d}".format(part) for part in tupledate])
|
||||
except Exception:
|
||||
# try taking a float unixtime
|
||||
suffix = "_".join(["{:02d}".format(part) for part in self.toDate(tupledate)])
|
||||
|
||||
suffix += f"__{copy_suffix}" if copy_suffix else ""
|
||||
|
||||
if os.path.exists(f"{self.path}.{suffix}"):
|
||||
# Append a higher copy_suffix to try to break the tie (starting from 2)
|
||||
copy_suffix += 1
|
||||
else:
|
||||
break
|
||||
return suffix
|
||||
|
||||
|
||||
def write(self, data):
|
||||
"Write data to log file"
|
||||
logfile.BaseLogFile.write(self, data)
|
||||
self.lastDate = max(self.lastDate, self.toDate())
|
||||
self.size += len(data)
|
||||
|
||||
|
||||
class PortalLogObserver(log.FileLogObserver):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue