forked from Research/WhisperCom
1389 lines
53 KiB
C++
1389 lines
53 KiB
C++
/*
|
||
Loguru logging library for C++, by Emil Ernerfeldt.
|
||
www.github.com/emilk/loguru
|
||
If you find Loguru useful, please let me know on twitter or in a mail!
|
||
Twitter: @ernerfeldt
|
||
Mail: emil.ernerfeldt@gmail.com
|
||
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, modify and distribute it as you see fit.
|
||
|
||
# Inspiration
|
||
Much of Loguru was inspired by GLOG, https://code.google.com/p/google-glog/.
|
||
The choice of public domain is fully due Sean T. Barrett
|
||
and his wonderful stb libraries at https://github.com/nothings/stb.
|
||
|
||
# Version history
|
||
* Version 0.1.0 - 2015-03-22 - Works great on Mac.
|
||
* Version 0.2.0 - 2015-09-17 - Removed the only dependency.
|
||
* Version 0.3.0 - 2015-10-02 - Drop-in replacement for most of GLOG
|
||
* Version 0.4.0 - 2015-10-07 - Single-file!
|
||
* Version 0.5.0 - 2015-10-17 - Improved file logging
|
||
* Version 0.6.0 - 2015-10-24 - Add stack traces
|
||
* Version 0.7.0 - 2015-10-27 - Signals
|
||
* Version 0.8.0 - 2015-10-30 - Color logging.
|
||
* Version 0.9.0 - 2015-11-26 - ABORT_S and proper handling of FATAL
|
||
* Version 1.0.0 - 2016-02-14 - ERROR_CONTEXT
|
||
* Version 1.1.0 - 2016-02-19 - -v OFF, -v INFO etc
|
||
* Version 1.1.1 - 2016-02-20 - textprintf vs strprintf
|
||
* Version 1.1.2 - 2016-02-22 - Remove g_alsologtostderr
|
||
* Version 1.1.3 - 2016-02-29 - ERROR_CONTEXT as linked list
|
||
* Version 1.2.0 - 2016-03-19 - Add get_thread_name()
|
||
* Version 1.2.1 - 2016-03-20 - Minor fixes
|
||
* Version 1.2.2 - 2016-03-29 - Fix issues with set_fatal_handler throwing an exception
|
||
* Version 1.2.3 - 2016-05-16 - Log current working directory in loguru::init().
|
||
* Version 1.2.4 - 2016-05-18 - Custom replacement for -v in loguru::init() by bjoernpollex
|
||
* Version 1.2.5 - 2016-05-18 - Add ability to print ERROR_CONTEXT of parent thread.
|
||
* Version 1.2.6 - 2016-05-19 - Bug fix regarding VLOG verbosity argument lacking ().
|
||
* Version 1.2.7 - 2016-05-23 - Fix PATH_MAX problem.
|
||
* Version 1.2.8 - 2016-05-26 - Add shutdown() and remove_all_callbacks()
|
||
* Version 1.2.9 - 2016-06-09 - Use a monotonic clock for uptime.
|
||
* Version 1.3.0 - 2016-07-20 - Fix issues with callback flush/close not being called.
|
||
* Version 1.3.1 - 2016-07-20 - Add LOGURU_UNSAFE_SIGNAL_HANDLER to toggle stacktrace on signals.
|
||
* Version 1.3.2 - 2016-07-20 - Add loguru::arguments()
|
||
* Version 1.4.0 - 2016-09-15 - Semantic versioning + add loguru::create_directories
|
||
* Version 1.4.1 - 2016-09-29 - Customize formating with LOGURU_FILENAME_WIDTH
|
||
* Version 1.5.0 - 2016-12-22 - LOGURU_USE_FMTLIB by kolis and LOGURU_WITH_FILEABS by scinart
|
||
* Version 1.5.1 - 2017-08-08 - Terminal colors on Windows 10 thanks to looki
|
||
* Version 1.6.0 - 2018-01-03 - Add LOGURU_RTTI and LOGURU_STACKTRACES settings
|
||
* Version 1.7.0 - 2018-01-03 - Add ability to turn off the preamble with loguru::g_preamble
|
||
* Version 1.7.1 - 2018-04-05 - Add function get_fatal_handler
|
||
* Version 1.7.2 - 2018-04-22 - Fix a bug where large file names could cause stack corruption (thanks @ccamporesi)
|
||
* 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 <loguru.hpp> where you want to use Loguru.
|
||
Then, in one .cpp file #include <loguru.cpp>
|
||
Make sure you compile with -std=c++11 -lstdc++ -lpthread -ldl
|
||
|
||
# Usage
|
||
For details, please see the official documentation at emilk.github.io/loguru
|
||
|
||
#include <loguru.hpp>
|
||
|
||
int main(int argc, char* argv[]) {
|
||
loguru::init(argc, argv);
|
||
|
||
// Put every log message in "everything.log":
|
||
loguru::add_file("everything.log", loguru::Append, loguru::Verbosity_MAX);
|
||
|
||
LOG_F(INFO, "The magic number is %d", 42);
|
||
}
|
||
|
||
*/
|
||
|
||
#if defined(LOGURU_IMPLEMENTATION)
|
||
#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:
|
||
#if defined(__clang__)
|
||
#pragma clang system_header
|
||
#elif defined(__GNUC__)
|
||
#pragma GCC system_header
|
||
#endif
|
||
|
||
#ifndef LOGURU_HAS_DECLARED_FORMAT_HEADER
|
||
#define LOGURU_HAS_DECLARED_FORMAT_HEADER
|
||
|
||
// 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 1
|
||
#define LOGURU_VERSION_PATCH 0
|
||
|
||
#if defined(_MSC_VER)
|
||
#include <sal.h> // Needed for _In_z_ etc annotations
|
||
#endif
|
||
|
||
// ----------------------------------------------------------------------------
|
||
|
||
#ifndef LOGURU_EXPORT
|
||
// Define to your project's export declaration if needed for use in a shared library.
|
||
#define LOGURU_EXPORT
|
||
#endif
|
||
|
||
#ifndef LOGURU_SCOPE_TEXT_SIZE
|
||
// Maximum length of text that can be printed by a LOG_SCOPE.
|
||
// This should be long enough to get most things, but short enough not to clutter the stack.
|
||
#define LOGURU_SCOPE_TEXT_SIZE 196
|
||
#endif
|
||
|
||
#ifndef LOGURU_FILENAME_WIDTH
|
||
// Width of the column containing the file name
|
||
#define LOGURU_FILENAME_WIDTH 23
|
||
#endif
|
||
|
||
#ifndef LOGURU_THREADNAME_WIDTH
|
||
// Width of the column containing the thread name
|
||
#define LOGURU_THREADNAME_WIDTH 16
|
||
#endif
|
||
|
||
#ifndef LOGURU_SCOPE_TIME_PRECISION
|
||
// Resolution of scope timers. 3=ms, 6=us, 9=ns
|
||
#define LOGURU_SCOPE_TIME_PRECISION 3
|
||
#endif
|
||
|
||
#ifndef LOGURU_CATCH_SIGABRT
|
||
// Should Loguru catch SIGABRT to print stack trace etc?
|
||
#define LOGURU_CATCH_SIGABRT 1
|
||
#endif
|
||
|
||
#ifndef LOGURU_VERBOSE_SCOPE_ENDINGS
|
||
// Show milliseconds and scope name at end of scope.
|
||
#define LOGURU_VERBOSE_SCOPE_ENDINGS 1
|
||
#endif
|
||
|
||
#ifndef LOGURU_REDEFINE_ASSERT
|
||
#define LOGURU_REDEFINE_ASSERT 0
|
||
#endif
|
||
|
||
#ifndef LOGURU_WITH_STREAMS
|
||
#define LOGURU_WITH_STREAMS 0
|
||
#endif
|
||
|
||
#ifndef LOGURU_REPLACE_GLOG
|
||
#define LOGURU_REPLACE_GLOG 0
|
||
#endif
|
||
|
||
#if LOGURU_REPLACE_GLOG
|
||
#undef LOGURU_WITH_STREAMS
|
||
#define LOGURU_WITH_STREAMS 1
|
||
#endif
|
||
|
||
#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
|
||
#undef LOGURU_WITH_STREAMS
|
||
#define LOGURU_WITH_STREAMS 1
|
||
#endif
|
||
|
||
#ifndef LOGURU_USE_FMTLIB
|
||
#define LOGURU_USE_FMTLIB 0
|
||
#endif
|
||
|
||
#ifndef LOGURU_WITH_FILEABS
|
||
#define LOGURU_WITH_FILEABS 0
|
||
#endif
|
||
|
||
#ifndef LOGURU_RTTI
|
||
#if defined(__clang__)
|
||
#if __has_feature(cxx_rtti)
|
||
#define LOGURU_RTTI 1
|
||
#endif
|
||
#elif defined(__GNUG__)
|
||
#if defined(__GXX_RTTI)
|
||
#define LOGURU_RTTI 1
|
||
#endif
|
||
#elif defined(_MSC_VER)
|
||
#if defined(_CPPRTTI)
|
||
#define LOGURU_RTTI 1
|
||
#endif
|
||
#endif
|
||
#endif
|
||
|
||
// --------------------------------------------------------------------
|
||
// Utility macros
|
||
|
||
#define LOGURU_CONCATENATE_IMPL(s1, s2) s1 ## s2
|
||
#define LOGURU_CONCATENATE(s1, s2) LOGURU_CONCATENATE_IMPL(s1, s2)
|
||
|
||
#ifdef __COUNTER__
|
||
# define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __COUNTER__)
|
||
#else
|
||
# define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __LINE__)
|
||
#endif
|
||
|
||
#if defined(__clang__) || defined(__GNUC__)
|
||
// Helper macro for declaring functions as having similar signature to printf.
|
||
// This allows the compiler to catch format errors at compile-time.
|
||
#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||
#define LOGURU_FORMAT_STRING_TYPE const char*
|
||
#elif defined(_MSC_VER)
|
||
#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
|
||
#define LOGURU_FORMAT_STRING_TYPE _In_z_ _Printf_format_string_ const char*
|
||
#else
|
||
#define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
|
||
#define LOGURU_FORMAT_STRING_TYPE const char*
|
||
#endif
|
||
|
||
// Used to mark log_and_abort for the benefit of the static analyzer and optimizer.
|
||
#if defined(_MSC_VER)
|
||
#define LOGURU_NORETURN __declspec(noreturn)
|
||
#else
|
||
#define LOGURU_NORETURN __attribute__((noreturn))
|
||
#endif
|
||
|
||
#if defined(_MSC_VER)
|
||
#define LOGURU_PREDICT_FALSE(x) (x)
|
||
#define LOGURU_PREDICT_TRUE(x) (x)
|
||
#else
|
||
#define LOGURU_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||
#define LOGURU_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||
#endif
|
||
|
||
#if LOGURU_USE_FMTLIB
|
||
#include <fmt/format.h>
|
||
#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
|
||
|
||
// --------------------------------------------------------------------
|
||
|
||
namespace loguru
|
||
{
|
||
// Simple RAII ownership of a char*.
|
||
class LOGURU_EXPORT Text
|
||
{
|
||
public:
|
||
explicit Text(char* owned_str) : _str(owned_str) {}
|
||
~Text();
|
||
Text(Text&& t)
|
||
{
|
||
_str = t._str;
|
||
t._str = nullptr;
|
||
}
|
||
Text(Text& t) = delete;
|
||
Text& operator=(Text& t) = delete;
|
||
void operator=(Text&& t) = delete;
|
||
|
||
const char* c_str() const { return _str; }
|
||
bool empty() const { return _str == nullptr || *_str == '\0'; }
|
||
|
||
char* release()
|
||
{
|
||
auto result = _str;
|
||
_str = nullptr;
|
||
return result;
|
||
}
|
||
|
||
private:
|
||
char* _str;
|
||
};
|
||
|
||
// Like printf, but returns the formated text.
|
||
#if LOGURU_USE_FMTLIB
|
||
LOGURU_EXPORT
|
||
Text vtextprintf(const char* format, fmt::format_args args);
|
||
|
||
template<typename... Args>
|
||
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
|
||
Text textprintf();
|
||
|
||
using Verbosity = int;
|
||
|
||
#undef FATAL
|
||
#undef ERROR
|
||
#undef WARNING
|
||
#undef INFO
|
||
#undef MAX
|
||
|
||
enum NamedVerbosity : Verbosity
|
||
{
|
||
// Used to mark an invalid verbosity. Do not log to this level.
|
||
Verbosity_INVALID = -10, // Never do LOG_F(INVALID)
|
||
|
||
// You may use Verbosity_OFF on g_stderr_verbosity, but for nothing else!
|
||
Verbosity_OFF = -9, // Never do LOG_F(OFF)
|
||
|
||
// Prefer to use ABORT_F or ABORT_S over LOG_F(FATAL) or LOG_S(FATAL).
|
||
Verbosity_FATAL = -3,
|
||
Verbosity_ERROR = -2,
|
||
Verbosity_WARNING = -1,
|
||
|
||
// Normal messages. By default written to stderr.
|
||
Verbosity_INFO = 0,
|
||
|
||
// Same as Verbosity_INFO in every way.
|
||
Verbosity_0 = 0,
|
||
|
||
// Verbosity levels 1-9 are generally not written to stderr, but are written to file.
|
||
Verbosity_1 = +1,
|
||
Verbosity_2 = +2,
|
||
Verbosity_3 = +3,
|
||
Verbosity_4 = +4,
|
||
Verbosity_5 = +5,
|
||
Verbosity_6 = +6,
|
||
Verbosity_7 = +7,
|
||
Verbosity_8 = +8,
|
||
Verbosity_9 = +9,
|
||
|
||
// Don not use higher verbosity levels, as that will make grepping log files harder.
|
||
Verbosity_MAX = +9,
|
||
};
|
||
|
||
struct Message
|
||
{
|
||
// You would generally print a Message by just concating the buffers without spacing.
|
||
// Optionally, ignore preamble and indentation.
|
||
Verbosity verbosity; // Already part of preamble
|
||
const char* filename; // Already part of preamble
|
||
unsigned line; // Already part of preamble
|
||
const char* preamble; // Date, time, uptime, thread, file:line, verbosity.
|
||
const char* indentation; // Just a bunch of spacing.
|
||
const char* prefix; // Assertion failure info goes here (or "").
|
||
const char* message; // User message goes here.
|
||
};
|
||
|
||
/* Everything with a verbosity equal or greater than g_stderr_verbosity will be
|
||
written to stderr. You can set this in code or via the -v argument.
|
||
Set to loguru::Verbosity_OFF to write nothing to stderr.
|
||
Default is 0, i.e. only log ERROR, WARNING and INFO are written to stderr.
|
||
*/
|
||
LOGURU_EXPORT extern Verbosity g_stderr_verbosity;
|
||
LOGURU_EXPORT extern bool g_colorlogtostderr; // True by default.
|
||
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
|
||
LOGURU_EXPORT extern bool g_preamble_uptime; // The time since init call
|
||
LOGURU_EXPORT extern bool g_preamble_thread; // The logging thread
|
||
LOGURU_EXPORT extern bool g_preamble_file; // The file from which the log originates from
|
||
LOGURU_EXPORT extern bool g_preamble_verbose; // The verbosity field
|
||
LOGURU_EXPORT extern bool g_preamble_pipe; // The pipe symbol right before the message
|
||
|
||
// May not throw!
|
||
typedef void (*log_handler_t)(void* user_data, const Message& message);
|
||
typedef void (*close_handler_t)(void* user_data);
|
||
typedef void (*flush_handler_t)(void* user_data);
|
||
|
||
// May throw if that's how you'd like to handle your errors.
|
||
typedef void (*fatal_handler_t)(const Message& message);
|
||
|
||
// Given a verbosity level, return the level's name or nullptr.
|
||
typedef const char* (*verbosity_to_name_t)(Verbosity verbosity);
|
||
|
||
// Given a verbosity level name, return the verbosity level or
|
||
// 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
|
||
* Program arguments logged
|
||
* Working dir logged
|
||
* Optional -v verbosity flag parsed
|
||
* Main thread name set to "main thread"
|
||
* Explanation of the preamble (date, threanmae etc) logged
|
||
|
||
loguru::init() will look for arguments meant for loguru and remove them.
|
||
Arguments meant for loguru are:
|
||
-v n Set loguru::g_stderr_verbosity level. Examples:
|
||
-v 3 Show verbosity level 3 and lower.
|
||
-v 0 Only show INFO, WARNING, ERROR, FATAL (default).
|
||
-v INFO Only show INFO, WARNING, ERROR, FATAL (default).
|
||
-v WARNING Only show WARNING, ERROR, FATAL.
|
||
-v ERROR Only show ERROR, FATAL.
|
||
-v FATAL Only show FATAL.
|
||
-v OFF Turn off logging to stderr.
|
||
|
||
Tip: You can set g_stderr_verbosity before calling loguru::init.
|
||
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 you something other than the -v flag by setting the verbosity_flag option.
|
||
*/
|
||
LOGURU_EXPORT
|
||
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.
|
||
LOGURU_EXPORT
|
||
void shutdown();
|
||
|
||
// What ~ will be replaced with, e.g. "/home/your_user_name/"
|
||
LOGURU_EXPORT
|
||
const char* home_dir();
|
||
|
||
/* Returns the name of the app as given in argv[0] but without leading path.
|
||
That is, if argv[0] is "../foo/app" this will return "app".
|
||
*/
|
||
LOGURU_EXPORT
|
||
const char* argv0_filename();
|
||
|
||
// Returns all arguments given to loguru::init(), but escaped with a single space as separator.
|
||
LOGURU_EXPORT
|
||
const char* arguments();
|
||
|
||
// Returns the path to the current working dir when loguru::init() was called.
|
||
LOGURU_EXPORT
|
||
const char* current_dir();
|
||
|
||
// Returns the part of the path after the last / or \ (if any).
|
||
LOGURU_EXPORT
|
||
const char* filename(const char* path);
|
||
|
||
// e.g. "foo/bar/baz.ext" will create the directories "foo/" and "foo/bar/"
|
||
LOGURU_EXPORT
|
||
bool create_directories(const char* file_path_const);
|
||
|
||
// Writes date and time with millisecond precision, e.g. "20151017_161503.123"
|
||
LOGURU_EXPORT
|
||
void write_date_time(char* buff, unsigned buff_size);
|
||
|
||
// Helper: thread-safe version strerror
|
||
LOGURU_EXPORT
|
||
Text errno_as_text();
|
||
|
||
/* Given a prefix of e.g. "~/loguru/" this might return
|
||
"/home/your_username/loguru/app_name/20151017_161503.123.log"
|
||
|
||
where "app_name" is a sanitized version of argv[0].
|
||
*/
|
||
LOGURU_EXPORT
|
||
void suggest_log_path(const char* prefix, char* buff, unsigned buff_size);
|
||
|
||
enum FileMode { Truncate, Append };
|
||
|
||
/* Will log to a file at the given path.
|
||
Any logging message with a verbosity lower or equal to
|
||
the given verbosity will be included.
|
||
The function will create all directories in 'path' if needed.
|
||
If path starts with a ~, it will be replaced with loguru::home_dir()
|
||
To stop the file logging, just call loguru::remove_callback(path) with the same path.
|
||
*/
|
||
LOGURU_EXPORT
|
||
bool add_file(const char* path, FileMode mode, Verbosity verbosity);
|
||
|
||
/* Will be called right before abort().
|
||
You can for instance use this to print custom error messages, or throw an exception.
|
||
Feel free to call LOG:ing function from this, but not FATAL ones! */
|
||
LOGURU_EXPORT
|
||
void set_fatal_handler(fatal_handler_t handler);
|
||
|
||
// Get the current fatal handler, if any. Default value is nullptr.
|
||
LOGURU_EXPORT
|
||
fatal_handler_t get_fatal_handler();
|
||
|
||
/* Will be called on each log messages with a verbosity less or equal to the given one.
|
||
Useful for displaying messages on-screen in a game, for example.
|
||
The given on_close is also expected to flush (if desired).
|
||
*/
|
||
LOGURU_EXPORT
|
||
void add_callback(
|
||
const char* id,
|
||
log_handler_t callback,
|
||
void* user_data,
|
||
Verbosity verbosity,
|
||
close_handler_t on_close = nullptr,
|
||
flush_handler_t on_flush = nullptr);
|
||
|
||
/* Set a callback that returns custom verbosity level names. If callback
|
||
is nullptr or returns nullptr, default log names will be used.
|
||
*/
|
||
LOGURU_EXPORT
|
||
void set_verbosity_to_name_callback(verbosity_to_name_t callback);
|
||
|
||
/* Set a callback that returns the verbosity level matching a name. The
|
||
callback should return Verbosity_INVALID if the name is not
|
||
recognized.
|
||
*/
|
||
LOGURU_EXPORT
|
||
void set_name_to_verbosity_callback(name_to_verbosity_t callback);
|
||
|
||
/* Get a custom name for a specific verbosity, if one exists, or nullptr. */
|
||
LOGURU_EXPORT
|
||
const char* get_verbosity_name(Verbosity verbosity);
|
||
|
||
/* Get the verbosity enum value from a custom 4-character level name, if one exists.
|
||
If the name does not match a custom level name, Verbosity_INVALID is returned.
|
||
*/
|
||
LOGURU_EXPORT
|
||
Verbosity get_verbosity_from_name(const char* name);
|
||
|
||
// Returns true iff the callback was found (and removed).
|
||
LOGURU_EXPORT
|
||
bool remove_callback(const char* id);
|
||
|
||
// Shut down all file logging and any other callback hooks installed.
|
||
LOGURU_EXPORT
|
||
void remove_all_callbacks();
|
||
|
||
// Returns the maximum of g_stderr_verbosity and all file/custom outputs.
|
||
LOGURU_EXPORT
|
||
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 <typename... Args>
|
||
LOGURU_EXPORT
|
||
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 <typename... Args>
|
||
LOGURU_EXPORT
|
||
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
|
||
void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
|
||
|
||
// Log without any preamble or indentation.
|
||
LOGURU_EXPORT
|
||
void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
|
||
#endif // !LOGURU_USE_FMTLIB
|
||
|
||
// Helper class for LOG_SCOPE_F
|
||
class LOGURU_EXPORT LogScopeRAII
|
||
{
|
||
public:
|
||
LogScopeRAII() : _file(nullptr) {} // No logging
|
||
LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
|
||
~LogScopeRAII();
|
||
|
||
#if defined(_MSC_VER) && _MSC_VER > 1800
|
||
// older MSVC default move ctors close the scope on move. See
|
||
// issue #43
|
||
LogScopeRAII(LogScopeRAII&& other)
|
||
: _verbosity(other._verbosity)
|
||
, _file(other._file)
|
||
, _line(other._line)
|
||
, _indent_stderr(other._indent_stderr)
|
||
, _start_time_ns(other._start_time_ns)
|
||
{
|
||
// Make sure the tmp object's destruction doesn't close the scope:
|
||
other._file = nullptr;
|
||
|
||
for (unsigned int i = 0; i < LOGURU_SCOPE_TEXT_SIZE; ++i) {
|
||
_name[i] = other._name[i];
|
||
}
|
||
}
|
||
#else
|
||
LogScopeRAII(LogScopeRAII&&) = default;
|
||
#endif
|
||
|
||
private:
|
||
LogScopeRAII(const LogScopeRAII&) = delete;
|
||
LogScopeRAII& operator=(const LogScopeRAII&) = delete;
|
||
void operator=(LogScopeRAII&&) = delete;
|
||
|
||
Verbosity _verbosity;
|
||
const char* _file; // Set to null if we are disabled due to verbosity
|
||
unsigned _line;
|
||
bool _indent_stderr; // Did we?
|
||
long long _start_time_ns;
|
||
char _name[LOGURU_SCOPE_TEXT_SIZE];
|
||
};
|
||
|
||
// 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 <typename... Args>
|
||
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);
|
||
|
||
// Flush output to stderr and files.
|
||
// If g_flush_interval_ms is set to non-zero, this will be called automatically this often.
|
||
// If not set, you do not need to call this at all.
|
||
LOGURU_EXPORT
|
||
void flush();
|
||
|
||
template<class T> inline Text format_value(const T&) { return textprintf("N/A"); }
|
||
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.
|
||
These thread names may or may not be the same as the system thread names,
|
||
depending on the system.
|
||
Try to limit the thread name to 15 characters or less. */
|
||
LOGURU_EXPORT
|
||
void set_thread_name(const char* name);
|
||
|
||
/* Returns the thread name for this thread.
|
||
On OSX this will return the system thread name (settable from both within and without Loguru).
|
||
On other systems it will return whatever you set in set_thread_name();
|
||
If no thread name is set, this will return a hexadecimal thread id.
|
||
length should be the number of bytes available in the buffer.
|
||
17 is a good number for length.
|
||
right_align_hext_id means any hexadecimal thread id will be written to the end of buffer.
|
||
*/
|
||
LOGURU_EXPORT
|
||
void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id);
|
||
|
||
/* Generates a readable stacktrace as a string.
|
||
'skip' specifies how many stack frames to skip.
|
||
For instance, the default skip (1) means:
|
||
don't include the call to loguru::stacktrace in the stack trace. */
|
||
LOGURU_EXPORT
|
||
Text stacktrace(int skip = 1);
|
||
|
||
/* Add a string to be replaced with something else in the stack output.
|
||
|
||
For instance, instead of having a stack trace look like this:
|
||
0x41f541 some_function(std::basic_ofstream<char, std::char_traits<char> >&)
|
||
You can clean it up with:
|
||
auto verbose_type_name = loguru::demangle(typeid(std::ofstream).name());
|
||
loguru::add_stack_cleanup(verbose_type_name.c_str(); "std::ofstream");
|
||
So the next time you will instead see:
|
||
0x41f541 some_function(std::ofstream&)
|
||
|
||
`replace_with_this` must be shorter than `find_this`.
|
||
*/
|
||
LOGURU_EXPORT
|
||
void add_stack_cleanup(const char* find_this, const char* replace_with_this);
|
||
|
||
// Example: demangle(typeid(std::ofstream).name()) -> "std::basic_ofstream<char, std::char_traits<char> >"
|
||
LOGURU_EXPORT
|
||
Text demangle(const char* name);
|
||
|
||
// ------------------------------------------------------------------------
|
||
/*
|
||
Not all terminals support colors, but if they do, and g_colorlogtostderr
|
||
is set, Loguru will write them to stderr to make errors in red, etc.
|
||
|
||
You also have the option to manually use them, via the function below.
|
||
|
||
Note, however, that if you do, the color codes could end up in your logfile!
|
||
|
||
This means if you intend to use them functions you should either:
|
||
* Use them on the stderr/stdout directly (bypass Loguru).
|
||
* Don't add file outputs to Loguru.
|
||
* Expect some \e[1m things in your logfile.
|
||
|
||
Usage:
|
||
printf("%sRed%sGreen%sBold green%sClear again\n",
|
||
loguru::terminal_red(), loguru::terminal_green(),
|
||
loguru::terminal_bold(), loguru::terminal_reset());
|
||
|
||
If the terminal at hand does not support colors the above output
|
||
will just not have funky \e[1m things showing.
|
||
*/
|
||
|
||
// Do the output terminal support colors?
|
||
LOGURU_EXPORT
|
||
bool terminal_has_color();
|
||
|
||
// Colors
|
||
LOGURU_EXPORT const char* terminal_black();
|
||
LOGURU_EXPORT const char* terminal_red();
|
||
LOGURU_EXPORT const char* terminal_green();
|
||
LOGURU_EXPORT const char* terminal_yellow();
|
||
LOGURU_EXPORT const char* terminal_blue();
|
||
LOGURU_EXPORT const char* terminal_purple();
|
||
LOGURU_EXPORT const char* terminal_cyan();
|
||
LOGURU_EXPORT const char* terminal_light_gray();
|
||
LOGURU_EXPORT const char* terminal_light_red();
|
||
LOGURU_EXPORT const char* terminal_white();
|
||
|
||
// Formating
|
||
LOGURU_EXPORT const char* terminal_bold();
|
||
LOGURU_EXPORT const char* terminal_underline();
|
||
|
||
// You should end each line with this!
|
||
LOGURU_EXPORT const char* terminal_reset();
|
||
|
||
// --------------------------------------------------------------------
|
||
// Error context related:
|
||
|
||
struct StringStream;
|
||
|
||
// Use this in your EcEntryBase::print_value overload.
|
||
LOGURU_EXPORT
|
||
void stream_print(StringStream& out_string_stream, const char* text);
|
||
|
||
class LOGURU_EXPORT EcEntryBase
|
||
{
|
||
public:
|
||
EcEntryBase(const char* file, unsigned line, const char* descr);
|
||
~EcEntryBase();
|
||
EcEntryBase(const EcEntryBase&) = delete;
|
||
EcEntryBase(EcEntryBase&&) = delete;
|
||
EcEntryBase& operator=(const EcEntryBase&) = delete;
|
||
EcEntryBase& operator=(EcEntryBase&&) = delete;
|
||
|
||
virtual void print_value(StringStream& out_string_stream) const = 0;
|
||
|
||
EcEntryBase* previous() const { return _previous; }
|
||
|
||
// private:
|
||
const char* _file;
|
||
unsigned _line;
|
||
const char* _descr;
|
||
EcEntryBase* _previous;
|
||
};
|
||
|
||
template<typename T>
|
||
class EcEntryData : public EcEntryBase
|
||
{
|
||
public:
|
||
using Printer = Text(*)(T data);
|
||
|
||
EcEntryData(const char* file, unsigned line, const char* descr, T data, Printer&& printer)
|
||
: EcEntryBase(file, line, descr), _data(data), _printer(printer) {}
|
||
|
||
virtual void print_value(StringStream& out_string_stream) const override
|
||
{
|
||
const auto str = _printer(_data);
|
||
stream_print(out_string_stream, str.c_str());
|
||
}
|
||
|
||
private:
|
||
T _data;
|
||
Printer _printer;
|
||
};
|
||
|
||
// template<typename Printer>
|
||
// class EcEntryLambda : public EcEntryBase
|
||
// {
|
||
// public:
|
||
// EcEntryLambda(const char* file, unsigned line, const char* descr, Printer&& printer)
|
||
// : EcEntryBase(file, line, descr), _printer(std::move(printer)) {}
|
||
|
||
// virtual void print_value(StringStream& out_string_stream) const override
|
||
// {
|
||
// const auto str = _printer();
|
||
// stream_print(out_string_stream, str.c_str());
|
||
// }
|
||
|
||
// private:
|
||
// Printer _printer;
|
||
// };
|
||
|
||
// template<typename Printer>
|
||
// EcEntryLambda<Printer> make_ec_entry_lambda(const char* file, unsigned line, const char* descr, Printer&& printer)
|
||
// {
|
||
// return {file, line, descr, std::move(printer)};
|
||
// }
|
||
|
||
template <class T>
|
||
struct decay_char_array { using type = T; };
|
||
|
||
template <unsigned long long N>
|
||
struct decay_char_array<const char(&)[N]> { using type = const char*; };
|
||
|
||
template <class T>
|
||
struct make_const_ptr { using type = T; };
|
||
|
||
template <class T>
|
||
struct make_const_ptr<T*> { using type = const T*; };
|
||
|
||
template <class T>
|
||
struct make_ec_type { using type = typename make_const_ptr<typename decay_char_array<T>::type>::type; };
|
||
|
||
/* A stack trace gives you the names of the function at the point of a crash.
|
||
With ERROR_CONTEXT, you can also get the values of select local variables.
|
||
Usage:
|
||
|
||
void process_customers(const std::string& filename)
|
||
{
|
||
ERROR_CONTEXT("Processing file", filename.c_str());
|
||
for (int customer_index : ...)
|
||
{
|
||
ERROR_CONTEXT("Customer index", customer_index);
|
||
...
|
||
}
|
||
}
|
||
|
||
The context is in effect during the scope of the ERROR_CONTEXT.
|
||
Use loguru::get_error_context() to get the contents of the active error contexts.
|
||
|
||
Example result:
|
||
|
||
------------------------------------------------
|
||
[ErrorContext] main.cpp:416 Processing file: "customers.json"
|
||
[ErrorContext] main.cpp:417 Customer index: 42
|
||
------------------------------------------------
|
||
|
||
Error contexts are printed automatically on crashes, and only on crashes.
|
||
This makes them much faster than logging the value of a variable.
|
||
*/
|
||
#define ERROR_CONTEXT(descr, data) \
|
||
const loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type> \
|
||
LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)( \
|
||
__FILE__, __LINE__, descr, data, \
|
||
static_cast<loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type>::Printer>(loguru::ec_to_text) ) // For better error messages
|
||
|
||
/*
|
||
#define ERROR_CONTEXT(descr, data) \
|
||
const auto LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)( \
|
||
loguru::make_ec_entry_lambda(__FILE__, __LINE__, descr, \
|
||
[=](){ return loguru::ec_to_text(data); }))
|
||
*/
|
||
|
||
using EcHandle = const EcEntryBase*;
|
||
|
||
/*
|
||
Get a light-weight handle to the error context stack on this thread.
|
||
The handle is valid as long as the current thread has no changes to its error context stack.
|
||
You can pass the handle to loguru::get_error_context on another thread.
|
||
This can be very useful for when you have a parent thread spawning several working threads,
|
||
and you want the error context of the parent thread to get printed (too) when there is an
|
||
error on the child thread. You can accomplish this thusly:
|
||
|
||
void foo(const char* parameter)
|
||
{
|
||
ERROR_CONTEXT("parameter", parameter)
|
||
const auto parent_ec_handle = loguru::get_thread_ec_handle();
|
||
|
||
std::thread([=]{
|
||
loguru::set_thread_name("child thread");
|
||
ERROR_CONTEXT("parent context", parent_ec_handle);
|
||
dangerous_code();
|
||
}.join();
|
||
}
|
||
|
||
*/
|
||
LOGURU_EXPORT
|
||
EcHandle get_thread_ec_handle();
|
||
|
||
// Get a string describing the current stack of error context. Empty string if there is none.
|
||
LOGURU_EXPORT
|
||
Text get_error_context();
|
||
|
||
// Get a string describing the error context of the given thread handle.
|
||
LOGURU_EXPORT
|
||
Text get_error_context_for(EcHandle ec_handle);
|
||
|
||
// ------------------------------------------------------------------------
|
||
|
||
LOGURU_EXPORT Text ec_to_text(const char* data);
|
||
LOGURU_EXPORT Text ec_to_text(char data);
|
||
LOGURU_EXPORT Text ec_to_text(int data);
|
||
LOGURU_EXPORT Text ec_to_text(unsigned int data);
|
||
LOGURU_EXPORT Text ec_to_text(long data);
|
||
LOGURU_EXPORT Text ec_to_text(unsigned long data);
|
||
LOGURU_EXPORT Text ec_to_text(long long data);
|
||
LOGURU_EXPORT Text ec_to_text(unsigned long long data);
|
||
LOGURU_EXPORT Text ec_to_text(float data);
|
||
LOGURU_EXPORT Text ec_to_text(double data);
|
||
LOGURU_EXPORT Text ec_to_text(long double data);
|
||
LOGURU_EXPORT Text ec_to_text(EcHandle);
|
||
|
||
/*
|
||
You can add ERROR_CONTEXT support for your own types by overloading ec_to_text. Here's how:
|
||
|
||
some.hpp:
|
||
namespace loguru {
|
||
Text ec_to_text(MySmallType data)
|
||
Text ec_to_text(const MyBigType* data)
|
||
} // namespace loguru
|
||
|
||
some.cpp:
|
||
namespace loguru {
|
||
Text ec_to_text(MySmallType small_value)
|
||
{
|
||
// 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())};
|
||
}
|
||
|
||
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())};
|
||
}
|
||
} // namespace loguru
|
||
|
||
Any file that include some.hpp:
|
||
void foo(MySmallType small, const MyBigType& big)
|
||
{
|
||
ERROR_CONTEXT("Small", small); // Copy ´small` by value.
|
||
ERROR_CONTEXT("Big", &big); // `big` should not change during this scope!
|
||
....
|
||
}
|
||
*/
|
||
} // namespace loguru
|
||
|
||
// --------------------------------------------------------------------
|
||
// Logging macros
|
||
|
||
// LOG_F(2, "Only logged if verbosity is 2 or higher: %d", some_number);
|
||
#define VLOG_F(verbosity, ...) \
|
||
((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0 \
|
||
: loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
|
||
|
||
// LOG_F(INFO, "Foo: %d", some_number);
|
||
#define LOG_F(verbosity_name, ...) VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
|
||
|
||
#define VLOG_IF_F(verbosity, cond, ...) \
|
||
((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
|
||
? (void)0 \
|
||
: loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
|
||
|
||
#define LOG_IF_F(verbosity_name, cond, ...) \
|
||
VLOG_IF_F(loguru::Verbosity_ ## verbosity_name, cond, __VA_ARGS__)
|
||
|
||
#define VLOG_SCOPE_F(verbosity, ...) \
|
||
loguru::LogScopeRAII LOGURU_ANONYMOUS_VARIABLE(error_context_RAII_) = \
|
||
((verbosity) > loguru::current_verbosity_cutoff()) ? loguru::LogScopeRAII() : \
|
||
loguru::LogScopeRAII(verbosity, __FILE__, __LINE__, __VA_ARGS__)
|
||
|
||
// Raw logging - no preamble, no indentation. Slightly faster than full logging.
|
||
#define RAW_VLOG_F(verbosity, ...) \
|
||
((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0 \
|
||
: loguru::raw_log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
|
||
|
||
#define RAW_LOG_F(verbosity_name, ...) RAW_VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
|
||
|
||
// Use to book-end a scope. Affects logging on all threads.
|
||
#define LOG_SCOPE_F(verbosity_name, ...) \
|
||
VLOG_SCOPE_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
|
||
|
||
#define LOG_SCOPE_FUNCTION(verbosity_name) LOG_SCOPE_F(verbosity_name, __func__)
|
||
|
||
// -----------------------------------------------
|
||
// ABORT_F macro. Usage: ABORT_F("Cause of error: %s", error_str);
|
||
|
||
// Message is optional
|
||
#define ABORT_F(...) loguru::log_and_abort(0, "ABORT: ", __FILE__, __LINE__, __VA_ARGS__)
|
||
|
||
// --------------------------------------------------------------------
|
||
// CHECK_F macros:
|
||
|
||
#define CHECK_WITH_INFO_F(test, info, ...) \
|
||
LOGURU_PREDICT_TRUE((test) == true) ? (void)0 : loguru::log_and_abort(0, "CHECK FAILED: " info " ", __FILE__, \
|
||
__LINE__, ##__VA_ARGS__)
|
||
|
||
/* Checked at runtime too. Will print error, then call fatal_handler (if any), then 'abort'.
|
||
Note that the test must be boolean.
|
||
CHECK_F(ptr); will not compile, but CHECK_F(ptr != nullptr); will. */
|
||
#define CHECK_F(test, ...) CHECK_WITH_INFO_F(test, #test, ##__VA_ARGS__)
|
||
|
||
#define CHECK_NOTNULL_F(x, ...) CHECK_WITH_INFO_F((x) != nullptr, #x " != nullptr", ##__VA_ARGS__)
|
||
|
||
#define CHECK_OP_F(expr_left, expr_right, op, ...) \
|
||
do \
|
||
{ \
|
||
auto val_left = expr_left; \
|
||
auto val_right = expr_right; \
|
||
if (! LOGURU_PREDICT_TRUE(val_left op val_right)) \
|
||
{ \
|
||
auto str_left = loguru::format_value(val_left); \
|
||
auto str_right = loguru::format_value(val_right); \
|
||
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__, \
|
||
LOGURU_FMT(s), user_msg.c_str()); \
|
||
} \
|
||
} while (false)
|
||
|
||
#ifndef LOGURU_DEBUG_LOGGING
|
||
#ifndef NDEBUG
|
||
#define LOGURU_DEBUG_LOGGING 1
|
||
#else
|
||
#define LOGURU_DEBUG_LOGGING 0
|
||
#endif
|
||
#endif
|
||
|
||
#if LOGURU_DEBUG_LOGGING
|
||
// Debug logging enabled:
|
||
#define DLOG_F(verbosity_name, ...) LOG_F(verbosity_name, __VA_ARGS__)
|
||
#define DVLOG_F(verbosity, ...) VLOG_F(verbosity, __VA_ARGS__)
|
||
#define DLOG_IF_F(verbosity_name, ...) LOG_IF_F(verbosity_name, __VA_ARGS__)
|
||
#define DVLOG_IF_F(verbosity, ...) VLOG_IF_F(verbosity, __VA_ARGS__)
|
||
#define DRAW_LOG_F(verbosity_name, ...) RAW_LOG_F(verbosity_name, __VA_ARGS__)
|
||
#define DRAW_VLOG_F(verbosity, ...) RAW_VLOG_F(verbosity, __VA_ARGS__)
|
||
#else
|
||
// Debug logging disabled:
|
||
#define DLOG_F(verbosity_name, ...)
|
||
#define DVLOG_F(verbosity, ...)
|
||
#define DLOG_IF_F(verbosity_name, ...)
|
||
#define DVLOG_IF_F(verbosity, ...)
|
||
#define DRAW_LOG_F(verbosity_name, ...)
|
||
#define DRAW_VLOG_F(verbosity, ...)
|
||
#endif
|
||
|
||
#define CHECK_EQ_F(a, b, ...) CHECK_OP_F(a, b, ==, ##__VA_ARGS__)
|
||
#define CHECK_NE_F(a, b, ...) CHECK_OP_F(a, b, !=, ##__VA_ARGS__)
|
||
#define CHECK_LT_F(a, b, ...) CHECK_OP_F(a, b, < , ##__VA_ARGS__)
|
||
#define CHECK_GT_F(a, b, ...) CHECK_OP_F(a, b, > , ##__VA_ARGS__)
|
||
#define CHECK_LE_F(a, b, ...) CHECK_OP_F(a, b, <=, ##__VA_ARGS__)
|
||
#define CHECK_GE_F(a, b, ...) CHECK_OP_F(a, b, >=, ##__VA_ARGS__)
|
||
|
||
#ifndef LOGURU_DEBUG_CHECKS
|
||
#ifndef NDEBUG
|
||
#define LOGURU_DEBUG_CHECKS 1
|
||
#else
|
||
#define LOGURU_DEBUG_CHECKS 0
|
||
#endif
|
||
#endif
|
||
|
||
#if LOGURU_DEBUG_CHECKS
|
||
// Debug checks enabled:
|
||
#define DCHECK_F(test, ...) CHECK_F(test, ##__VA_ARGS__)
|
||
#define DCHECK_NOTNULL_F(x, ...) CHECK_NOTNULL_F(x, ##__VA_ARGS__)
|
||
#define DCHECK_EQ_F(a, b, ...) CHECK_EQ_F(a, b, ##__VA_ARGS__)
|
||
#define DCHECK_NE_F(a, b, ...) CHECK_NE_F(a, b, ##__VA_ARGS__)
|
||
#define DCHECK_LT_F(a, b, ...) CHECK_LT_F(a, b, ##__VA_ARGS__)
|
||
#define DCHECK_LE_F(a, b, ...) CHECK_LE_F(a, b, ##__VA_ARGS__)
|
||
#define DCHECK_GT_F(a, b, ...) CHECK_GT_F(a, b, ##__VA_ARGS__)
|
||
#define DCHECK_GE_F(a, b, ...) CHECK_GE_F(a, b, ##__VA_ARGS__)
|
||
#else
|
||
// Debug checks disabled:
|
||
#define DCHECK_F(test, ...)
|
||
#define DCHECK_NOTNULL_F(x, ...)
|
||
#define DCHECK_EQ_F(a, b, ...)
|
||
#define DCHECK_NE_F(a, b, ...)
|
||
#define DCHECK_LT_F(a, b, ...)
|
||
#define DCHECK_LE_F(a, b, ...)
|
||
#define DCHECK_GT_F(a, b, ...)
|
||
#define DCHECK_GE_F(a, b, ...)
|
||
#endif // NDEBUG
|
||
|
||
|
||
#if LOGURU_REDEFINE_ASSERT
|
||
#undef assert
|
||
#ifndef NDEBUG
|
||
// Debug:
|
||
#define assert(test) CHECK_WITH_INFO_F(!!(test), #test) // HACK
|
||
#else
|
||
#define assert(test)
|
||
#endif
|
||
#endif // LOGURU_REDEFINE_ASSERT
|
||
|
||
#endif // LOGURU_HAS_DECLARED_FORMAT_HEADER
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// .dP"Y8 888888 88""Yb 888888 db 8b d8 .dP"Y8
|
||
// `Ybo." 88 88__dP 88__ dPYb 88b d88 `Ybo."
|
||
// o.`Y8b 88 88"Yb 88"" dP__Yb 88YbdP88 o.`Y8b
|
||
// 8bodP' 88 88 Yb 888888 dP""""Yb 88 YY 88 8bodP'
|
||
|
||
#if LOGURU_WITH_STREAMS
|
||
#ifndef LOGURU_HAS_DECLARED_STREAMS_HEADER
|
||
#define LOGURU_HAS_DECLARED_STREAMS_HEADER
|
||
|
||
/* This file extends loguru to enable std::stream-style logging, a la Glog.
|
||
It's an optional feature behind the LOGURU_WITH_STREAMS settings
|
||
because including it everywhere will slow down compilation times.
|
||
*/
|
||
|
||
#include <cstdarg>
|
||
#include <sstream> // Adds about 38 kLoC on clang.
|
||
#include <string>
|
||
|
||
namespace loguru
|
||
{
|
||
// Like sprintf, but returns the formated text.
|
||
LOGURU_EXPORT
|
||
std::string strprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2);
|
||
|
||
// Like vsprintf, but returns the formated text.
|
||
LOGURU_EXPORT
|
||
std::string vstrprintf(LOGURU_FORMAT_STRING_TYPE format, va_list) LOGURU_PRINTF_LIKE(1, 0);
|
||
|
||
class LOGURU_EXPORT StreamLogger
|
||
{
|
||
public:
|
||
StreamLogger(Verbosity verbosity, const char* file, unsigned line) : _verbosity(verbosity), _file(file), _line(line) {}
|
||
~StreamLogger() noexcept(false);
|
||
|
||
template<typename T>
|
||
StreamLogger& operator<<(const T& t)
|
||
{
|
||
_ss << t;
|
||
return *this;
|
||
}
|
||
|
||
// std::endl and other iomanip:s.
|
||
StreamLogger& operator<<(std::ostream&(*f)(std::ostream&))
|
||
{
|
||
f(_ss);
|
||
return *this;
|
||
}
|
||
|
||
private:
|
||
Verbosity _verbosity;
|
||
const char* _file;
|
||
unsigned _line;
|
||
std::ostringstream _ss;
|
||
};
|
||
|
||
class LOGURU_EXPORT AbortLogger
|
||
{
|
||
public:
|
||
AbortLogger(const char* expr, const char* file, unsigned line) : _expr(expr), _file(file), _line(line) { }
|
||
LOGURU_NORETURN ~AbortLogger() noexcept(false);
|
||
|
||
template<typename T>
|
||
AbortLogger& operator<<(const T& t)
|
||
{
|
||
_ss << t;
|
||
return *this;
|
||
}
|
||
|
||
// std::endl and other iomanip:s.
|
||
AbortLogger& operator<<(std::ostream&(*f)(std::ostream&))
|
||
{
|
||
f(_ss);
|
||
return *this;
|
||
}
|
||
|
||
private:
|
||
const char* _expr;
|
||
const char* _file;
|
||
unsigned _line;
|
||
std::ostringstream _ss;
|
||
};
|
||
|
||
class LOGURU_EXPORT Voidify
|
||
{
|
||
public:
|
||
Voidify() {}
|
||
// This has to be an operator with a precedence lower than << but higher than ?:
|
||
void operator&(const StreamLogger&) { }
|
||
void operator&(const AbortLogger&) { }
|
||
};
|
||
|
||
/* Helper functions for CHECK_OP_S macro.
|
||
GLOG trick: The (int, int) specialization works around the issue that the compiler
|
||
will not instantiate the template version of the function on values of unnamed enum type. */
|
||
#define DEFINE_CHECK_OP_IMPL(name, op) \
|
||
template <typename T1, typename T2> \
|
||
inline std::string* name(const char* expr, const T1& v1, const char* op_str, const T2& v2) \
|
||
{ \
|
||
if (LOGURU_PREDICT_TRUE(v1 op v2)) { return NULL; } \
|
||
std::ostringstream ss; \
|
||
ss << "CHECK FAILED: " << expr << " (" << v1 << " " << op_str << " " << v2 << ") "; \
|
||
return new std::string(ss.str()); \
|
||
} \
|
||
inline std::string* name(const char* expr, int v1, const char* op_str, int v2) \
|
||
{ \
|
||
return name<int, int>(expr, v1, op_str, v2); \
|
||
}
|
||
|
||
DEFINE_CHECK_OP_IMPL(check_EQ_impl, ==)
|
||
DEFINE_CHECK_OP_IMPL(check_NE_impl, !=)
|
||
DEFINE_CHECK_OP_IMPL(check_LE_impl, <=)
|
||
DEFINE_CHECK_OP_IMPL(check_LT_impl, < )
|
||
DEFINE_CHECK_OP_IMPL(check_GE_impl, >=)
|
||
DEFINE_CHECK_OP_IMPL(check_GT_impl, > )
|
||
#undef DEFINE_CHECK_OP_IMPL
|
||
|
||
/* GLOG trick: Function is overloaded for integral types to allow static const integrals
|
||
declared in classes and not defined to be used as arguments to CHECK* macros. */
|
||
template <class T>
|
||
inline const T& referenceable_value(const T& t) { return t; }
|
||
inline char referenceable_value(char t) { return t; }
|
||
inline unsigned char referenceable_value(unsigned char t) { return t; }
|
||
inline signed char referenceable_value(signed char t) { return t; }
|
||
inline short referenceable_value(short t) { return t; }
|
||
inline unsigned short referenceable_value(unsigned short t) { return t; }
|
||
inline int referenceable_value(int t) { return t; }
|
||
inline unsigned int referenceable_value(unsigned int t) { return t; }
|
||
inline long referenceable_value(long t) { return t; }
|
||
inline unsigned long referenceable_value(unsigned long t) { return t; }
|
||
inline long long referenceable_value(long long t) { return t; }
|
||
inline unsigned long long referenceable_value(unsigned long long t) { return t; }
|
||
} // namespace loguru
|
||
|
||
// -----------------------------------------------
|
||
// Logging macros:
|
||
|
||
// usage: LOG_STREAM(INFO) << "Foo " << std::setprecision(10) << some_value;
|
||
#define VLOG_IF_S(verbosity, cond) \
|
||
((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
|
||
? (void)0 \
|
||
: loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
|
||
#define LOG_IF_S(verbosity_name, cond) VLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
|
||
#define VLOG_S(verbosity) VLOG_IF_S(verbosity, true)
|
||
#define LOG_S(verbosity_name) VLOG_S(loguru::Verbosity_ ## verbosity_name)
|
||
|
||
// -----------------------------------------------
|
||
// ABORT_S macro. Usage: ABORT_S() << "Causo of error: " << details;
|
||
|
||
#define ABORT_S() loguru::Voidify() & loguru::AbortLogger("ABORT: ", __FILE__, __LINE__)
|
||
|
||
// -----------------------------------------------
|
||
// CHECK_S macros:
|
||
|
||
#define CHECK_WITH_INFO_S(cond, info) \
|
||
LOGURU_PREDICT_TRUE((cond) == true) \
|
||
? (void)0 \
|
||
: loguru::Voidify() & loguru::AbortLogger("CHECK FAILED: " info " ", __FILE__, __LINE__)
|
||
|
||
#define CHECK_S(cond) CHECK_WITH_INFO_S(cond, #cond)
|
||
#define CHECK_NOTNULL_S(x) CHECK_WITH_INFO_S((x) != nullptr, #x " != nullptr")
|
||
|
||
#define CHECK_OP_S(function_name, expr1, op, expr2) \
|
||
while (auto error_string = loguru::function_name(#expr1 " " #op " " #expr2, \
|
||
loguru::referenceable_value(expr1), #op, \
|
||
loguru::referenceable_value(expr2))) \
|
||
loguru::AbortLogger(error_string->c_str(), __FILE__, __LINE__)
|
||
|
||
#define CHECK_EQ_S(expr1, expr2) CHECK_OP_S(check_EQ_impl, expr1, ==, expr2)
|
||
#define CHECK_NE_S(expr1, expr2) CHECK_OP_S(check_NE_impl, expr1, !=, expr2)
|
||
#define CHECK_LE_S(expr1, expr2) CHECK_OP_S(check_LE_impl, expr1, <=, expr2)
|
||
#define CHECK_LT_S(expr1, expr2) CHECK_OP_S(check_LT_impl, expr1, < , expr2)
|
||
#define CHECK_GE_S(expr1, expr2) CHECK_OP_S(check_GE_impl, expr1, >=, expr2)
|
||
#define CHECK_GT_S(expr1, expr2) CHECK_OP_S(check_GT_impl, expr1, > , expr2)
|
||
|
||
#if LOGURU_DEBUG_LOGGING
|
||
// Debug logging enabled:
|
||
#define DVLOG_IF_S(verbosity, cond) VLOG_IF_S(verbosity, cond)
|
||
#define DLOG_IF_S(verbosity_name, cond) LOG_IF_S(verbosity_name, cond)
|
||
#define DVLOG_S(verbosity) VLOG_S(verbosity)
|
||
#define DLOG_S(verbosity_name) LOG_S(verbosity_name)
|
||
#else
|
||
// Debug logging disabled:
|
||
#define DVLOG_IF_S(verbosity, cond) \
|
||
(true || (verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
|
||
? (void)0 \
|
||
: loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
|
||
|
||
#define DLOG_IF_S(verbosity_name, cond) DVLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
|
||
#define DVLOG_S(verbosity) DVLOG_IF_S(verbosity, true)
|
||
#define DLOG_S(verbosity_name) DVLOG_S(loguru::Verbosity_ ## verbosity_name)
|
||
#endif
|
||
|
||
#if LOGURU_DEBUG_CHECKS
|
||
// Debug checks enabled:
|
||
#define DCHECK_S(cond) CHECK_S(cond)
|
||
#define DCHECK_NOTNULL_S(x) CHECK_NOTNULL_S(x)
|
||
#define DCHECK_EQ_S(a, b) CHECK_EQ_S(a, b)
|
||
#define DCHECK_NE_S(a, b) CHECK_NE_S(a, b)
|
||
#define DCHECK_LT_S(a, b) CHECK_LT_S(a, b)
|
||
#define DCHECK_LE_S(a, b) CHECK_LE_S(a, b)
|
||
#define DCHECK_GT_S(a, b) CHECK_GT_S(a, b)
|
||
#define DCHECK_GE_S(a, b) CHECK_GE_S(a, b)
|
||
#else
|
||
// Debug checks disabled:
|
||
#define DCHECK_S(cond) CHECK_S(true || (cond))
|
||
#define DCHECK_NOTNULL_S(x) CHECK_S(true || (x) != nullptr)
|
||
#define DCHECK_EQ_S(a, b) CHECK_S(true || (a) == (b))
|
||
#define DCHECK_NE_S(a, b) CHECK_S(true || (a) != (b))
|
||
#define DCHECK_LT_S(a, b) CHECK_S(true || (a) < (b))
|
||
#define DCHECK_LE_S(a, b) CHECK_S(true || (a) <= (b))
|
||
#define DCHECK_GT_S(a, b) CHECK_S(true || (a) > (b))
|
||
#define DCHECK_GE_S(a, b) CHECK_S(true || (a) >= (b))
|
||
#endif
|
||
|
||
#if LOGURU_REPLACE_GLOG
|
||
#undef LOG
|
||
#undef VLOG
|
||
#undef LOG_IF
|
||
#undef VLOG_IF
|
||
#undef CHECK
|
||
#undef CHECK_NOTNULL
|
||
#undef CHECK_EQ
|
||
#undef CHECK_NE
|
||
#undef CHECK_LT
|
||
#undef CHECK_LE
|
||
#undef CHECK_GT
|
||
#undef CHECK_GE
|
||
#undef DLOG
|
||
#undef DVLOG
|
||
#undef DLOG_IF
|
||
#undef DVLOG_IF
|
||
#undef DCHECK
|
||
#undef DCHECK_NOTNULL
|
||
#undef DCHECK_EQ
|
||
#undef DCHECK_NE
|
||
#undef DCHECK_LT
|
||
#undef DCHECK_LE
|
||
#undef DCHECK_GT
|
||
#undef DCHECK_GE
|
||
#undef VLOG_IS_ON
|
||
|
||
#define LOG LOG_S
|
||
#define VLOG VLOG_S
|
||
#define LOG_IF LOG_IF_S
|
||
#define VLOG_IF VLOG_IF_S
|
||
#define CHECK(cond) CHECK_S(!!(cond))
|
||
#define CHECK_NOTNULL CHECK_NOTNULL_S
|
||
#define CHECK_EQ CHECK_EQ_S
|
||
#define CHECK_NE CHECK_NE_S
|
||
#define CHECK_LT CHECK_LT_S
|
||
#define CHECK_LE CHECK_LE_S
|
||
#define CHECK_GT CHECK_GT_S
|
||
#define CHECK_GE CHECK_GE_S
|
||
#define DLOG DLOG_S
|
||
#define DVLOG DVLOG_S
|
||
#define DLOG_IF DLOG_IF_S
|
||
#define DVLOG_IF DVLOG_IF_S
|
||
#define DCHECK DCHECK_S
|
||
#define DCHECK_NOTNULL DCHECK_NOTNULL_S
|
||
#define DCHECK_EQ DCHECK_EQ_S
|
||
#define DCHECK_NE DCHECK_NE_S
|
||
#define DCHECK_LT DCHECK_LT_S
|
||
#define DCHECK_LE DCHECK_LE_S
|
||
#define DCHECK_GT DCHECK_GT_S
|
||
#define DCHECK_GE DCHECK_GE_S
|
||
#define VLOG_IS_ON(verbosity) ((verbosity) <= loguru::current_verbosity_cutoff())
|
||
|
||
#endif // LOGURU_REPLACE_GLOG
|
||
|
||
#endif // LOGURU_WITH_STREAMS
|
||
|
||
#endif // LOGURU_HAS_DECLARED_STREAMS_HEADER
|