diff options
-rw-r--r-- | include/filelogger.h | 98 | ||||
-rw-r--r-- | src/filelogger.cpp | 108 |
2 files changed, 206 insertions, 0 deletions
diff --git a/include/filelogger.h b/include/filelogger.h new file mode 100644 index 000000000..ab92e8cde --- /dev/null +++ b/include/filelogger.h @@ -0,0 +1,98 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + +#include <time.h> +#include <string> +#include <sstream> +#include "socketengine.h" + + +/** Debug levels for use with InspIRCd::Log() + * */ +enum DebugLevel +{ + DEBUG = 10, + VERBOSE = 20, + DEFAULT = 30, + SPARSE = 40, + NONE = 50 +}; + + +/* 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(); +}; + + +#endif diff --git a/src/filelogger.cpp b/src/filelogger.cpp new file mode 100644 index 000000000..5fcd58f15 --- /dev/null +++ b/src/filelogger.cpp @@ -0,0 +1,108 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2007 InspIRCd Development Team + * See: http://www.inspircd.org/wiki/index.php/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include <time.h> +#include <string> +#include <sstream> +#include <fstream> +#include "socketengine.h" +#include "inspircd_se_config.h" +#include "filelogger.h" + +FileLogger::FileLogger(InspIRCd* Instance, FILE* logfile) +: ServerInstance(Instance), log(logfile), writeops(0) +{ + if (log) + { + irc::sockets::NonBlocking(fileno(log)); + SetFd(fileno(log)); + buffer.clear(); + } +} + +bool FileLogger::Readable() +{ + return false; +} + +void FileLogger::HandleEvent(EventType et, int errornum) +{ + WriteLogLine(""); + if (log) + ServerInstance->SE->DelFd(this); +} + +void FileLogger::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 FileLogger::Close() +{ + if (log) + { + /* Burlex: Windows assumes nonblocking on FILE* pointers anyway, and also "file" fd's aren't the same + * as socket fd's. + */ +#ifndef WIN32 + int flags = fcntl(fileno(log), F_GETFL, 0); + fcntl(fileno(log), F_SETFL, flags ^ O_NONBLOCK); +#endif + 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(); +} + |