diff options
author | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2010-09-29 20:39:56 +0200 |
---|---|---|
committer | Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer> | 2010-09-29 20:41:41 +0200 |
commit | f438a7bc612e94bfcd1ef2b61a7d5b61ce2eaaa6 (patch) | |
tree | e4be8a023eaecc238c72f2eca9f3883816151863 /src | |
parent | 992cd35b0d1c0e6a6bc543960d6d6720b5429e89 (diff) | |
download | manaserv-f438a7bc612e94bfcd1ef2b61a7d5b61ce2eaaa6.tar.gz manaserv-f438a7bc612e94bfcd1ef2b61a7d5b61ce2eaaa6.tar.bz2 manaserv-f438a7bc612e94bfcd1ef2b61a7d5b61ce2eaaa6.tar.xz manaserv-f438a7bc612e94bfcd1ef2b61a7d5b61ce2eaaa6.zip |
Add log file rotation support based on ExceptionFault's work.
This patch adds options to enable log rotations
base on files size and or change of date.
Note: Zip support will be added in a second commit.
Reviewed-by: CodyMartin, Thorbjorn.
Diffstat (limited to 'src')
-rw-r--r-- | src/account-server/main-account.cpp | 10 | ||||
-rw-r--r-- | src/game-server/main-game.cpp | 10 | ||||
-rw-r--r-- | src/utils/logger.cpp | 154 | ||||
-rw-r--r-- | src/utils/logger.h | 43 | ||||
-rw-r--r-- | src/utils/string.hpp | 14 |
5 files changed, 212 insertions, 19 deletions
diff --git a/src/account-server/main-account.cpp b/src/account-server/main-account.cpp index 23332362..159df4c6 100644 --- a/src/account-server/main-account.cpp +++ b/src/account-server/main-account.cpp @@ -160,6 +160,16 @@ static void initialize() LOG_INFO("Using statistics file: " << statisticsFile); + // Set up the options related to log rotation. + Logger::enableLogRotation(Configuration::getBoolValue("log_enableRotation", + false)); + + Logger::setMaxLogfileSize(Configuration::getValue("log_maxFileSize", + 1024)); + + Logger::setSwitchLogEachDay(Configuration::getBoolValue("log_perDay", + false)); + ResourceManager::initialize(); // Open database diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp index 14e47112..8cd41699 100644 --- a/src/game-server/main-game.cpp +++ b/src/game-server/main-game.cpp @@ -173,6 +173,16 @@ static void initializeServer() LOG_INFO("Using log file: " << logFile); + // Set up the options related to log rotation. + Logger::enableLogRotation(Configuration::getBoolValue("log_enableRotation", + false)); + + Logger::setMaxLogfileSize(Configuration::getValue("log_maxFileSize", + 1024)); + + Logger::setSwitchLogEachDay(Configuration::getBoolValue("log_perDay", + false)); + // --- Initialize the managers // Initialize the slang's and double quotes filter. stringFilter = new utils::StringFilter; diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp index 71f92a88..45a68eb5 100644 --- a/src/utils/logger.cpp +++ b/src/utils/logger.cpp @@ -1,6 +1,7 @@ /* * The Mana Server * Copyright (C) 2004-2010 The Mana World Development Team + * Copyright (C) 2010 The Mana Development Team * * This file is part of The Mana Server. * @@ -19,6 +20,8 @@ */ #include "logger.h" +#include "common/resourcemanager.hpp" +#include "utils/string.hpp" #include <ctime> #include <fstream> @@ -31,11 +34,24 @@ namespace utils { - -static std::ofstream mLogFile; /**< Log file. */ -bool Logger::mHasTimestamp = true; /**< Timestamp flag. */ -bool Logger::mTeeMode = false; /**< Tee mode flag. */ -Logger::Level Logger::mVerbosity = Logger::Info; /**< Verbosity level. */ +/** Log file. */ +static std::ofstream mLogFile; +/** current log filename */ +std::string Logger::mFilename = ""; +/** Timestamp flag. */ +bool Logger::mHasTimestamp = true; +/** Tee mode flag. */ +bool Logger::mTeeMode = false; +/** Verbosity level. */ +Logger::Level Logger::mVerbosity = Logger::Info; +/** Enables logrotation by size of the logfile. */ +bool Logger::mLogRotation = false; +/** Maximum size of current logfile. */ +long Logger::mMaxFileSize = 1024; // 1 Mb +/** Switch log file each day. */ +bool Logger::mSwitchLogEachDay = false; +/** Last call date */ +static std::string mLastCallDate = ""; /** * Gets the current time. @@ -47,29 +63,72 @@ static std::string getCurrentTime() time_t now; tm local; - // get current time_t value + // Get current time_t value time(&now); - // convert time_t to tm struct to break the time into individual - // constituents + // Convert time_t to tm struct to break the time into individual + // constituents. local = *(localtime(&now)); - // stringify the time, the format is: [hh:mm:ss] + // Stringify the time, the format is: [hh-mm-ss] using namespace std; ostringstream os; - os << "[" << setw(2) << setfill('0') << local.tm_hour - << ":" << setw(2) << setfill('0') << local.tm_min - << ":" << setw(2) << setfill('0') << local.tm_sec - << "]"; + os << setw(2) << setfill('0') << local.tm_hour + << "-" << setw(2) << setfill('0') << local.tm_min + << "-" << setw(2) << setfill('0') << local.tm_sec; return os.str(); } +/** + * Gets the current date. + * + * @return the current date as string. + */ +static std::string getCurrentDate() +{ + time_t now; + tm local; + + // Get current time_t value + time(&now); + + // Convert time_t to tm struct to break the time into individual + // constituents. + local = *(localtime(&now)); + + // Stringify the time, the format is: yyyy-mm-dd + using namespace std; + ostringstream os; + os << setw(4) << setfill('0') << (local.tm_year + 1900) + << "-" << setw(2) << setfill('0') << local.tm_mon + << "-" << setw(2) << setfill('0') << local.tm_mday; + + return os.str(); +} + +/** + * Check whether the day has changed since the last call. + * + * @return whether the day has changed. + */ +static bool getDayChanged() +{ + static std::string date = getCurrentDate(); + if (mLastCallDate.compare(date)) + { + // Reset the current date for next call. + mLastCallDate = date; + return true; + } + return false; +} + void Logger::output(std::ostream &os, const std::string &msg, const char *prefix) { if (mHasTimestamp) { - os << getCurrentTime() << ' '; + os << "[" << getCurrentTime() << "]" << ' '; } if (prefix) @@ -80,7 +139,7 @@ void Logger::output(std::ostream &os, const std::string &msg, const char *prefix os << msg << std::endl; } -void Logger::setLogFile(const std::string &logFile) +void Logger::setLogFile(const std::string &logFile, bool append) { // Close the current log file. if (mLogFile.is_open()) @@ -88,8 +147,12 @@ void Logger::setLogFile(const std::string &logFile) mLogFile.close(); } - // Open the file for output and remove the former file contents. - mLogFile.open(logFile.c_str(), std::ios::trunc); + // Open the file for output + // and remove the former file contents depending on the append flag. + mLogFile.open(logFile.c_str(), + append ? std::ios::ate : std::ios::trunc); + mFilename = logFile; + mLastCallDate = getCurrentDate(); if (!mLogFile.is_open()) { @@ -97,7 +160,7 @@ void Logger::setLogFile(const std::string &logFile) } else { - // by default the streams do not throw any exception + // By default the streams do not throw any exception // let std::ios::failbit and std::ios::badbit throw exceptions. mLogFile.exceptions(std::ios::failbit | std::ios::badbit); } @@ -127,6 +190,7 @@ void Logger::output(const std::string &msg, Level atVerbosity) if (open) { output(mLogFile, msg, prefixes[atVerbosity]); + switchLogs(); } if (!open || mTeeMode) @@ -137,4 +201,58 @@ void Logger::output(const std::string &msg, Level atVerbosity) } } +void Logger::switchLogs() +{ + // Handles logswitch if enabled + // and if at least one switch condition permits it. + if (!mLogRotation || (mMaxFileSize <= 0 && !mSwitchLogEachDay)) + return; + + // Update current filesize + long mFileSize = mLogFile.tellp(); + + if ((mFileSize >= mMaxFileSize * 1024) + || (mSwitchLogEachDay && getDayChanged())) + { + // Close logfile, rename it and open a new one + mLogFile.flush(); + mLogFile.close(); + + // Stringify the time, the format is: yyyy-mm-dd_hh-mm-ss-logFilename. + using namespace std; + ostringstream os; + os << getCurrentDate(); + + int fileNum = 1; + std::string newFileName = os.str() + "-" + toString<int>(fileNum) + + "_" + mFilename; + // Keeping a hard limit of 100 files per day. + while (ResourceManager::exists(newFileName) && fileNum < 100) + { + fileNum++; + newFileName = os.str() + "-" + toString<int>(fileNum) + + "_" + mFilename; + } + + if (rename(mFilename.c_str(), newFileName.c_str())) + { + ostringstream errorOs; + errorOs << "Error renaming file: " << mFilename << " to: " + << newFileName << std::endl << "Continuing on the same log file."; + perror(errorOs.str().c_str()); + + // Continue appending on the original file. + setLogFile(mFilename, true); + } + else + { + // Keep the logging after emptying the original log file. + setLogFile(mFilename); + } + + mLogFile << "---- Continue logging from former file " << os.str() + << " ----" << std::endl; + } +} + } // namespace utils diff --git a/src/utils/logger.h b/src/utils/logger.h index 473e0257..ba64b10b 100644 --- a/src/utils/logger.h +++ b/src/utils/logger.h @@ -1,6 +1,7 @@ /* * The Mana Server * Copyright (C) 2004-2010 The Mana World Development Team + * Copyright (C) 2010 The Mana Development Team * * This file is part of The Mana Server. * @@ -88,10 +89,11 @@ class Logger * contents are removed. * * @param logFile the log file name (may include path). + * @param append whether the file is cleaned up before logging in. * * @exception std::ios::failure if the log file could not be opened. */ - static void setLogFile(const std::string &logFile); + static void setLogFile(const std::string &logFile, bool append = false); /** * Add/removes the timestamp. @@ -120,6 +122,31 @@ class Logger { mVerbosity = verbosity; } /** + * Enable logrotation based on the maximum filesize given in + * setMaxLogfileSize. + * + * @param enable Set to true to enable logrotation. + */ + static void enableLogRotation(bool enable = true) + { mLogRotation = enable; } + + /** + * Sets the maximum size of a logfile before logrotation occurs. + * + * @param kiloBytes Maximum size of logfile in bytes. Defaults to 1MB. + */ + static void setMaxLogfileSize(long kiloBytes = 1024) + { mMaxFileSize = kiloBytes; } + + /** + * Sets whether the logfile switches when changing date. + * + * @param switchLogEachDay Keeps whether the parameter is activated. + */ + static void setSwitchLogEachDay(bool switchLogEachDay) + { mSwitchLogEachDay = switchLogEachDay; } + + /** * Logs a generic message. * * @param msg the message to log. @@ -136,6 +163,14 @@ class Logger static bool mHasTimestamp; /**< Timestamp flag. */ static bool mTeeMode; /**< Tee mode flag. */ + static std::string mFilename; /**< Name of the current logfile. */ + /** Enable rotation of logfiles by size. */ + static bool mLogRotation; + /** Maximum size of current logfile in bytes */ + static long mMaxFileSize; + /** Sets whether the logfile switches when changing date. */ + static bool mSwitchLogEachDay; + /** * Logs a generic message. * @@ -147,6 +182,12 @@ class Logger */ static void output(std::ostream &os, const std::string &msg, const char *prefix); + + /** + * Switch the log file based on a maximum size + * and/or and a date change. + */ + static void switchLogs(); }; diff --git a/src/utils/string.hpp b/src/utils/string.hpp index 9f2b4ac6..6127bfed 100644 --- a/src/utils/string.hpp +++ b/src/utils/string.hpp @@ -22,6 +22,7 @@ #define UTILS_STRING_H #include <string> +#include <sstream> namespace utils { @@ -67,6 +68,19 @@ namespace utils * @param str the string to trim spaces off */ void trim(std::string &str); + + /** + * Converts the given value to a string using std::stringstream. + * + * @param arg the value to convert to a string + * @return the string representation of arg + */ + template<typename T> std::string toString(const T &arg) + { + std::stringstream ss; + ss << arg; + return ss.str(); + } } #endif // UTILS_STRING_H |