From 0ad277322fec729cfc92663bed2aa8d82be7dba8 Mon Sep 17 00:00:00 2001 From: Chunting Gu Date: Sun, 7 Apr 2019 12:25:56 +0800 Subject: [PATCH] Support terminal colors for logger. --- CMakeLists.txt | 5 ++ _clang-format | 14 +-- doc/screenshots/logger_colors.png | Bin 0 -> 49849 bytes test/CMakeLists.txt | 19 +++++ test/test_logger.cc | 15 ++++ webcc/http_request_builder.cc | 2 +- webcc/logger.cc | 137 +++++++++++++++++++++++++++--- 7 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 doc/screenshots/logger_colors.png create mode 100644 test/CMakeLists.txt create mode 100644 test/test_logger.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index a87b232..5caad12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ endif() project(webcc) option(WEBCC_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON) +option(WEBCC_ENABLE_TEST "Build test?" ON) option(WEBCC_ENABLE_UNITTEST "Build unit test?" ON) option(WEBCC_ENABLE_EXAMPLES "Build examples?" ON) @@ -140,6 +141,10 @@ if(WEBCC_ENABLE_EXAMPLES) add_subdirectory(examples) endif() +if(WEBCC_ENABLE_TEST) + add_subdirectory(test) +endif() + if(WEBCC_ENABLE_UNITTEST) add_subdirectory(${THIRD_PARTY_DIR}/src/gtest) add_subdirectory(unittest) diff --git a/_clang-format b/_clang-format index 255c975..bb15149 100644 --- a/_clang-format +++ b/_clang-format @@ -20,7 +20,7 @@ AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true -BraceWrapping: +BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false @@ -56,12 +56,12 @@ DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true -ForEachMacros: +ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve -IncludeCategories: +IncludeCategories: - Regex: '^' Priority: 2 - Regex: '^<.*\.h>' @@ -95,9 +95,9 @@ PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left -RawStringFormats: +RawStringFormats: - Language: Cpp - Delimiters: + Delimiters: - cc - CC - cpp @@ -108,12 +108,12 @@ RawStringFormats: CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto - Delimiters: + Delimiters: - pb - PB - proto - PROTO - EnclosingFunctions: + EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO diff --git a/doc/screenshots/logger_colors.png b/doc/screenshots/logger_colors.png new file mode 100644 index 0000000000000000000000000000000000000000..993db1b814269000e58e26a3df6d83e3e67f810a GIT binary patch literal 49849 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 literal 0 HcmV?d00001 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..627359b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,19 @@ +# Tests + +# Common libraries to link. +set(TEST_COMMON_LIBS webcc ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} + "${CMAKE_THREAD_LIBS_INIT}") +if(WIN32) + set(TEST_COMMON_LIBS ${TEST_COMMON_LIBS} zlibstatic crypt32) +else() + set(TEST_COMMON_LIBS ${TEST_COMMON_LIBS} ${ZLIB_LIBRARIES}) +endif() + +if(UNIX) + # Add `-ldl` for Linux to avoid "undefined reference to `dlopen'". + set(TEST_COMMON_LIBS ${TEST_COMMON_LIBS} ${CMAKE_DL_LIBS}) +endif() + +add_executable(test_logger test_logger.cc) +target_link_libraries(test_logger ${TEST_COMMON_LIBS}) + diff --git a/test/test_logger.cc b/test/test_logger.cc new file mode 100644 index 0000000..ecb5436 --- /dev/null +++ b/test/test_logger.cc @@ -0,0 +1,15 @@ +#include "webcc/logger.h" + +int main() { + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); + + LOG_INFO("info"); + LOG_WARN("warn"); + LOG_ERRO("erro"); + LOG_VERB("verb"); + LOG_FATA("fata"); + LOG_INFO("info"); + + return 0; +} + diff --git a/webcc/http_request_builder.cc b/webcc/http_request_builder.cc index a0a9fc1..a46e8d1 100644 --- a/webcc/http_request_builder.cc +++ b/webcc/http_request_builder.cc @@ -43,7 +43,7 @@ HttpRequestPtr HttpRequestBuilder::Build() { std::string data; CreateFormData(&data, boundary); - // Ingore gzip since most servers don't support it. + // Ingore gzip since most servers don't support it. request->SetContent(std::move(data), true); } diff --git a/webcc/logger.cc b/webcc/logger.cc index bd5bab7..fa2971a 100644 --- a/webcc/logger.cc +++ b/webcc/logger.cc @@ -24,6 +24,16 @@ namespace webcc { +// ----------------------------------------------------------------------------- + +static std::string g_main_thread_id; + +static const char* kLevelNames[] = { + "VERB", "INFO", "WARN", "ERRO", "FATA" +}; + +// ----------------------------------------------------------------------------- + struct Logger { Logger() : file(nullptr), modes(0) { } @@ -56,11 +66,96 @@ struct Logger { // Global logger. static Logger g_logger; -static std::string g_main_thread_id; +// ----------------------------------------------------------------------------- -static const char* kLevelNames[] = { - "VERB", "INFO", "WARN", "ERRO", "FATA" -}; +// The colors related code was adapted from Loguru. See: +// https://github.com/emilk/loguru/blob/master/loguru.cpp +// Thanks to Loguru! + +bool g_colorlogtostderr = true; + +static const bool g_terminal_has_color = []() { +#if (defined(WIN32) || defined(_WIN64)) +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE); + if (houtput != INVALID_HANDLE_VALUE) { + DWORD mode = 0; + GetConsoleMode(houtput, &mode); + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + return SetConsoleMode(houtput, mode) != 0; + } + return false; +#else + const char* term = getenv("TERM"); + if (term == nullptr) { + return false; + } + + return strcmp(term, "cygwin") == 0 || strcmp(term, "linux") == 0 || + strcmp(term, "rxvt-unicode-256color") == 0 || + strcmp(term, "screen") == 0 || strcmp(term, "screen-256color") == 0 || + strcmp(term, "tmux-256color") == 0 || strcmp(term, "xterm") == 0 || + strcmp(term, "xterm-256color") == 0 || + strcmp(term, "xterm-termite") == 0 || strcmp(term, "xterm-color") == 0; +#endif +}(); + +// Colors + +#ifdef _WIN32 +#define VTSEQ(ID) ("\x1b[1;" #ID "m") +#else +#define VTSEQ(ID) ("\x1b[" #ID "m") +#endif + +const char* TerminalBlack() { + return g_terminal_has_color ? VTSEQ(30) : ""; +} +const char* TerminalRed() { + return g_terminal_has_color ? VTSEQ(31) : ""; +} +const char* TerminalGreen() { + return g_terminal_has_color ? VTSEQ(32) : ""; +} +const char* TerminalYellow() { + return g_terminal_has_color ? VTSEQ(33) : ""; +} +const char* TerminalBlue() { + return g_terminal_has_color ? VTSEQ(34) : ""; +} +const char* TerminalPurple() { + return g_terminal_has_color ? VTSEQ(35) : ""; +} +const char* TerminalCyan() { + return g_terminal_has_color ? VTSEQ(36) : ""; +} +const char* TerminalLightGray() { + return g_terminal_has_color ? VTSEQ(37) : ""; +} +const char* TerminalWhite() { + return g_terminal_has_color ? VTSEQ(37) : ""; +} +const char* TerminalLightRed() { + return g_terminal_has_color ? VTSEQ(91) : ""; +} +const char* TerminalDim() { + return g_terminal_has_color ? VTSEQ(2) : ""; +} + +// Formating +const char* TerminalBold() { + return g_terminal_has_color ? VTSEQ(1) : ""; +} +const char* TerminalUnderline() { + return g_terminal_has_color ? VTSEQ(4) : ""; +} + +// You should end each line with this! +const char* TerminalReset() { + return g_terminal_has_color ? VTSEQ(0) : ""; +} namespace bfs = boost::filesystem; @@ -123,8 +218,8 @@ static std::string GetTimestamp() { ss << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S"); std::chrono::milliseconds milli_seconds = - std::chrono::duration_cast( - now.time_since_epoch()); + std::chrono::duration_cast( + now.time_since_epoch()); std::string micro_seconds_str = std::to_string(milli_seconds.count() % 1000); while (micro_seconds_str.size() < 3) { micro_seconds_str = "0" + micro_seconds_str; @@ -168,13 +263,33 @@ void LogWrite(int level, const char* file, int line, const char* format, ...) { va_list args; va_start(args, format); - fprintf(stderr, "%s, %s, %7s, %25s, %4d, ", - timestamp.c_str(), kLevelNames[level], thread_id.c_str(), - file, line); + if (g_colorlogtostderr && g_terminal_has_color) { + if (level < WEBCC_WARN) { + fprintf(stderr, "%s%s%s, %s, %7s, %25s, %4d, %s", + TerminalReset(), TerminalDim(), + timestamp.c_str(), kLevelNames[level], thread_id.c_str(), + file, line, + level == WEBCC_INFO ? TerminalReset() : ""); // un-dim for INFO + } else { + fprintf(stderr, "%s%s%s, %s, %7s, %25s, %4d, ", + TerminalReset(), + level == WEBCC_WARN ? TerminalYellow() : TerminalRed(), + timestamp.c_str(), kLevelNames[level], thread_id.c_str(), + file, line); + } - vfprintf(stderr, format, args); + vfprintf(stderr, format, args); - fprintf(stderr, "\n"); + fprintf(stderr, "%s\n", TerminalReset()); + } else { + fprintf(stderr, "%s, %s, %7s, %25s, %4d, ", + timestamp.c_str(), kLevelNames[level], thread_id.c_str(), + file, line); + + vfprintf(stderr, format, args); + + fprintf(stderr, "\n"); + } if ((g_logger.modes & LOG_FLUSH) != 0) { fflush(stderr);