From 32f725d32f8e15f9bd4d0607251ede14c38fd993 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 22 Jun 2019 14:42:48 +0000 Subject: [PATCH] Properly format multiline logs As a side effect, colouring on Windows should now work regardless of version --- contrib/epee/include/misc_log_ex.h | 42 +++--- contrib/epee/src/mlog.cpp | 38 ++++- external/easylogging++/easylogging++.cc | 130 ++++++++++++++---- external/easylogging++/easylogging++.h | 48 ++++--- src/common/perf_timer.cpp | 2 +- src/cryptonote_core/cryptonote_core.cpp | 2 +- .../cryptonote_protocol_handler.inl | 4 +- tests/unit_tests/logging.cpp | 17 +++ 8 files changed, 217 insertions(+), 66 deletions(-) diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 602b6a371..0b216f2c4 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -38,29 +38,29 @@ #define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes #define MAX_LOG_FILES 50 -#define MCLOG_TYPE(level, cat, type, x) do { \ +#define MCLOG_TYPE(level, cat, color, type, x) do { \ if (ELPP->vRegistry()->allowed(level, cat)) { \ - el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \ + el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \ } \ } while (0) -#define MCLOG(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::NormalLog, x) -#define MCLOG_FILE(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::FileOnlyLog, x) +#define MCLOG(level, cat, color, x) MCLOG_TYPE(level, cat, color, el::base::DispatchAction::NormalLog, x) +#define MCLOG_FILE(level, cat, x) MCLOG_TYPE(level, cat, el::Color::Default, el::base::DispatchAction::FileOnlyLog, x) -#define MCFATAL(cat,x) MCLOG(el::Level::Fatal,cat, x) -#define MCERROR(cat,x) MCLOG(el::Level::Error,cat, x) -#define MCWARNING(cat,x) MCLOG(el::Level::Warning,cat, x) -#define MCINFO(cat,x) MCLOG(el::Level::Info,cat, x) -#define MCDEBUG(cat,x) MCLOG(el::Level::Debug,cat, x) -#define MCTRACE(cat,x) MCLOG(el::Level::Trace,cat, x) +#define MCFATAL(cat,x) MCLOG(el::Level::Fatal,cat, el::Color::Default, x) +#define MCERROR(cat,x) MCLOG(el::Level::Error,cat, el::Color::Default, x) +#define MCWARNING(cat,x) MCLOG(el::Level::Warning,cat, el::Color::Default, x) +#define MCINFO(cat,x) MCLOG(el::Level::Info,cat, el::Color::Default, x) +#define MCDEBUG(cat,x) MCLOG(el::Level::Debug,cat, el::Color::Default, x) +#define MCTRACE(cat,x) MCLOG(el::Level::Trace,cat, el::Color::Default, x) -#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m") -#define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x) -#define MCLOG_GREEN(level,cat,x) MCLOG_COLOR(level,cat,"32",x) -#define MCLOG_YELLOW(level,cat,x) MCLOG_COLOR(level,cat,"33",x) -#define MCLOG_BLUE(level,cat,x) MCLOG_COLOR(level,cat,"34",x) -#define MCLOG_MAGENTA(level,cat,x) MCLOG_COLOR(level,cat,"35",x) -#define MCLOG_CYAN(level,cat,x) MCLOG_COLOR(level,cat,"36",x) +#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,color,x) +#define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Red,x) +#define MCLOG_GREEN(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Green,x) +#define MCLOG_YELLOW(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Yellow,x) +#define MCLOG_BLUE(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Blue,x) +#define MCLOG_MAGENTA(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Magenta,x) +#define MCLOG_CYAN(level,cat,x) MCLOG_COLOR(level,cat,el::Color::Cyan,x) #define MLOG_RED(level,x) MCLOG_RED(level,MONERO_DEFAULT_LOG_CATEGORY,x) #define MLOG_GREEN(level,x) MCLOG_GREEN(level,MONERO_DEFAULT_LOG_CATEGORY,x) @@ -75,7 +75,7 @@ #define MINFO(x) MCINFO(MONERO_DEFAULT_LOG_CATEGORY,x) #define MDEBUG(x) MCDEBUG(MONERO_DEFAULT_LOG_CATEGORY,x) #define MTRACE(x) MCTRACE(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG(level,x) MCLOG(level,MONERO_DEFAULT_LOG_CATEGORY,x) +#define MLOG(level,x) MCLOG(level,MONERO_DEFAULT_LOG_CATEGORY,el::Color::Default,x) #define MGINFO(x) MCINFO("global",x) #define MGINFO_RED(x) MCLOG_RED(el::Level::Info, "global",x) @@ -85,14 +85,14 @@ #define MGINFO_MAGENTA(x) MCLOG_MAGENTA(el::Level::Info, "global",x) #define MGINFO_CYAN(x) MCLOG_CYAN(el::Level::Info, "global",x) -#define IFLOG(level, cat, type, init, x) \ +#define IFLOG(level, cat, color, type, init, x) \ do { \ if (ELPP->vRegistry()->allowed(level, cat)) { \ init; \ - el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \ + el::base::Writer(level, color, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \ } \ } while(0) -#define MIDEBUG(init, x) IFLOG(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY, el::base::DispatchAction::NormalLog, init, x) +#define MIDEBUG(init, x) IFLOG(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY, el::Color::Default, el::base::DispatchAction::NormalLog, init, x) #define LOG_ERROR(x) MERROR(x) diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index 4c6ad5516..0cf579840 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -109,7 +109,7 @@ static const char *get_default_categories(int level) categories = "*:DEBUG"; break; case 3: - categories = "*:TRACE"; + categories = "*:TRACE,*.dump:DEBUG"; break; case 4: categories = "*:TRACE"; @@ -472,4 +472,40 @@ void reset_console_color() { } +static void mlog(el::Level level, const char *category, const char *format, va_list ap) +{ + int size = 0; + char *p = NULL; + va_list apc; + + /* Determine required size */ + va_copy(apc, ap); + size = vsnprintf(p, size, format, apc); + va_end(apc); + if (size < 0) + return; + + size++; /* For '\0' */ + p = (char*)malloc(size); + if (p == NULL) + return; + + size = vsnprintf(p, size, format, ap); + if (size < 0) + { + free(p); + return; + } + + MCLOG(level, category, el::Color::Default, p); + free(p); +} + +void mfatal(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Fatal, category, fmt, ap); va_end(ap); } +void merror(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Error, category, fmt, ap); va_end(ap); } +void mwarning(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Warning, category, fmt, ap); va_end(ap); } +void minfo(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Info, category, fmt, ap); va_end(ap); } +void mdebug(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Debug, category, fmt, ap); va_end(ap); } +void mtrace(const char *category, const char *fmt, ...) { va_list ap; va_start(ap, fmt); mlog(el::Level::Trace, category, fmt, ap); va_end(ap); } + #endif //_MLOG_H_ diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc index 2b4c7bbbf..a5a4a64b7 100644 --- a/external/easylogging++/easylogging++.cc +++ b/external/easylogging++/easylogging++.cc @@ -18,6 +18,7 @@ #include "easylogging++.h" #include +#include #if defined(AUTO_INITIALIZE_EASYLOGGINGPP) INITIALIZE_EASYLOGGINGPP @@ -133,6 +134,50 @@ static void abort(int status, const std::string& reason) { #endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) } +static el::Color colorFromLevel(el::Level level) +{ + switch (level) + { + case Level::Error: case Level::Fatal: return el::Color::Red; + case Level::Warning: return el::Color::Yellow; + case Level::Debug: return el::Color::Green; + case Level::Info: return el::Color::Cyan; + case Level::Trace: return el::Color::Magenta; + default: return el::Color::Default; + } +} + +static void setConsoleColor(el::Color color, bool bright) +{ +#if ELPP_OS_WINDOWS + HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); + switch (color) + { + case el::Color::Red: SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Green: SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Yellow: SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Blue: SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Magenta: SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Cyan: SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); break; + case el::Color::Default: default: SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0)); break; + } +#else + if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) + { + switch (color) + { + case el::Color::Red: ELPP_COUT << (bright ? "\033[1;31m" : "\033[0;31m"); break; + case el::Color::Green: ELPP_COUT << (bright ? "\033[1;32m" : "\033[0;32m"); break; + case el::Color::Yellow: ELPP_COUT << (bright ? "\033[1;33m" : "\033[0;33m"); break; + case el::Color::Blue: ELPP_COUT << (bright ? "\033[1;34m" : "\033[0;34m"); break; + case el::Color::Magenta: ELPP_COUT << (bright ? "\033[1;35m" : "\033[0;35m"); break; + case el::Color::Cyan: ELPP_COUT << (bright ? "\033[1;36m" : "\033[0;36m"); break; + case el::Color::Default: default: ELPP_COUT << "\033[0m"; break; + } + } +#endif +} + } // namespace utils } // namespace base @@ -609,19 +654,34 @@ void Configurations::unsafeSetGlobally(ConfigurationType configurationType, cons // LogBuilder -void LogBuilder::convertToColoredOutput(base::type::string_t* logLine, Level level) { +void LogBuilder::convertToColoredOutput(base::type::string_t* logLine, Level level, Color color) { if (!m_termSupportsColor) return; const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m"); - if (level == Level::Error || level == Level::Fatal) - *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; - else if (level == Level::Warning) - *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; - else if (level == Level::Debug) - *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; - else if (level == Level::Info) - *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; - else if (level == Level::Trace) - *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; + if (color == Color::Red) + *logLine = ELPP_LITERAL("\x1b[1;31m") + *logLine + resetColor; + else if (color == Color::Yellow) + *logLine = ELPP_LITERAL("\x1b[1;33m") + *logLine + resetColor; + else if (color == Color::Green) + *logLine = ELPP_LITERAL("\x1b[1;32m") + *logLine + resetColor; + else if (color == Color::Cyan) + *logLine = ELPP_LITERAL("\x1b[1;36m") + *logLine + resetColor; + else if (color == Color::Magenta) + *logLine = ELPP_LITERAL("\x1b[1;35m") + *logLine + resetColor; + else if (color == Color::Blue) + *logLine = ELPP_LITERAL("\x1b[1;34m") + *logLine + resetColor; + else if (color == Color::Default) + { + if (level == Level::Error || level == Level::Fatal) + *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; + else if (level == Level::Warning) + *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; + else if (level == Level::Debug) + *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; + else if (level == Level::Info) + *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; + else if (level == Level::Trace) + *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; + } } // Logger @@ -2372,13 +2432,32 @@ void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { m_data = data; base::TypedConfigurations* tc = m_data->logMessage()->logger()->typedConfigurations(); const base::LogFormat* logFormat = &tc->logFormat(m_data->logMessage()->level()); - dispatch(base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), &tc->subsecondPrecision(m_data->logMessage()->level())) - + "\t" + convertToChar(m_data->logMessage()->level()) + " " + m_data->logMessage()->message() + "\n", - m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), - m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog)); + + const auto &logmsg = m_data->logMessage(); + const auto msg = logmsg->message(); + if (strchr(msg.c_str(), '\n')) + { + std::vector v; + boost::split(v, msg, boost::is_any_of("\n")); + for (const std::string &s: v) + { + LogMessage msgline(logmsg->level(), logmsg->color(), logmsg->file(), logmsg->line(), logmsg->func(), logmsg->verboseLevel(), logmsg->logger(), &s); + dispatch(base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), &tc->subsecondPrecision(m_data->logMessage()->level())) + "\t" + convertToChar(m_data->logMessage()->level()) + " ", + s + "\n", + m_data->logMessage()->logger()->logBuilder()->build(&msgline, + m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog)); + } + } + else + { + dispatch(base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), &tc->subsecondPrecision(m_data->logMessage()->level())) + + "\t" + convertToChar(m_data->logMessage()->level()) + " ", m_data->logMessage()->message() + "\n", + m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), + m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog)); + } } -void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLine, base::type::string_t&& logLine) { +void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine) { if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) { if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) { base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream( @@ -2404,9 +2483,14 @@ void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLine, base:: } if (m_data->dispatchAction() != base::DispatchAction::FileOnlyLog) { if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&rawLine, m_data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(rawLine); + const el::Level level = m_data->logMessage()->level(); + const el::Color color = m_data->logMessage()->color(); + el::base::utils::setConsoleColor(el::base::utils::colorFromLevel(level), false); + ELPP_COUT << rawLinePrefix; + el::base::utils::setConsoleColor(color == el::Color::Default ? el::base::utils::colorFromLevel(level): color, color != el::Color::Default); + ELPP_COUT << rawLinePayload; + el::base::utils::setConsoleColor(el::Color::Default, false); + ELPP_COUT << std::flush; } } } @@ -2447,7 +2531,7 @@ void AsyncLogDispatchCallback::handle(const LogDispatchData* data) { if ((data->dispatchAction() == base::DispatchAction::NormalLog || data->dispatchAction() == base::DispatchAction::FileOnlyLog) && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) { if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level()); + data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level(), data->logMessage()->color()); ELPP_COUT << ELPP_COUT_LINE(logLine); } // Save resources and only queue if we want to write to file otherwise just ignore handler @@ -2739,7 +2823,7 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); } } - Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) + Writer(Level::Debug, Color::Default, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) << "Logger [" << loggerId << "] is not registered yet!"; m_proceed = false; } else { @@ -2813,7 +2897,7 @@ void Writer::processDispatch() { void Writer::triggerDispatch(void) { if (m_proceed) { if (m_msg == nullptr) { - LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel, + LogMessage msg(m_level, m_color, m_file, m_line, m_func, m_verboseLevel, m_logger); base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch(); } else { @@ -2826,7 +2910,7 @@ void Writer::triggerDispatch(void) { } if (m_proceed && m_level == Level::Fatal && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { - base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) + base::Writer(Level::Warning, Color::Default, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]"; std::stringstream reasonStream; reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h index f1fa2cb0d..a10b0c8e6 100644 --- a/external/easylogging++/easylogging++.h +++ b/external/easylogging++/easylogging++.h @@ -604,6 +604,15 @@ enum class Level : base::type::EnumType { /// @brief Represents unknown level Unknown = 1010 }; +enum class Color : base::type::EnumType { + Default, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, +}; } // namespace el namespace std { template<> struct hash { @@ -2225,7 +2234,7 @@ class LogBuilder : base::NoCopy { ELPP_INTERNAL_INFO(3, "Destroying log builder...") } virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0; - void convertToColoredOutput(base::type::string_t* logLine, Level level); + void convertToColoredOutput(base::type::string_t* logLine, Level level, Color color); private: bool m_termSupportsColor; friend class el::base::DefaultLogDispatchCallback; @@ -2503,14 +2512,17 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe { } // namespace base class LogMessage { public: - LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func, - base::type::VerboseLevel verboseLevel, Logger* logger) : - m_level(level), m_file(file), m_line(line), m_func(func), - m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) { + LogMessage(Level level, Color color, const std::string& file, base::type::LineNumber line, const std::string& func, + base::type::VerboseLevel verboseLevel, Logger* logger, const base::type::string_t *msg = nullptr) : + m_level(level), m_color(color), m_file(file), m_line(line), m_func(func), + m_verboseLevel(verboseLevel), m_logger(logger), m_message(msg ? *msg : logger->stream().str()) { } inline Level level(void) const { return m_level; } + inline Color color(void) const { + return m_color; + } inline const std::string& file(void) const { return m_file; } @@ -2531,6 +2543,7 @@ class LogMessage { } private: Level m_level; + Color m_color; std::string m_file; base::type::LineNumber m_line; std::string m_func; @@ -2781,7 +2794,7 @@ class DefaultLogDispatchCallback : public LogDispatchCallback { void handle(const LogDispatchData* data); private: const LogDispatchData* m_data; - void dispatch(base::type::string_t&& rawLine, base::type::string_t&& logLine); + void dispatch(base::type::string_t&& rawLinePrefix, base::type::string_t&& rawLinePayload, base::type::string_t&& logLine); }; #if ELPP_ASYNC_LOGGING class AsyncLogDispatchCallback : public LogDispatchCallback { @@ -3242,10 +3255,10 @@ class NullWriter : base::NoCopy { /// @brief Main entry point of each logging class Writer : base::NoCopy { public: - Writer(Level level, const char* file, base::type::LineNumber line, + Writer(Level level, Color color, const char* file, base::type::LineNumber line, const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, base::type::VerboseLevel verboseLevel = 0) : - m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), + m_msg(nullptr), m_level(level), m_color(color), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { } @@ -3299,6 +3312,7 @@ class Writer : base::NoCopy { protected: LogMessage* m_msg; Level m_level; + Color m_color; const char* m_file; const base::type::LineNumber m_line; const char* m_func; @@ -3317,10 +3331,10 @@ class Writer : base::NoCopy { }; class PErrorWriter : public base::Writer { public: - PErrorWriter(Level level, const char* file, base::type::LineNumber line, + PErrorWriter(Level level, Color color, const char* file, base::type::LineNumber line, const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, base::type::VerboseLevel verboseLevel = 0) : - base::Writer(level, file, line, func, dispatchAction, verboseLevel) { + base::Writer(level, color, file, line, func, dispatchAction, verboseLevel) { } virtual ~PErrorWriter(void); @@ -3353,14 +3367,14 @@ template void Logger::log_(Level level, int vlevel, const T& log) { if (level == Level::Verbose) { if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) { - base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", + base::Writer(Level::Verbose, Color::Default, "FILE", 0, "FUNCTION", base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; } else { stream().str(ELPP_LITERAL("")); releaseLock(); } } else { - base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; + base::Writer(level, Color::Default, "FILE", 0, "FUNCTION").construct(this, false) << log; } } template @@ -3460,18 +3474,18 @@ LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace) #endif // ELPP_COMPILER_MSVC #define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) #define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) #define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \ ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) #define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \ ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) #define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \ ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) class PerformanceTrackingData { public: diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp index 189eb85eb..4408170d1 100644 --- a/src/common/perf_timer.cpp +++ b/src/common/perf_timer.cpp @@ -34,7 +34,7 @@ #define MONERO_DEFAULT_LOG_CATEGORY "perf" #define PERF_LOG_ALWAYS(level, cat, x) \ - el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x + el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x #define PERF_LOG(level, cat, x) \ do { \ if (ELPP->vRegistry()->allowed(level, cat)) PERF_LOG_ALWAYS(level, cat, x); \ diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 0147bde23..52e96562a 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1641,7 +1641,7 @@ namespace cryptonote break; case HardFork::UpdateNeeded: level = el::Level::Info; - MCLOG(level, "global", "Last scheduled hard fork time suggests a daemon update will be released within the next couple months."); + MCLOG(level, "global", el::Color::Default, "Last scheduled hard fork time suggests a daemon update will be released within the next couple months."); break; default: break; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 65115ee72..96fa1e124 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -55,7 +55,7 @@ if (ELPP->vRegistry()->allowed(level, cat)) { \ init; \ if (test) \ - el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \ + el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << x; \ } \ } while(0) @@ -370,7 +370,7 @@ namespace cryptonote uint64_t max_block_height = std::max(hshd.current_height,m_core.get_current_blockchain_height()); uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1; uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0; - MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height + MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", el::Color::Yellow, context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height << " [Your node is " << abs_diff << " blocks (" << ((abs_diff - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) " << (0 <= diff ? std::string("behind") : std::string("ahead")) << "] " << ENDL << "SYNCHRONIZATION started"); diff --git a/tests/unit_tests/logging.cpp b/tests/unit_tests/logging.cpp index 056eae604..c8526abae 100644 --- a/tests/unit_tests/logging.cpp +++ b/tests/unit_tests/logging.cpp @@ -178,3 +178,20 @@ TEST(logging, last_precedence) cleanup(); } +TEST(logging, multiline) +{ + init(); + mlog_set_categories("global:INFO"); + MGINFO("first\nsecond\nthird"); + std::string str; + ASSERT_TRUE(load_log_to_string(log_filename, str)); + ASSERT_TRUE(nlines(str) == 3); + ASSERT_TRUE(str.find("global") != std::string::npos); + ASSERT_TRUE(str.find("first") != std::string::npos); + ASSERT_TRUE(str.find("second") != std::string::npos); + ASSERT_TRUE(str.find("third") != std::string::npos); + ASSERT_TRUE(str.find("first\nsecond") == std::string::npos); + ASSERT_TRUE(str.find("second\nthird") == std::string::npos); + cleanup(); +} +