diff --git a/evennia/settings_default.py b/evennia/settings_default.py index c5844205c..f94bf5d3e 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -125,6 +125,10 @@ LOCKWARNING_LOG_FILE = os.path.join(LOG_DIR, 'lockwarnings.log') # file sizes down. Turn off to get ever growing log files and never # loose 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 of channel log files before they rotate +CHANNEL_LOG_ROTATE_SIZE = 1000000 # Local time zone for this installation. All choices can be found here: # http://www.postgresql.org/docs/8.0/interactive/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE TIME_ZONE = 'UTC' diff --git a/evennia/utils/logger.py b/evennia/utils/logger.py index a46c549de..adf960d04 100644 --- a/evennia/utils/logger.py +++ b/evennia/utils/logger.py @@ -19,7 +19,7 @@ import os import time from datetime import datetime from traceback import format_exc -from twisted.python import log +from twisted.python import log, logfile from twisted.internet.threads import deferToThread @@ -153,6 +153,53 @@ log_depmsg = log_dep # Arbitrary file logger +class EvenniaLogFile(logfile.LogFile): + """ + A rotating logfile based off Twisted's LogFile. It overrides + the LogFile's rotate method in order to append some of the last + lines of the previous log to the start of the new log, in order + to preserve a continuous chat history for channel log files. + """ + from django.conf import settings + num_lines_to_append = settings.CHANNEL_LOG_NUM_TAIL_LINES + + def rotate(self): + """ + Rotates our log file and appends some number of lines from + the previous log to the start of the new one. + """ + append_tail = self.num_lines_to_append > 0 + if not append_tail: + logfile.LogFile.rotate(self) + return + lines = tail_log_file(self.path, 0, self.num_lines_to_append) + logfile.LogFile.rotate(self) + for line in lines: + self.write(line) + + def seek(self, *args, **kwargs): + """ + Convenience method for accessing our _file attribute's seek method, + which is used in tail_log_function. + Args: + *args: Same args as file.seek + **kwargs: Same kwargs as file.seek + """ + return self._file.seek(*args, **kwargs) + + def readlines(self, *args, **kwargs): + """ + Convenience method for accessing our _file attribute's readlines method, + which is used in tail_log_function. + Args: + *args: same args as file.readlines + **kwargs: same kwargs as file.readlines + + Returns: + lines (list): lines from our _file attribute. + """ + return self._file.readlines(*args, **kwargs) + _LOG_FILE_HANDLES = {} # holds open log handles @@ -162,9 +209,9 @@ def _open_log_file(filename): handle. Will create a new file in the log dir if one didn't exist. """ + from django.conf import settings global _LOG_FILE_HANDLES, _LOGDIR if not _LOGDIR: - from django.conf import settings _LOGDIR = settings.LOG_DIR filename = os.path.join(_LOGDIR, filename) @@ -173,7 +220,8 @@ def _open_log_file(filename): return _LOG_FILE_HANDLES[filename] else: try: - filehandle = open(filename, "a+") # append mode + reading + filehandle = EvenniaLogFile.fromFullPath(filename, rotateLength=settings.CHANNEL_LOG_ROTATE_SIZE) + # filehandle = open(filename, "a+") # append mode + reading _LOG_FILE_HANDLES[filename] = filehandle return filehandle except IOError: