diff options
-rw-r--r-- | include/filelogger.h | 73 | ||||
-rw-r--r-- | include/logger.h | 90 | ||||
-rw-r--r-- | src/filelogger.cpp | 83 | ||||
-rw-r--r-- | src/helperfuncs.cpp | 4 | ||||
-rw-r--r-- | src/logger.cpp | 146 |
5 files changed, 250 insertions, 146 deletions
diff --git a/include/filelogger.h b/include/filelogger.h index a2d63a0d9..3100761d9 100644 --- a/include/filelogger.h +++ b/include/filelogger.h @@ -14,6 +14,8 @@ #ifndef __LOG_H__ #define __LOG_H__ +#include "logger.h" + /** Debug levels for use with InspIRCd::Log() * */ enum DebugLevel @@ -29,79 +31,14 @@ enum DebugLevel /* Forward declaration -- required */ class InspIRCd; -/** This class implements a nonblocking log-writer. - * Most people writing an ircd give little thought to their disk - * i/o. On a congested system, disk writes can block for long - * periods of time (e.g. if the system is busy and/or swapping - * a lot). If we just use a blocking fprintf() call, this could - * block for undesirable amounts of time (half of a second through - * to whole seconds). We DO NOT want this, so we make our logfile - * nonblocking and hook it into the SocketEngine. - * NB: If the operating system does not support nonblocking file - * I/O (linux seems to, as does freebsd) this will default to - * blocking behaviour. - */ -class CoreExport FileLogger : public EventHandler -{ - protected: - /** The creator/owner of this object - */ - InspIRCd* ServerInstance; - /** The log file (fd is inside this somewhere, - * we get it out with fileno()) - */ - FILE* log; - /** Buffer of pending log lines to be written - */ - std::string buffer; - /** Number of write operations that have occured - */ - int writeops; - public: - /** The constructor takes an already opened logfile. - */ - FileLogger(InspIRCd* Instance, FILE* logfile); - /** This returns false, logfiles are writeable. - */ - virtual bool Readable(); - /** Handle pending write events. - * This will flush any waiting data to disk. - * If any data remains after the fprintf call, - * another write event is scheduled to write - * the rest of the data when possible. - */ - virtual void HandleEvent(EventType et, int errornum = 0); - /** Write one or more preformatted log lines. - * If the data cannot be written immediately, - * this class will insert itself into the - * SocketEngine, and register a write event, - * and when the write event occurs it will - * attempt again to write the data. - */ - void WriteLogLine(const std::string &line); - /** Close the log file and cancel any events. - */ - virtual void Close(); - /** Close the log file and cancel any events. - * (indirectly call Close() - */ - virtual ~FileLogger(); -}; - class CoreExport FileLogStream : public LogStream { private: - FileLogger *f; + FileWriter *f; public: - FileLogStream(InspIRCd *Instance, int loglevel, FILE *f) : LogStream(Instance, loglevel) - { - this->f = new FileLogger(Instance, f); - } + FileLogStream(InspIRCd *Instance, int loglevel, FileWriter *fw); - ~FileLogStream() - { - delete this->f; - } + virtual ~FileLogStream(); virtual void OnLog(int loglevel, const std::string &type, const std::string &msg); }; diff --git a/include/logger.h b/include/logger.h index 8f030b53b..c4729035c 100644 --- a/include/logger.h +++ b/include/logger.h @@ -14,6 +14,65 @@ #ifndef __LOGMANAGER_H #define __LOGMANAGER_H +/** This class implements a nonblocking writer. + * Most people writing an ircd give little thought to their disk + * i/o. On a congested system, disk writes can block for long + * periods of time (e.g. if the system is busy and/or swapping + * a lot). If we just use a blocking fprintf() call, this could + * block for undesirable amounts of time (half of a second through + * to whole seconds). We DO NOT want this, so we make our logfile + * nonblocking and hook it into the SocketEngine. + * NB: If the operating system does not support nonblocking file + * I/O (linux seems to, as does freebsd) this will default to + * blocking behaviour. + */ +class CoreExport FileWriter : public EventHandler +{ + protected: + /** The creator/owner of this object + */ + InspIRCd* ServerInstance; + /** The log file (fd is inside this somewhere, + * we get it out with fileno()) + */ + FILE* log; + /** Buffer of pending log lines to be written + */ + std::string buffer; + /** Number of write operations that have occured + */ + int writeops; + public: + /** The constructor takes an already opened logfile. + */ + FileWriter(InspIRCd* Instance, FILE* logfile); + /** This returns false, logfiles are writeable. + */ + virtual bool Readable(); + /** Handle pending write events. + * This will flush any waiting data to disk. + * If any data remains after the fprintf call, + * another write event is scheduled to write + * the rest of the data when possible. + */ + virtual void HandleEvent(EventType et, int errornum = 0); + /** Write one or more preformatted log lines. + * If the data cannot be written immediately, + * this class will insert itself into the + * SocketEngine, and register a write event, + * and when the write event occurs it will + * attempt again to write the data. + */ + void WriteLogLine(const std::string &line); + /** Close the log file and cancel any events. + */ + virtual void Close(); + /** Close the log file and cancel any events. + * (indirectly call Close() + */ + virtual ~FileWriter(); +}; + class CoreExport LogStream : public classbase { protected: @@ -25,9 +84,13 @@ class CoreExport LogStream : public classbase this->ServerInstance = Instance; } + virtual ~LogStream() { } + virtual void OnLog(int loglevel, const std::string &type, const std::string &msg) { } }; +typedef std::map<FileWriter*, int> FileLogMap; + class CoreExport LogManager : public classbase { private: @@ -35,6 +98,7 @@ class CoreExport LogManager : public classbase InspIRCd *ServerInstance; std::map<std::string, std::vector<LogStream *> > LogStreams; std::vector<LogStream *> GlobalLogStreams; //holds all logstreams with a type of * + FileLogMap FileLogs; /* Holds all file logs, refcounted */ public: LogManager(InspIRCd *Instance) { @@ -42,6 +106,32 @@ class CoreExport LogManager : public classbase Logging = false; } + void AddLoggerRef(FileWriter* fw) + { + FileLogMap::iterator i = FileLogs.find(fw); + if (i == FileLogs.end()) + { + FileLogs.insert(std::make_pair(fw, 1)); + } + else + { + ++i->second; + } + } + + void DelLoggerRef(FileWriter* fw) + { + FileLogMap::iterator i = FileLogs.find(fw); + if (i == FileLogs.end()) return; /* Maybe should log this? */ + if (--i->second < 1) + { + delete i->first; + FileLogs.erase(i); + } + } + + void OpenSingleFile(FILE* f, const std::string& type, int loglevel); + void OpenFileLogs(); void CloseLogs(); bool AddLogType(const std::string &type, LogStream *l); bool DelLogType(const std::string &type, LogStream *l); diff --git a/src/filelogger.cpp b/src/filelogger.cpp index 5c2757520..b0eb77310 100644 --- a/src/filelogger.cpp +++ b/src/filelogger.cpp @@ -19,89 +19,18 @@ #include "inspircd_se_config.h" #include "filelogger.h" -FileLogger::FileLogger(InspIRCd* Instance, FILE* logfile) -: ServerInstance(Instance), log(logfile), writeops(0) +FileLogStream::FileLogStream(InspIRCd *Instance, int loglevel, FileWriter *fw) + : LogStream(Instance, loglevel), f(fw) { - if (log) - { - Instance->SE->NonBlocking(fileno(log)); - SetFd(fileno(log)); - buffer.clear(); - } -} - -bool FileLogger::Readable() -{ - return false; -} - -void FileLogger::HandleEvent(EventType, int) -{ - WriteLogLine(""); - if (log) - ServerInstance->SE->DelFd(this); + ServerInstance->Logs->AddLoggerRef(f); } -void FileLogger::WriteLogLine(const std::string &line) +FileLogStream::~FileLogStream() { - if (line.length()) - buffer.append(line); - - if (log) - { - int written = fprintf(log,"%s",buffer.c_str()); -#ifdef WINDOWS - buffer.clear(); -#else - if ((written >= 0) && (written < (int)buffer.length())) - { - buffer.erase(0, buffer.length()); - ServerInstance->SE->AddFd(this); - } - else if (written == -1) - { - if (errno == EAGAIN) - ServerInstance->SE->AddFd(this); - } - else - { - /* Wrote the whole buffer, and no need for write callback */ - buffer.clear(); - } -#endif - if (writeops++ % 20) - { - fflush(log); - } - } + /* FileWriter is managed externally now */ + ServerInstance->Logs->DelLoggerRef(f); } -void FileLogger::Close() -{ - if (log) - { - ServerInstance->SE->Blocking(fileno(log)); - - if (buffer.size()) - fprintf(log,"%s",buffer.c_str()); - -#ifndef WINDOWS - ServerInstance->SE->DelFd(this); -#endif - - fflush(log); - fclose(log); - } - - buffer.clear(); -} - -FileLogger::~FileLogger() -{ - this->Close(); -} - - void FileLogStream::OnLog(int loglevel, const std::string &type, const std::string &text) { static char TIMESTR[26]; diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 8ae88e752..d325b40aa 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -324,7 +324,9 @@ bool InspIRCd::OpenLog(char**, int) return false; } - FileLogStream *f = new FileLogStream(this, Config->LogLevel, Config->log_file); + FileWriter* fw = new FileWriter(this, Config->log_file); + FileLogStream *f = new FileLogStream(this, Config->LogLevel, fw); + this->Logs->AddLogType("*", f); return true; } diff --git a/src/logger.cpp b/src/logger.cpp index 03c02fe09..1d5111fb7 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -15,6 +15,8 @@ #include "inspircd.h" +#include "filelogger.h" + /* * Suggested implementation... * class LogManager @@ -42,6 +44,61 @@ * */ +void LogManager::OpenFileLogs() +{ + ConfigReader* Conf = new ConfigReader(ServerInstance); + std::map<std::string, FileWriter*> logmap; + std::map<std::string, FileWriter*>::iterator i; + for (int index = 0; index < Conf->Enumerate("log"); ++index) + { + std::string method = Conf->ReadValue("log", "method", index); + if (method != "file") continue; + std::string type = Conf->ReadValue("log", "type", index); + std::string level = Conf->ReadValue("log", "level", index); + int loglevel = DEFAULT; + if (level == "debug") + { + loglevel = DEBUG; + ServerInstance->Config->debugging = true; + } + else if (level == "verbose") + { + loglevel = VERBOSE; + } + else if (level == "default") + { + loglevel = DEFAULT; + } + else if (level == "sparse") + { + loglevel = SPARSE; + } + else if (level == "none") + { + loglevel = NONE; + } + FileWriter* fw; + std::string target = Conf->ReadValue("log", "target", index); + if ((i = logmap.find(target)) == logmap.end()) + { + FILE* f = fopen(target.c_str(), "a"); + fw = new FileWriter(ServerInstance, f); + logmap.insert(std::make_pair(target, fw)); + } + else + { + fw = i->second; + } + FileLogStream* fls = new FileLogStream(ServerInstance, loglevel, fw); + irc::commasepstream css(type); + std::string tok; + while (css.GetToken(tok)) + { + AddLogType(tok, fls); + } + } +} + void LogManager::CloseLogs() { /* @@ -64,6 +121,12 @@ void LogManager::CloseLogs() LogStreams.erase(i); } + /* Now close FileLoggers, for those logstreams that neglected to properly free their stuff. */ + for (FileLogMap::iterator i = FileLogs.begin(); i != FileLogs.end(); ++i) + { + delete i->first; + } + FileLogMap().swap(FileLogs); /* Swap with empty map to clear */ } bool LogManager::AddLogType(const std::string &type, LogStream *l) @@ -172,3 +235,86 @@ void LogManager::Log(const std::string &type, int loglevel, const std::string &m } +FileWriter::FileWriter(InspIRCd* Instance, FILE* logfile) +: ServerInstance(Instance), log(logfile), writeops(0) +{ + if (log) + { + Instance->SE->NonBlocking(fileno(log)); + SetFd(fileno(log)); + buffer.clear(); + } +} + +bool FileWriter::Readable() +{ + return false; +} + +void FileWriter::HandleEvent(EventType, int) +{ + WriteLogLine(""); + if (log) + ServerInstance->SE->DelFd(this); +} + +void FileWriter::WriteLogLine(const std::string &line) +{ + if (line.length()) + buffer.append(line); + + if (log) + { + int written = fprintf(log,"%s",buffer.c_str()); +#ifdef WINDOWS + buffer.clear(); +#else + if ((written >= 0) && (written < (int)buffer.length())) + { + buffer.erase(0, buffer.length()); + ServerInstance->SE->AddFd(this); + } + else if (written == -1) + { + if (errno == EAGAIN) + ServerInstance->SE->AddFd(this); + } + else + { + /* Wrote the whole buffer, and no need for write callback */ + buffer.clear(); + } +#endif + if (writeops++ % 20) + { + fflush(log); + } + } +} + +void FileWriter::Close() +{ + if (log) + { + ServerInstance->SE->Blocking(fileno(log)); + + if (buffer.size()) + fprintf(log,"%s",buffer.c_str()); + +#ifndef WINDOWS + ServerInstance->SE->DelFd(this); +#endif + + fflush(log); + fclose(log); + } + + buffer.clear(); +} + +FileWriter::~FileWriter() +{ + this->Close(); +} + + |