Merge branch 'master' into gcc8-workaround

This commit is contained in:
Farook Al-Sammarraie 2021-11-27 18:14:44 +03:00 committed by GitHub
commit 62b74a1c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 145 additions and 104 deletions

View File

@ -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.<br><br> 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.<br><br>
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
Writing a log is as simple as `#!cpp CROW_LOG_<LOG LEVEL> << "Hello";` (replace&lt;LOG LEVEL&gt; with the actual level in all caps, so you have `CROW_LOG_WARNING`). Writing a log is as simple as `#!cpp CROW_LOG_<LOG LEVEL> << "Hello";` (replace&lt;LOG LEVEL&gt; 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_<LOG LEVEL>` macro.<br>
All you need is a class extending `#!cpp crow::ILogHandler` containing the method `#!cpp void log(std::string, crow::LogLevel)`.<br>
Once you have your custom logger, you need to set it via `#!cpp crow::logger::setHandler(&MyLogger);`. Here's a full example:<br>
```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();
}
```

View File

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <string> #include "crow/settings.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string>
#include "crow/settings.h"
namespace crow namespace crow
{ {
@ -30,115 +30,128 @@ namespace crow
Critical, Critical,
}; };
class ILogHandler { class ILogHandler
public: {
virtual void log(std::string message, LogLevel level) = 0; public:
virtual void log(std::string message, LogLevel level) = 0;
}; };
class CerrLogHandler : public ILogHandler { class CerrLogHandler : public ILogHandler
public: {
void log(std::string message, LogLevel /*level*/) override { public:
std::cerr << message; void log(std::string message, LogLevel level) override
} {
}; std::string prefix;
switch (level)
class logger {
private:
//
static std::string timestamp()
{ {
char date[32]; case LogLevel::Debug:
time_t t = time(0); 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__) #if defined(_MSC_VER) || defined(__MINGW32__)
gmtime_s(&my_tm, &t); gmtime_s(&my_tm, &t);
#else #else
gmtime_r(&t, &my_tm); gmtime_r(&t, &my_tm);
#endif #endif
size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm);
return std::string(date, date+sz); 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 <typename T>
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<LogLevel>(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_;
}; };
}
#define CROW_LOG_CRITICAL \ class logger
if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ {
crow::logger("CRITICAL", crow::LogLevel::Critical) public:
#define CROW_LOG_ERROR \ logger(LogLevel level):
if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ level_(level)
crow::logger("ERROR ", crow::LogLevel::Error) {
#define CROW_LOG_WARNING \ }
if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ ~logger()
crow::logger("WARNING ", crow::LogLevel::Warning) {
#define CROW_LOG_INFO \ #ifdef CROW_ENABLE_LOGGING
if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ if (level_ >= get_current_log_level())
crow::logger("INFO ", crow::LogLevel::Info) {
#define CROW_LOG_DEBUG \ stringstream_ << std::endl;
if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ get_handler_ref()->log(stringstream_.str(), level_);
crow::logger("DEBUG ", crow::LogLevel::Debug) }
#endif
}
//
template<typename T>
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<LogLevel>(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)