inspircd/include/logging.h

386 lines
11 KiB
C
Raw Permalink Normal View History

/*
* InspIRCd -- Internet Relay Chat Daemon
*
2025-02-28 13:42:05 +00:00
* Copyright (C) 2022-2025 Sadie Powell <sadie@witchery.services>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace Log
{
class Method;
class FileMethod;
class Engine;
class FileEngine;
class StreamEngine;
class Manager;
/** A shared pointer to a log method. */
typedef std::shared_ptr<Method> MethodPtr;
/** Levels at which messages can be logged. */
enum class Level
: uint8_t
{
/** A critical message which must be investigated. */
CRITICAL = 0,
/** An important message which should be investigated. */
WARNING = 1,
/** A general message which is useful to have on record. */
NORMAL = 2,
/** A debug message that we might want to store when testing. */
DEBUG = 3,
/** A sensitive message that we should not store lightly. */
RAWIO = 4,
/** The lowest log level supported. */
LOWEST = CRITICAL,
/** The highest log level supported. */
HIGHEST = RAWIO,
};
/** Converts a log level to a string.
* @param level The log level to convert.
*/
CoreExport const char* LevelToString(Level level);
2023-01-22 22:49:15 +00:00
/** Notify a user that raw I/O logging is enabled.
* @param user The user to notify.
* @param type The type of message to send.
*/
CoreExport void NotifyRawIO(LocalUser* user, MessageType type);
}
/** Base class for logging methods. */
class CoreExport Log::Method
{
protected:
Method() = default;
public:
virtual ~Method() = default;
/** Determines whether this logging method accepts cached messages. */
virtual bool AcceptsCachedMessages() const { return true; }
/** Writes a message to the logger.
* @param time The time at which the message was logged.
* @param level The level at which the log message was written.
* @param type The component which wrote the log message.
* @param message The message which was written to the log.
*/
virtual void OnLog(time_t time, Level level, const std::string& type, const std::string& message) = 0;
};
/** A logger that writes to a file stream. */
class CoreExport Log::FileMethod final
: public Method
, public Timer
{
private:
/** Whether to autoclose the file on exit. */
bool autoclose;
/** The file to which the log is written. */
FILE* file;
/** How often the file stream should be flushed. */
const unsigned long flush;
/** The number of lines which have been written since the file stream was created. */
unsigned long lines = 0;
/** The name the underlying file. */
const std::string name;
public:
FileMethod(const std::string& n, FILE* fh, unsigned long fl, bool ac);
~FileMethod() override;
/** @copydoc Log::Method::AcceptsCachedMessages */
bool AcceptsCachedMessages() const override { return false; }
/** @copydoc Timer::Tick */
bool Tick() override;
/** @copydoc Log::Method::OnLog */
void OnLog(time_t time, Level level, const std::string& type, const std::string& message) override;
};
/** Base class for logging engines. */
class CoreExport Log::Engine
: public DataProvider
{
protected:
Engine(Module* Creator, const std::string& Name);
public:
virtual ~Engine() override;
/** Creates a new logger from the specified config.
* @param tag The config tag to configure the logger with.
*/
virtual MethodPtr Create(const std::shared_ptr<ConfigTag>& tag) = 0;
};
/** A logger which writes to a file. */
class CoreExport Log::FileEngine final
: public Engine
{
public:
FileEngine(Module* Creator);
/** @copydoc Log::Engine::Create */
MethodPtr Create(const std::shared_ptr<ConfigTag>& tag) override;
};
/** A logger which writes to a stream. */
class CoreExport Log::StreamEngine final
: public Engine
{
private:
FILE* file;
public:
StreamEngine(Module* Creator, const std::string& Name, FILE* fh);
/** @copydoc Log::Engine::Create */
MethodPtr Create(const std::shared_ptr<ConfigTag>& tag) override;
};
/** Manager for the logging system. */
class CoreExport Log::Manager final
{
private:
/** A log message which has been cached until modules load. */
struct CachedMessage final
{
/** The time the message was logged at. */
time_t time;
/** The level the message was logged at. */
Level level;
/** The type of the message that was logged. */
std::string type;
/** The message that was logged. */
std::string message;
CachedMessage(time_t ts, Level l, const std::string& t, const std::string& m);
};
/** Encapsulates information about a logger. */
struct Info final
{
/** Whether the logger was read from the server config. */
bool config;
/** Whether this logger is dead and is awaiting removal. */
bool dead = false;
/** The minimum log level that this logger accepts. */
Level level;
/** The types of log message that this logger accepts. */
TokenList types;
/** The handler for this logger type. */
MethodPtr method;
/** The engine which created this logger. */
const Engine* engine;
Info(Level l, TokenList t, MethodPtr m, bool c, const Engine* e) ATTR_NOT_NULL(6);
/** Determines whether a message of the specified level and type should be written to this logger.
* @param l The level to check
* @param t The type to check.
*/
bool Suitable(Level l, const std::string& t) const;
};
/** The log messages we have cached for modules. */
std::vector<CachedMessage> cache;
/** Whether we have just started up and need to cache messages until modules are loaded. */
bool caching = true;
/** The logger engine that writes to a file. */
Log::FileEngine filelog;
/** A logger that writes to stderr. */
Log::StreamEngine stderrlog;
/** A logger that writes to stdout. */
Log::StreamEngine stdoutlog;
/** The currently registered loggers. */
std::vector<Info> loggers;
/** Whether we are currently logging to a file. */
bool logging = false;
/** The highest level that loggers will accept. */
Log::Level maxlevel = Level::HIGHEST;
/** Check for the highest log level and warn about raw logging */
void CheckLevel();
/** Writes a message to the server log.
* @param level The level to log at.
* @param type The type of message that is being logged.
* @param message The message to log.
*/
void Write(Level level, const std::string& type, const std::string& message);
template <typename... Args>
void Write(Level level, const std::string& type, const char* format, Args&&... args)
{
if (maxlevel < level && !caching)
return; // No loggers care about this message.
Write(level, type, fmt::vformat(format, fmt::make_format_args(args...)));
}
public:
Manager();
/** Closes all loggers which were opened from the config. */
void CloseLogs();
/** Enables writing rawio logs to the standard output stream. */
void EnableDebugMode();
/** Opens loggers that are specified in the config. */
void OpenLogs(bool requiremethods);
/** Registers the core logging services with the event system. */
void RegisterServices();
/** Unloads all loggers that are provided by the specified engine.
* @param engine The engine to unload the loggers of.
*/
void UnloadEngine(const Engine* engine) ATTR_NOT_NULL(2);
/** Writes an critical message to the server log.
* @param type The type of message that is being logged.
2022-05-02 17:31:57 +01:00
* @param message The message to log.
*/
inline void Critical(const std::string& type, const std::string& message)
{
Write(Level::CRITICAL, type, message);
}
/** Writes an critical message to the server log.
* @param type The type of message that is being logged.
* @param format A format string to format and then log.
* @param args One or more arguments to format the string with.
*/
template <typename... Args>
void Critical(const std::string& type, const char* format, Args&&... args)
{
Write(Level::CRITICAL, type, format, std::forward<Args>(args)...);
}
/** Writes a warning message to the server log.
* @param type The type of message that is being logged.
2022-05-02 17:31:57 +01:00
* @param message The message to log.
*/
inline void Warning(const std::string& type, const std::string& message)
{
Write(Level::WARNING, type, message);
}
/** Writes a warning message to the server log.
* @param type The type of message that is being logged.
* @param format A format string to format and then log.
* @param args One or more arguments to format the string with.
*/
template <typename... Args>
void Warning(const std::string& type, const char* format, Args&&... args)
{
Write(Level::WARNING, type, format, std::forward<Args>(args)...);
}
/** Writes a normal message to the server log.
* @param type The type of message that is being logged.
2022-05-02 17:31:57 +01:00
* @param message The message to log.
*/
inline void Normal(const std::string& type, const std::string& message)
{
Write(Level::NORMAL, type, message);
}
/** Writes a normal message to the server log.
* @param type The type of message that is being logged.
* @param format A format string to format and then log.
* @param args One or more arguments to format the string with.
*/
template <typename... Args>
void Normal(const std::string& type, const char* format, Args&&... args)
{
Write(Level::NORMAL, type, format, std::forward<Args>(args)...);
}
/** Writes a debug message to the server log.
* @param type The type of message that is being logged.
2022-05-02 17:31:57 +01:00
* @param message The message to log.
*/
inline void Debug(const std::string& type, const std::string& message)
{
Write(Level::DEBUG, type, message);
}
/** Writes a debug message to the server log.
* @param type The type of message that is being logged.
* @param format A format string to format and then log.
* @param args One or more arguments to format the string with.
*/
template <typename... Args>
void Debug(const std::string& type, const char* format, Args&&... args)
{
Write(Level::DEBUG, type, format, std::forward<Args>(args)...);
}
/** Writes a raw I/O message to the server log.
* @param type The type of message that is being logged.
2022-05-02 17:31:57 +01:00
* @param message The message to log.
*/
inline void RawIO(const std::string& type, const std::string& message)
{
Write(Level::RAWIO, type, message);
}
/** Writes a raw I/O message to the server log.
* @param type The type of message that is being logged.
* @param format A format string to format and then log.
* @param args One or more arguments to format the string with.
*/
template <typename... Args>
void RawIO(const std::string& type, const char* format, Args&&... args)
{
Write(Level::RAWIO, type, format, std::forward<Args>(args)...);
}
};