Files
eepp/include/eepp/system/log.hpp
2025-08-22 01:33:51 -03:00

238 lines
7.5 KiB
C++

#ifndef EE_SYSTEM_LOG_H
#define EE_SYSTEM_LOG_H
#include <eepp/system/iostreamfile.hpp>
#include <eepp/system/mutex.hpp>
#include <eepp/system/singleton.hpp>
#include <eepp/system/sys.hpp>
#include <unordered_map>
namespace EE { namespace System {
/** @brief The reader interface is useful if you want to keep track of what is write in the log, for
* example for a console. */
class LogReaderInterface {
public:
virtual void writeLog( const std::string_view& Text ) = 0;
};
enum class LogLevel : int {
Debug, ///< Detailed debug information.
Info, ///< Interesting events in your application.
Notice, ///< Normal, but significant events in your application.
Warning, ///< Exceptional occurrences that are not errors.
Error, ///< Runtime errors that do not require immediate action but should typically be
///< logged and monitored.
Critical, ///< Critical conditions.
Assert, ///< Asserted critical condition.
};
/** @brief Global log file. The engine will log everything in this file. */
class EE_API Log : protected Mutex {
SINGLETON_DECLARE_HEADERS( Log )
public:
static std::unordered_map<std::string, LogLevel> getMapFlag();
static constexpr LogLevel getDefaultLogLevel() {
#ifdef EE_DEBUG
return LogLevel::Debug;
#else
return LogLevel::Info;
#endif
}
static Log* create( const std::string& logPath, const LogLevel& level, bool stdOutLog,
bool liveWrite );
static Log* create( const LogLevel& level, bool stdOutLog, bool liveWrite );
virtual ~Log();
/** @brief Indicates that the log must be written to a file when the Log instance is closed.
** @param filepath The path to the file to write the log.
*/
void save( const std::string& filepath = "" );
/** @brief Writes the text to the log
** @param text The text to write */
void write( const std::string_view& text );
/** @brief Writes the text to the log with a log level.
** @param level The log level that will try to write.
** @param text The text to write */
void write( const LogLevel& level, const std::string_view& text );
/** @brief Writes the text to the log and appends a new line character at the end.
** @param text The text to write */
void writel( const std::string_view& text );
/** @brief Writes the text to the log and appends a new line character at the end with a log
*level.
** @param levelThe log level that will try to write.
** @param text The text to write */
void writel( const LogLevel& level, const std::string_view& text );
/** @brief Writes a formatted string to the log with a log level.
** @param level The log level that will try to write.
** @param format The Text format.
*/
template <typename... Args>
void writef( const LogLevel& level, std::string_view format, Args&&... args ) {
if ( mLogLevelThreshold > level )
return;
auto result = String::format(
format, FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
write( logLevelWithTimestamp( level, result, true ) );
}
/** @brief Writes a formatted string to the log */
template <typename... Args>
void writef( std::string_view format, Args&&... args ) {
auto result = String::format(
format, FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
write( result );
write( "\n" );
}
/** @returns A reference of the current written log. */
const std::string& getBuffer() const;
/** @returns If the log Writes are outputted to stdout. */
const bool& isLoggingToStdOut() const;
/** @brief Enabled or disables to output the Writes to stdout. */
void setLogToStdOut( const bool& output );
/** @returns If the file is forced to flush the data on every Write call. */
const bool& isLiveWrite() const;
/** @brief Activate or deactivate to flush the written data to the log on every Write call. */
void setLiveWrite( const bool& lw );
/** @brief Adds a reader interface.
** The reader interface is used to the informed for every written text to the log.
*/
void addLogReader( LogReaderInterface* reader );
/** @brief Removes the reader interface */
void removeLogReader( LogReaderInterface* reader );
/** @return The log level threshold. */
const LogLevel& getLogLevelThreshold() const;
/** Sets the log level threshold. This is the minimum level that message will actually be
* logged. */
void setLogLevelThreshold( const LogLevel& logLevelThreshold );
/** @return The file path of the log file (if any). */
const std::string& getFilePath() const;
/** Sets the file path of the log file. */
void setFilePath( const std::string& filePath );
/** @return True if the logs are being buffered in memory */
bool getKeepLog() const;
/** Enable/Disable to keep a copy of the logs into memory (disabled by default) */
void setKeepLog( bool keepLog );
static void debug( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Debug, text );
}
static void info( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Info, text );
}
static void notice( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Notice, text );
}
static void warning( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Warning, text );
}
static void error( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Error, text );
}
static void critical( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Critical, text );
}
static void assertLog( const std::string_view& text ) {
Log::instance()->writel( LogLevel::Assert, text );
}
template <class... Args> static void debug( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Debug, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void info( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Info, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void notice( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Notice, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void warning( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Warning, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void error( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Error, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void critical( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Critical, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
template <class... Args> static void assertLog( const char* format, Args&&... args ) {
Log::instance()->writef(
LogLevel::Assert, format,
FormatArg<std::decay_t<Args>>::get( std::forward<Args>( args ) )... );
}
protected:
Log();
Log( const std::string& logPath, const LogLevel& level, bool stdOutLog, bool liveWrite );
std::string mData;
std::string mFilePath;
bool mSave;
bool mStdOutEnabled;
bool mLiveWrite;
bool mKeepLog{ false };
LogLevel mLogLevelThreshold{ getDefaultLogLevel() };
IOStreamFile* mFS;
std::vector<LogReaderInterface*> mReaders;
void openFS();
void closeFS();
void writeToReaders( const std::string_view& text );
std::string logLevelWithTimestamp( const LogLevel& level, const std::string_view& text,
bool appendNewLine );
};
}} // namespace EE::System
#endif