diff --git a/SConstruct b/SConstruct index b736c303..d5144918 100644 --- a/SConstruct +++ b/SConstruct @@ -258,16 +258,16 @@ cpp_compiler_changed = False usingGCC = True -# ** Special setup for compilation by P.E. on Mac (assumes GCC v13 is installed and -# callable via gcc-13 and g++-13) +# ** Special setup for compilation by P.E. on Mac (assumes GCC v14 is installed and +# callable via gcc-14 and g++-14) # Comment this out otherwise! # Note that the following way of determining the username seems to be a bit more # portable than "getpass.getuser()", which fails for "Ubuntu on Windows" (acc. to # Lee Kelvin, who contributed the new version) userName = pwd.getpwuid(os.getuid())[0] if (os_type == "Darwin") and (userName == "erwin"): - CC_COMPILER = "gcc-13" - CPP_COMPILER = "g++-13" + CC_COMPILER = "gcc-14" + CPP_COMPILER = "g++-14" c_compiler_changed = True cpp_compiler_changed = True usingGCC = True @@ -333,7 +333,7 @@ AddOption("--extra-funcs", dest="useExtraFuncs", action="store_true", default=False, help="compile additional FunctionObject classes for testing") AddOption("--extra-checks", dest="doExtraChecks", action="store_true", default=False, help="turn on additional error-checking and warning flags during compilation") -# options to specify use of non-default compilers, extra checks, loggin +# options to specify use of non-default compilers, extra checks, logging AddOption("--cc", dest="cc_compiler", type="string", action="store", default=None, help="C compiler to use instead of system default") AddOption("--cpp", dest="cpp_compiler", type="string", action="store", default=None, @@ -412,8 +412,8 @@ if GetOption("useGCC"): print("ERROR: You cannot specify both Clang and GCC as the compiler!") Exit(2) usingGCC = True - CC_COMPILER = "gcc-13" - CPP_COMPILER = "g++-13" + CC_COMPILER = "gcc-14" + CPP_COMPILER = "g++-14" print("using %s for C compiler" % CC_COMPILER) print("using %s for C++ compiler" % CPP_COMPILER) c_compiler_changed = True diff --git a/loguru/loguru.cpp b/loguru/loguru.cpp index bd75e999..468675d5 100644 --- a/loguru/loguru.cpp +++ b/loguru/loguru.cpp @@ -1,3 +1,4 @@ +#ifndef _WIN32 // Disable all warnings from gcc/clang: #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" @@ -15,6 +16,12 @@ #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wunused-macros" #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#else +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4018) +#endif // _MSC_VER +#endif #include "loguru.hpp" @@ -71,7 +78,7 @@ #ifndef LOGURU_STACKTRACES #define LOGURU_STACKTRACES 0 #endif -#elif defined(__rtems__) +#elif defined(__rtems__) || defined(__ANDROID__) #define LOGURU_PTHREADS 1 #define LOGURU_WINTHREADS 0 #ifndef LOGURU_STACKTRACES @@ -122,6 +129,7 @@ #define LOGURU_PTLS_NAMES 0 #endif + namespace loguru { using namespace std::chrono; @@ -164,6 +172,8 @@ namespace loguru unsigned g_flush_interval_ms = 0; bool g_preamble = true; + Verbosity g_internal_verbosity = Verbosity_0; + // Preamble details bool g_preamble_date = true; bool g_preamble_time = true; @@ -211,6 +221,7 @@ namespace loguru || 0 == strcmp(term, "rxvt-unicode-256color") || 0 == strcmp(term, "screen") || 0 == strcmp(term, "screen-256color") + || 0 == strcmp(term, "screen.xterm-256color") || 0 == strcmp(term, "tmux-256color") || 0 == strcmp(term, "xterm") || 0 == strcmp(term, "xterm-256color") @@ -332,21 +343,21 @@ namespace loguru fclose(file_abs->fp); } if (!file_abs->fp) { - LOG_F(INFO, "Reopening file '%s' due to previous error", file_abs->path); + VLOG_F(g_internal_verbosity, "Reopening file '" LOGURU_FMT(s) "' due to previous error", file_abs->path); } else if (ret < 0) { const auto why = errno_as_text(); - LOG_F(INFO, "Reopening file '%s' due to '%s'", file_abs->path, why.c_str()); + VLOG_F(g_internal_verbosity, "Reopening file '" LOGURU_FMT(s) "' due to '" LOGURU_FMT(s) "'", file_abs->path, why.c_str()); } else { - LOG_F(INFO, "Reopening file '%s' due to file changed", file_abs->path); + VLOG_F(g_internal_verbosity, "Reopening file '" LOGURU_FMT(s) "' due to file changed", file_abs->path); } // try reopen current file. if (!create_directories(file_abs->path)) { - LOG_F(ERROR, "Failed to create directories to '%s'", file_abs->path); + LOG_F(ERROR, "Failed to create directories to '" LOGURU_FMT(s) "'", file_abs->path); } file_abs->fp = fopen(file_abs->path, file_abs->mode_str); if (!file_abs->fp) { - LOG_F(ERROR, "Failed to open '%s'", file_abs->path); + LOG_F(ERROR, "Failed to open '" LOGURU_FMT(s) "'", file_abs->path); } else { stat(file_abs->path, &file_abs->st); } @@ -360,6 +371,12 @@ namespace loguru Text::~Text() { free(_str); } +#if LOGURU_USE_FMTLIB + Text vtextprintf(const char* format, fmt::format_args args) + { + return Text(STRDUP(fmt::vformat(format, args).c_str())); + } +#else LOGURU_PRINTF_LIKE(1, 0) static Text vtextprintf(const char* format, va_list vlist) { @@ -372,7 +389,7 @@ namespace loguru #else char* buff = nullptr; int result = vasprintf(&buff, format, vlist); - CHECK_F(result >= 0, "Bad string format: '%s'", format); + CHECK_F(result >= 0, "Bad string format: '" LOGURU_FMT(s) "'", format); return Text(buff); #endif } @@ -385,6 +402,7 @@ namespace loguru va_end(vlist); return result; } +#endif // Overloaded for variadic template matching. Text textprintf() @@ -420,7 +438,7 @@ namespace loguru if (value_str[0] == '\0') { // Value in separate argument arg_it += 1; - CHECK_LT_F(arg_it, argc, "Missing verbosiy level after %s", verbosity_flag); + CHECK_LT_F(arg_it, argc, "Missing verbosiy level after " LOGURU_FMT(s) "", verbosity_flag); value_str = argv[arg_it]; out_argc -= 1; } @@ -433,7 +451,7 @@ namespace loguru char* end = 0; g_stderr_verbosity = static_cast(strtol(value_str, &end, 10)); CHECK_F(end && *end == '\0', - "Invalid verbosity. Expected integer, INFO, WARNING, ERROR or OFF, got '%s'", value_str); + "Invalid verbosity. Expected integer, INFO, WARNING, ERROR or OFF, got '" LOGURU_FMT(s) "'", value_str); } } else { argv[arg_dest++] = argv[arg_it]; @@ -464,11 +482,11 @@ namespace loguru static void on_atexit() { - LOG_F(INFO, "atexit"); + VLOG_F(g_internal_verbosity, "atexit"); flush(); } - static void install_signal_handlers(); + static void install_signal_handlers(bool unsafe_signal_handler); static void write_hex_digit(std::string& out, unsigned num) { @@ -510,21 +528,21 @@ namespace loguru char buff[256]; #if defined(__GLIBC__) && defined(_GNU_SOURCE) // GNU Version - return Text(strdup(strerror_r(errno, buff, sizeof(buff)))); + return Text(STRDUP(strerror_r(errno, buff, sizeof(buff)))); #elif defined(__APPLE__) || _POSIX_C_SOURCE >= 200112L // XSI Version strerror_r(errno, buff, sizeof(buff)); return Text(strdup(buff)); #elif defined(_WIN32) strerror_s(buff, sizeof(buff), errno); - return Text(strdup(buff)); + return Text(STRDUP(buff)); #else // Not thread-safe. - return Text(strdup(strerror(errno))); + return Text(STRDUP(strerror(errno))); #endif } - void init(int& argc, char* argv[], const char* verbosity_flag) + void init(int& argc, char* argv[], const Options& options) { CHECK_GT_F(argc, 0, "Expected proper argc/argv"); CHECK_EQ_F(argv[argc], nullptr, "Expected proper argc/argv"); @@ -535,10 +553,9 @@ namespace loguru #define getcwd _getcwd #endif - if (!getcwd(s_current_dir, sizeof(s_current_dir))) - { + if (!getcwd(s_current_dir, sizeof(s_current_dir))) { const auto error_text = errno_as_text(); - LOG_F(WARNING, "Failed to get current working directory: %s", error_text.c_str()); + LOG_F(WARNING, "Failed to get current working directory: " LOGURU_FMT(s) "", error_text.c_str()); } s_arguments = ""; @@ -549,28 +566,30 @@ namespace loguru } } - if (verbosity_flag) { - parse_args(argc, argv, verbosity_flag); + if (options.verbosity_flag) { + parse_args(argc, argv, options.verbosity_flag); } - #if LOGURU_PTLS_NAMES || LOGURU_WINTHREADS - set_thread_name("main thread"); - #elif LOGURU_PTHREADS - char old_thread_name[16] = {0}; - auto this_thread = pthread_self(); - #if defined(__APPLE__) || defined(__linux__) - pthread_getname_np(this_thread, old_thread_name, sizeof(old_thread_name)); - #endif - if (old_thread_name[0] == 0) { - #ifdef __APPLE__ - pthread_setname_np("main thread"); - #elif defined(__FreeBSD__) || defined(__OpenBSD__) - pthread_set_name_np(this_thread, "main thread"); - #elif defined(__linux__) - pthread_setname_np(this_thread, "main thread"); + if (const auto main_thread_name = options.main_thread_name) { + #if LOGURU_PTLS_NAMES || LOGURU_WINTHREADS + set_thread_name(main_thread_name); + #elif LOGURU_PTHREADS + char old_thread_name[16] = {0}; + auto this_thread = pthread_self(); + #if defined(__APPLE__) || defined(__linux__) + pthread_getname_np(this_thread, old_thread_name, sizeof(old_thread_name)); #endif - } - #endif // LOGURU_PTHREADS + if (old_thread_name[0] == 0) { + #ifdef __APPLE__ + pthread_setname_np(main_thread_name); + #elif defined(__FreeBSD__) || defined(__OpenBSD__) + pthread_set_name_np(this_thread, main_thread_name); + #elif defined(__linux__) + pthread_setname_np(this_thread, main_thread_name); + #endif + } + #endif // LOGURU_PTHREADS + } if (g_stderr_verbosity >= Verbosity_INFO) { if (g_preamble) { @@ -584,22 +603,22 @@ namespace loguru } fflush(stderr); } - LOG_F(INFO, "arguments: %s", s_arguments.c_str()); + VLOG_F(g_internal_verbosity, "arguments: " LOGURU_FMT(s) "", s_arguments.c_str()); if (strlen(s_current_dir) != 0) { - LOG_F(INFO, "Current dir: %s", s_current_dir); + VLOG_F(g_internal_verbosity, "Current dir: " LOGURU_FMT(s) "", s_current_dir); } - LOG_F(INFO, "stderr verbosity: %d", g_stderr_verbosity); - LOG_F(INFO, "-----------------------------------"); + VLOG_F(g_internal_verbosity, "stderr verbosity: " LOGURU_FMT(d) "", g_stderr_verbosity); + VLOG_F(g_internal_verbosity, "-----------------------------------"); - install_signal_handlers(); + install_signal_handlers(options.unsafe_signal_handler); atexit(on_atexit); } void shutdown() { - LOG_F(INFO, "loguru::shutdown()"); + VLOG_F(g_internal_verbosity, "loguru::shutdown()"); remove_all_callbacks(); set_fatal_handler(nullptr); set_verbosity_to_name_callback(nullptr); @@ -673,7 +692,7 @@ namespace loguru bool create_directories(const char* file_path_const) { CHECK_F(file_path_const && *file_path_const); - char* file_path = strdup(file_path_const); + char* file_path = STRDUP(file_path_const); for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) { *p = '\0'; @@ -683,7 +702,7 @@ namespace loguru if (mkdir(file_path, 0755) == -1) { #endif if (errno != EEXIST) { - LOG_F(ERROR, "Failed to create directory '%s'", file_path); + LOG_F(ERROR, "Failed to create directory '" LOGURU_FMT(s) "'", file_path); LOG_IF_F(ERROR, errno == EACCES, "EACCES"); LOG_IF_F(ERROR, errno == ENAMETOOLONG, "ENAMETOOLONG"); LOG_IF_F(ERROR, errno == ENOENT, "ENOENT"); @@ -710,13 +729,13 @@ namespace loguru } if (!create_directories(path)) { - LOG_F(ERROR, "Failed to create directories to '%s'", path); + LOG_F(ERROR, "Failed to create directories to '" LOGURU_FMT(s) "'", path); } const char* mode_str = (mode == FileMode::Truncate ? "w" : "a"); auto file = fopen(path, mode_str); if (!file) { - LOG_F(ERROR, "Failed to open '%s'", path); + LOG_F(ERROR, "Failed to open '" LOGURU_FMT(s) "'", path); return false; } #if LOGURU_WITH_FILEABS @@ -748,7 +767,7 @@ namespace loguru } fflush(file); - LOG_F(INFO, "Logging to '%s', mode: '%s', verbosity: %d", path, mode_str, verbosity); + VLOG_F(g_internal_verbosity, "Logging to '" LOGURU_FMT(s) "', mode: '" LOGURU_FMT(s) "', verbosity: " LOGURU_FMT(d) "", path, mode_str, verbosity); return true; } @@ -865,7 +884,7 @@ namespace loguru on_callback_change(); return true; } else { - LOG_F(ERROR, "Failed to locate callback with id '%s'", id); + LOG_F(ERROR, "Failed to locate callback with id '" LOGURU_FMT(s) "'", id); return false; } } @@ -901,7 +920,7 @@ namespace loguru { #if LOGURU_PTLS_NAMES (void)pthread_once(&s_pthread_key_once, make_pthread_key_name); - (void)pthread_setspecific(s_pthread_key_name, strdup(name)); + (void)pthread_setspecific(s_pthread_key_name, STRDUP(name)); #elif LOGURU_PTHREADS #ifdef __APPLE__ @@ -928,6 +947,9 @@ namespace loguru void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id) { +#ifdef _WIN32 + (void)right_align_hext_id; +#endif CHECK_NE_F(length, 0u, "Zero length buffer in get_thread_name"); CHECK_NOTNULL_F(buffer, "nullptr in get_thread_name"); #if LOGURU_PTHREADS @@ -982,7 +1004,7 @@ namespace loguru { int status = -1; char* demangled = abi::__cxa_demangle(name, 0, 0, &status); - Text result{status == 0 ? demangled : strdup(name)}; + Text result{status == 0 ? demangled : STRDUP(name)}; return result; } @@ -1090,7 +1112,7 @@ namespace loguru #else // LOGURU_STACKTRACES Text demangle(const char* name) { - return Text(strdup(name)); + return Text(STRDUP(name)); } std::string stacktrace_as_stdstring(int) @@ -1104,7 +1126,7 @@ namespace loguru Text stacktrace(int skip) { auto str = stacktrace_as_stdstring(skip + 1); - return Text(strdup(str.c_str())); + return Text(STRDUP(str.c_str())); } // ------------------------------------------------------------------------ @@ -1207,12 +1229,12 @@ namespace loguru if (message.verbosity == Verbosity_FATAL) { auto st = loguru::stacktrace(stack_trace_skip + 2); if (!st.empty()) { - RAW_LOG_F(ERROR, "Stack trace:\n%s", st.c_str()); + RAW_LOG_F(ERROR, "Stack trace:\n" LOGURU_FMT(s) "", st.c_str()); } auto ec = loguru::get_error_context(); if (!ec.empty()) { - RAW_LOG_F(ERROR, "%s", ec.c_str()); + RAW_LOG_F(ERROR, "" LOGURU_FMT(s) "", ec.c_str()); } } @@ -1309,19 +1331,18 @@ namespace loguru } #if LOGURU_USE_FMTLIB - void log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args) + void vlog(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::format_args args) { - auto formatted = fmt::format(format, args); + auto formatted = fmt::vformat(format, args); log_to_everywhere(1, verbosity, file, line, "", formatted.c_str()); } - void raw_log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args) + void raw_vlog(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::format_args args) { - auto formatted = fmt::format(format, args); + auto formatted = fmt::vformat(format, args); auto message = Message{verbosity, file, line, "", "", "", formatted.c_str()}; log_message(1, message, false, true); } - #else void log(Verbosity verbosity, const char* file, unsigned line, const char* format, ...) { @@ -1401,7 +1422,11 @@ namespace loguru } #if LOGURU_VERBOSE_SCOPE_ENDINGS auto duration_sec = (now_ns() - _start_time_ns) / 1e9; +#if LOGURU_USE_FMTLIB + auto buff = textprintf("{:.{}f} s: {:s}", duration_sec, LOGURU_SCOPE_TIME_PRECISION, _name); +#else auto buff = textprintf("%.*f s: %s", LOGURU_SCOPE_TIME_PRECISION, duration_sec, _name); +#endif log_to_everywhere(1, _verbosity, _file, _line, "} ", buff.c_str()); #else log_to_everywhere(1, _verbosity, _file, _line, "}", ""); @@ -1409,6 +1434,14 @@ namespace loguru } } +#if LOGURU_USE_FMTLIB + void vlog_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, const char* format, fmt::format_args args) + { + auto formatted = fmt::vformat(format, args); + log_to_everywhere(stack_trace_skip + 1, Verbosity_FATAL, file, line, expr, formatted.c_str()); + abort(); // log_to_everywhere already does this, but this makes the analyzer happy. + } +#else void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, const char* format, ...) { va_list vlist; @@ -1418,6 +1451,7 @@ namespace loguru va_end(vlist); abort(); // log_to_everywhere already does this, but this makes the analyzer happy. } +#endif void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line) { @@ -1427,6 +1461,21 @@ namespace loguru // ---------------------------------------------------------------------------- // Streams: +#if LOGURU_USE_FMTLIB + template + std::string vstrprintf(const char* format, const Args&... args) + { + auto text = textprintf(format, args...); + std::string result = text.c_str(); + return result; + } + + template + std::string strprintf(const char* format, const Args&... args) + { + return vstrprintf(format, args...); + } +#else std::string vstrprintf(const char* format, va_list vlist) { auto text = vtextprintf(format, vlist); @@ -1442,19 +1491,20 @@ namespace loguru va_end(vlist); return result; } +#endif #if LOGURU_WITH_STREAMS StreamLogger::~StreamLogger() noexcept(false) { auto message = _ss.str(); - log(_verbosity, _file, _line, "%s", message.c_str()); + log(_verbosity, _file, _line, LOGURU_FMT(s), message.c_str()); } AbortLogger::~AbortLogger() noexcept(false) { auto message = _ss.str(); - loguru::log_and_abort(1, _expr, _file, _line, "%s", message.c_str()); + loguru::log_and_abort(1, _expr, _file, _line, LOGURU_FMT(s), message.c_str()); } #endif // LOGURU_WITH_STREAMS @@ -1545,15 +1595,20 @@ namespace loguru result.str += "------------------------------------------------\n"; for (auto entry : stack) { const auto description = std::string(entry->_descr) + ":"; +#if LOGURU_USE_FMTLIB + auto prefix = textprintf("[ErrorContext] {.{}s}:{:-5u} {:-20s} ", + filename(entry->_file), LOGURU_FILENAME_WIDTH, entry->_line, description.c_str()); +#else auto prefix = textprintf("[ErrorContext] %*s:%-5u %-20s ", LOGURU_FILENAME_WIDTH, filename(entry->_file), entry->_line, description.c_str()); +#endif result.str += prefix.c_str(); entry->print_value(result); result.str += "\n"; } result.str += "------------------------------------------------"; } - return Text(strdup(result.str.c_str())); + return Text(STRDUP(result.str.c_str())); } EcEntryBase::EcEntryBase(const char* file, unsigned line, const char* descr) @@ -1576,7 +1631,7 @@ namespace loguru // Add quotes around the string to make it obvious where it begin and ends. // This is great for detecting erroneous leading or trailing spaces in e.g. an identifier. auto str = "\"" + std::string(value) + "\""; - return Text{strdup(str.c_str())}; + return Text{STRDUP(str.c_str())}; } Text ec_to_text(char c) @@ -1614,14 +1669,14 @@ namespace loguru str += "'"; - return Text{strdup(str.c_str())}; + return Text{STRDUP(str.c_str())}; } #define DEFINE_EC(Type) \ Text ec_to_text(Type value) \ { \ auto str = std::to_string(value); \ - return Text{strdup(str.c_str())}; \ + return Text{STRDUP(str.c_str())}; \ } DEFINE_EC(int) @@ -1658,13 +1713,10 @@ namespace loguru #ifdef _WIN32 namespace loguru { - void install_signal_handlers() + void install_signal_handlers(bool unsafe_signal_handler) { - #if defined(_MSC_VER) - #pragma message ( "No signal handlers on Win32" ) - #else - #warning "No signal handlers on Win32" - #endif + (void)unsafe_signal_handler; + // TODO: implement signal handlers on windows } } // namespace loguru @@ -1710,6 +1762,8 @@ namespace loguru kill(getpid(), signal_number); } + static bool s_unsafe_signal_handler = false; + void signal_handler(int signal_number, siginfo_t*, void*) { const char* signal_name = "UNKNOWN SIGNAL"; @@ -1743,33 +1797,35 @@ namespace loguru // -------------------------------------------------------------------- -#if LOGURU_UNSAFE_SIGNAL_HANDLER - // -------------------------------------------------------------------- - /* Now we do unsafe things. This can for example lead to deadlocks if - the signal was triggered from the system's memory management functions - and the code below tries to do allocations. - */ + if (s_unsafe_signal_handler) { + // -------------------------------------------------------------------- + /* Now we do unsafe things. This can for example lead to deadlocks if + the signal was triggered from the system's memory management functions + and the code below tries to do allocations. + */ - flush(); - char preamble_buff[LOGURU_PREAMBLE_WIDTH]; - print_preamble(preamble_buff, sizeof(preamble_buff), Verbosity_FATAL, "", 0); - auto message = Message{Verbosity_FATAL, "", 0, preamble_buff, "", "Signal: ", signal_name}; - try { - log_message(1, message, false, false); - } catch (...) { - // This can happed due to s_fatal_handler. - write_to_stderr("Exception caught and ignored by Loguru signal handler.\n"); - } - flush(); + flush(); + char preamble_buff[LOGURU_PREAMBLE_WIDTH]; + print_preamble(preamble_buff, sizeof(preamble_buff), Verbosity_FATAL, "", 0); + auto message = Message{Verbosity_FATAL, "", 0, preamble_buff, "", "Signal: ", signal_name}; + try { + log_message(1, message, false, false); + } catch (...) { + // This can happed due to s_fatal_handler. + write_to_stderr("Exception caught and ignored by Loguru signal handler.\n"); + } + flush(); - // -------------------------------------------------------------------- -#endif // LOGURU_UNSAFE_SIGNAL_HANDLER + // -------------------------------------------------------------------- + } call_default_signal_handler(signal_number); } - void install_signal_handlers() + void install_signal_handlers(bool unsafe_signal_handler) { + s_unsafe_signal_handler = unsafe_signal_handler; + struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); @@ -1777,11 +1833,17 @@ namespace loguru sig_action.sa_sigaction = &signal_handler; for (const auto& s : ALL_SIGNALS) { CHECK_F(sigaction(s.number, &sig_action, NULL) != -1, - "Failed to install handler for %s", s.name); + "Failed to install handler for " LOGURU_FMT(s) "", s.name); } } } // namespace loguru #endif // _WIN32 +#ifdef _WIN32 +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER +#endif // _WIN32 + #endif // LOGURU_IMPLEMENTATION diff --git a/loguru/loguru.hpp b/loguru/loguru.hpp index 76e2a824..05b4e980 100644 --- a/loguru/loguru.hpp +++ b/loguru/loguru.hpp @@ -8,8 +8,8 @@ Website: www.ilikebigbits.com # License This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy - and modify this file as you see fit. + recognized, you are granted a perpetual, irrevocable license to + copy, modify and distribute it as you see fit. # Inspiration Much of Loguru was inspired by GLOG, https://code.google.com/p/google-glog/. @@ -55,6 +55,7 @@ Website: www.ilikebigbits.com * Version 1.8.0 - 2018-04-23 - Shorten long file names to keep preamble fixed width * Version 1.9.0 - 2018-09-22 - Adjust terminal colors, add LOGURU_VERBOSE_SCOPE_ENDINGS, add LOGURU_SCOPE_TIME_PRECISION, add named log levels * Version 2.0.0 - 2018-09-22 - Split loguru.hpp into loguru.hpp and loguru.cpp + * Version 2.1.0 - 2019-09-23 - Update fmtlib + add option to loguru::init to NOT set main thread name. # Compiling Just include where you want to use Loguru. @@ -78,7 +79,7 @@ Website: www.ilikebigbits.com */ #if defined(LOGURU_IMPLEMENTATION) - #warning "You are defining LOGURU_IMPLEMENTATION. This is for older versions of Loguru. You should now instead include loguru.cpp (or build it and link with it)" + #error "You are defining LOGURU_IMPLEMENTATION. This is for older versions of Loguru. You should now instead include loguru.cpp (or build it and link with it)" #endif // Disable all warnings from gcc/clang: @@ -93,7 +94,7 @@ Website: www.ilikebigbits.com // Semantic versioning. Loguru version can be printed with printf("%d.%d.%d", LOGURU_VERSION_MAJOR, LOGURU_VERSION_MINOR, LOGURU_VERSION_PATCH); #define LOGURU_VERSION_MAJOR 2 -#define LOGURU_VERSION_MINOR 0 +#define LOGURU_VERSION_MINOR 1 #define LOGURU_VERSION_PATCH 0 #if defined(_MSC_VER) @@ -155,8 +156,8 @@ Website: www.ilikebigbits.com #define LOGURU_WITH_STREAMS 1 #endif -#ifndef LOGURU_UNSAFE_SIGNAL_HANDLER - #define LOGURU_UNSAFE_SIGNAL_HANDLER 1 +#if defined(LOGURU_UNSAFE_SIGNAL_HANDLER) + #error "You are defining LOGURU_UNSAFE_SIGNAL_HANDLER. This is for older versions of Loguru. You should now instead set the unsafe_signal_handler option when you call loguru::init." #endif #if LOGURU_IMPLEMENTATION @@ -230,6 +231,15 @@ Website: www.ilikebigbits.com #if LOGURU_USE_FMTLIB #include + #define LOGURU_FMT(x) "{:" #x "}" +#else + #define LOGURU_FMT(x) "%" #x +#endif + +#ifdef _WIN32 + #define STRDUP(str) _strdup(str) +#else + #define STRDUP(str) strdup(str) #endif // -------------------------------------------------------------------- @@ -266,8 +276,19 @@ namespace loguru }; // Like printf, but returns the formated text. +#if LOGURU_USE_FMTLIB + LOGURU_EXPORT + Text vtextprintf(const char* format, fmt::format_args args); + + template + LOGURU_EXPORT + Text textprintf(LOGURU_FORMAT_STRING_TYPE format, const Args&... args) { + return vtextprintf(format, fmt::make_format_args(args...)); + } +#else LOGURU_EXPORT Text textprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2); +#endif // Overloaded for variadic template matching. LOGURU_EXPORT @@ -338,6 +359,11 @@ namespace loguru LOGURU_EXPORT extern unsigned g_flush_interval_ms; // 0 (unbuffered) by default. LOGURU_EXPORT extern bool g_preamble; // Prefix each log line with date, time etc? True by default. + /* Specify the verbosity used by loguru to log its info messages including the header + logged when logged::init() is called or on exit. Default is 0 (INFO). + */ + LOGURU_EXPORT extern Verbosity g_internal_verbosity; + // Turn off individual parts of the preamble LOGURU_EXPORT extern bool g_preamble_date; // The date field LOGURU_EXPORT extern bool g_preamble_time; // The time of the current day @@ -362,6 +388,27 @@ namespace loguru // Verbosity_INVALID if name is not recognized. typedef Verbosity (*name_to_verbosity_t)(const char* name); + // Runtime options passed to loguru::init + struct Options + { + // This allows you to use something else instead of "-v" via verbosity_flag. + // Set to nullptr to if you don't want Loguru to parse verbosity from the args.' + const char* verbosity_flag = "-v"; + + // loguru::init will set the name of the calling thread to this. + // If you don't want Loguru to set the name of the main thread, + // set this to nullptr. + // NOTE: on SOME platforms loguru::init will only overwrite the thread name + // if a thread name has not already been set. + // To always set a thread name, use loguru::set_thread_name instead. + const char* main_thread_name = "main thread"; + + // Make Loguru try to do unsafe but useful things, + // like printing a stack trace, when catching signals. + // This may lead to bad things like deadlocks in certain situations. + bool unsafe_signal_handler = true; + }; + /* Should be called from the main thread. You don't *need* to call this, but if you do you get: * Signal handlers installed @@ -386,11 +433,10 @@ namespace loguru That way you can set the default but have the user override it with the -v flag. Note that -v does not affect file logging (see loguru::add_file). - You can use something else instead of "-v" via verbosity_flag. - You can also set verbosity_flag to nullptr. + You can you something other than the -v flag by setting the verbosity_flag option. */ LOGURU_EXPORT - void init(int& argc, char* argv[], const char* verbosity_flag = "-v"); + void init(int& argc, char* argv[], const Options& options = {}); // Will call remove_all_callbacks(). After calling this, logging will still go to stderr. // You generally don't need to call this. @@ -510,15 +556,23 @@ namespace loguru Verbosity current_verbosity_cutoff(); #if LOGURU_USE_FMTLIB + // Internal functions + void vlog(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::format_args args); + void raw_vlog(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::format_args args); + // Actual logging function. Use the LOG macro instead of calling this directly. + template LOGURU_EXPORT - void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args); - FMT_VARIADIC(void, log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE) + void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, const Args &... args) { + vlog(verbosity, file, line, format, fmt::make_format_args(args...)); + } // Log without any preamble or indentation. + template LOGURU_EXPORT - void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args); - FMT_VARIADIC(void, raw_log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE) + void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, const Args &... args) { + raw_vlog(verbosity, file, line, format, fmt::make_format_args(args...)); + } #else // LOGURU_USE_FMTLIB? // Actual logging function. Use the LOG macro instead of calling this directly. LOGURU_EXPORT @@ -573,8 +627,18 @@ namespace loguru // Marked as 'noreturn' for the benefit of the static analyzer and optimizer. // stack_trace_skip is the number of extrace stack frames to skip above log_and_abort. +#if LOGURU_USE_FMTLIB + LOGURU_EXPORT + LOGURU_NORETURN void vlog_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::format_args); + template + LOGURU_EXPORT + LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, const Args&... args) { + vlog_and_abort(stack_trace_skip, expr, file, line, format, fmt::make_format_args(args...)); + } +#else LOGURU_EXPORT LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6); +#endif LOGURU_EXPORT LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line); @@ -585,15 +649,15 @@ namespace loguru void flush(); template inline Text format_value(const T&) { return textprintf("N/A"); } - template<> inline Text format_value(const char& v) { return textprintf("%c", v); } - template<> inline Text format_value(const int& v) { return textprintf("%d", v); } - template<> inline Text format_value(const unsigned int& v) { return textprintf("%u", v); } - template<> inline Text format_value(const long& v) { return textprintf("%lu", v); } - template<> inline Text format_value(const unsigned long& v) { return textprintf("%ld", v); } - template<> inline Text format_value(const long long& v) { return textprintf("%llu", v); } - template<> inline Text format_value(const unsigned long long& v) { return textprintf("%lld", v); } - template<> inline Text format_value(const float& v) { return textprintf("%f", v); } - template<> inline Text format_value(const double& v) { return textprintf("%f", v); } + template<> inline Text format_value(const char& v) { return textprintf(LOGURU_FMT(c), v); } + template<> inline Text format_value(const int& v) { return textprintf(LOGURU_FMT(d), v); } + template<> inline Text format_value(const unsigned int& v) { return textprintf(LOGURU_FMT(u), v); } + template<> inline Text format_value(const long& v) { return textprintf(LOGURU_FMT(lu), v); } + template<> inline Text format_value(const unsigned long& v) { return textprintf(LOGURU_FMT(ld), v); } + template<> inline Text format_value(const long long& v) { return textprintf(LOGURU_FMT(llu), v); } + template<> inline Text format_value(const unsigned long long& v) { return textprintf(LOGURU_FMT(lld), v); } + template<> inline Text format_value(const float& v) { return textprintf(LOGURU_FMT(f), v); } + template<> inline Text format_value(const double& v) { return textprintf(LOGURU_FMT(f), v); } /* Thread names can be set for the benefit of readable logs. If you do not set the thread name, a hex id will be shown instead. @@ -878,14 +942,14 @@ namespace loguru { // Called only when needed, i.e. on a crash. std::string str = small_value.as_string(); // Format 'small_value' here somehow. - return Text{strdup(str.c_str())}; + return Text{STRDUP(str.c_str())}; } Text ec_to_text(const MyBigType* big_value) { // Called only when needed, i.e. on a crash. std::string str = big_value->as_string(); // Format 'big_value' here somehow. - return Text{strdup(str.c_str())}; + return Text{STRDUP(str.c_str())}; } } // namespace loguru @@ -965,11 +1029,11 @@ namespace loguru { \ auto str_left = loguru::format_value(val_left); \ auto str_right = loguru::format_value(val_right); \ - auto fail_info = loguru::textprintf("CHECK FAILED: %s %s %s (%s %s %s) ", \ + auto fail_info = loguru::textprintf("CHECK FAILED: " LOGURU_FMT(s) " " LOGURU_FMT(s) " " LOGURU_FMT(s) " (" LOGURU_FMT(s) " " LOGURU_FMT(s) " " LOGURU_FMT(s) ") ", \ #expr_left, #op, #expr_right, str_left.c_str(), #op, str_right.c_str()); \ auto user_msg = loguru::textprintf(__VA_ARGS__); \ loguru::log_and_abort(0, fail_info.c_str(), __FILE__, __LINE__, \ - "%s", user_msg.c_str()); \ + LOGURU_FMT(s), user_msg.c_str()); \ } \ } while (false)