From 9e0bd8ddc7d371da0de01841751cb8ea5104e26b Mon Sep 17 00:00:00 2001 From: Luca Schlecker Date: Fri, 26 Nov 2021 11:59:45 +0100 Subject: [PATCH 1/2] logger: move prefix and timestamp logic inside the ILogHandler default implementation. Signed-off-by: Luca Schlecker --- include/crow/logging.h | 219 ++++++++++++++++++++++------------------- 1 file changed, 116 insertions(+), 103 deletions(-) diff --git a/include/crow/logging.h b/include/crow/logging.h index 0156d067c..f08884cd6 100644 --- a/include/crow/logging.h +++ b/include/crow/logging.h @@ -1,13 +1,13 @@ #pragma once -#include +#include "crow/settings.h" + #include #include #include #include #include - -#include "crow/settings.h" +#include namespace crow { @@ -30,115 +30,128 @@ namespace crow Critical, }; - class ILogHandler { - public: - virtual void log(std::string message, LogLevel level) = 0; + class ILogHandler + { + public: + virtual void log(std::string message, LogLevel level) = 0; }; - class CerrLogHandler : public ILogHandler { - public: - void log(std::string message, LogLevel /*level*/) override { - std::cerr << message; - } - }; - - class logger { - - private: - // - static std::string timestamp() + class CerrLogHandler : public ILogHandler + { + public: + void log(std::string message, LogLevel level) override + { + std::string prefix; + switch (level) { - char date[32]; - time_t t = time(0); + case LogLevel::Debug: + prefix = "DEBUG "; + break; + case LogLevel::Info: + prefix = "INFO "; + break; + case LogLevel::Warning: + prefix = "WARNING "; + break; + case LogLevel::Error: + prefix = "ERROR "; + break; + case LogLevel::Critical: + prefix = "CRITICAL"; + break; + } + std::cerr << "(" << timestamp() << ") [" << prefix << "] " << message; + } - tm my_tm; + private: + static std::string timestamp() + { + char date[32]; + time_t t = time(0); + + tm my_tm; #if defined(_MSC_VER) || defined(__MINGW32__) - gmtime_s(&my_tm, &t); + gmtime_s(&my_tm, &t); #else - gmtime_r(&t, &my_tm); + gmtime_r(&t, &my_tm); #endif - size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); - return std::string(date, date+sz); - } - - public: - - - logger(std::string prefix, LogLevel level) : level_(level) { - #ifdef CROW_ENABLE_LOGGING - stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; - #endif - - } - ~logger() { - #ifdef CROW_ENABLE_LOGGING - if(level_ >= get_current_log_level()) { - stringstream_ << std::endl; - get_handler_ref()->log(stringstream_.str(), level_); - } - #endif - } - - // - template - logger& operator<<(T const &value) { - - #ifdef CROW_ENABLE_LOGGING - if(level_ >= get_current_log_level()) { - stringstream_ << value; - } - #endif - return *this; - } - - // - static void setLogLevel(LogLevel level) { - get_log_level_ref() = level; - } - - static void setHandler(ILogHandler* handler) { - get_handler_ref() = handler; - } - - static LogLevel get_current_log_level() { - return get_log_level_ref(); - } - - private: - // - static LogLevel& get_log_level_ref() - { - static LogLevel current_level = static_cast(CROW_LOG_LEVEL); - return current_level; - } - static ILogHandler*& get_handler_ref() - { - static CerrLogHandler default_handler; - static ILogHandler* current_handler = &default_handler; - return current_handler; - } - - // - std::ostringstream stringstream_; - LogLevel level_; + size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); + return std::string(date, date + sz); + } }; -} -#define CROW_LOG_CRITICAL \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ - crow::logger("CRITICAL", crow::LogLevel::Critical) -#define CROW_LOG_ERROR \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ - crow::logger("ERROR ", crow::LogLevel::Error) -#define CROW_LOG_WARNING \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ - crow::logger("WARNING ", crow::LogLevel::Warning) -#define CROW_LOG_INFO \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ - crow::logger("INFO ", crow::LogLevel::Info) -#define CROW_LOG_DEBUG \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ - crow::logger("DEBUG ", crow::LogLevel::Debug) + class logger + { + public: + logger(LogLevel level): + level_(level) + { + } + ~logger() + { +#ifdef CROW_ENABLE_LOGGING + if (level_ >= get_current_log_level()) + { + stringstream_ << std::endl; + get_handler_ref()->log(stringstream_.str(), level_); + } +#endif + } + // + template + logger& operator<<(T const& value) + { +#ifdef CROW_ENABLE_LOGGING + if (level_ >= get_current_log_level()) + { + stringstream_ << value; + } +#endif + return *this; + } + + // + static void setLogLevel(LogLevel level) { get_log_level_ref() = level; } + + static void setHandler(ILogHandler* handler) { get_handler_ref() = handler; } + + static LogLevel get_current_log_level() { return get_log_level_ref(); } + + private: + // + static LogLevel& get_log_level_ref() + { + static LogLevel current_level = static_cast(CROW_LOG_LEVEL); + return current_level; + } + static ILogHandler*& get_handler_ref() + { + static CerrLogHandler default_handler; + static ILogHandler* current_handler = &default_handler; + return current_handler; + } + + // + std::ostringstream stringstream_; + LogLevel level_; + }; +} // namespace crow + +#define CROW_LOG_CRITICAL \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ + crow::logger(crow::LogLevel::Critical) +#define CROW_LOG_ERROR \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ + crow::logger(crow::LogLevel::Error) +#define CROW_LOG_WARNING \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ + crow::logger(crow::LogLevel::Warning) +#define CROW_LOG_INFO \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ + crow::logger(crow::LogLevel::Info) +#define CROW_LOG_DEBUG \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ + crow::logger(crow::LogLevel::Debug) From d1b057d3b8aa799a93d6dfcf209a06eb826218b1 Mon Sep 17 00:00:00 2001 From: The-EDev Date: Sat, 27 Nov 2021 17:37:30 +0300 Subject: [PATCH 2/2] Added documentation for creating a custom logger --- docs/guides/logging.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/guides/logging.md b/docs/guides/logging.md index 0e3529779..e5fa7e194 100644 --- a/docs/guides/logging.md +++ b/docs/guides/logging.md @@ -14,7 +14,35 @@ The available log levels are as follows (please not that setting a level will al To set a logLevel, just use `#!cpp app.loglevel(crow::LogLevel::Warning)`, This will not show any debug or info logs. It will however still show error and critical logs.

-Please note that setting the Macro `CROW_ENABLE_DEBUG` during compilation will also set the log level to `Debug`. +!!! note + + Setting the Macro `CROW_ENABLE_DEBUG` during compilation will also set the log level to `Debug` (unless otherwise set using `loglevel()`). + ## Writing a log Writing a log is as simple as `#!cpp CROW_LOG_ << "Hello";` (replace<LOG LEVEL> with the actual level in all caps, so you have `CROW_LOG_WARNING`). + +## Creating A custom logger +Assuming you have an existing logger or Crow's default format just doesn't work for you. Crow allows you to use a custom logger for any log made using the `CROW_LOG_` macro.
+All you need is a class extending `#!cpp crow::ILogHandler` containing the method `#!cpp void log(std::string, crow::LogLevel)`.
+Once you have your custom logger, you need to set it via `#!cpp crow::logger::setHandler(&MyLogger);`. Here's a full example:
+```cpp +class CustomLogger : public crow::ILogHandler { + public: + CustomLogger() {} + void log(std::string message, crow::LogLevel /*level*/) { + // "message" doesn't contain the timestamp and loglevel prefix the default + // logger does and it ends with a std::endl. + std::cerr << message; + } +}; + +int main(int argc, char** argv) { + CustomLogger logger; + crow::logger::setHandler(&logger); + + crow::SimpleApp app; + CROW_ROUTE(app, "/")([]() { return "Hello"; }); + app.run(); +} +```