{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Introduction to G3log","text":"
introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"#welcome-to-g3log","title":"Welcome to g3log","text":"G3log is an asynchronous logger with three main features: 1. Intuitive LOG(...)
API 2. Design-by-contract
CHECK(...)
functionality 3. Fatal crash handling for graceful shutdown of the logged process without loosing any log details up to the point of the crash
The super quick introduction to g3log can be seen in the steps 1 - 9 below.
For more in-depth information please see the full usage description in g3log_usage.md. The internal API for more advanced integration with g3log can be accessed in API.md
"},{"location":"#1-easy-usage-in-files","title":"1. Easy usage in files","text":"Avoid deep dependency injection complexity and instead get access to the logger as easy as
#include <g3log/g3log.hpp>\n
"},{"location":"#2-access-to-streaming-and-print_f-log-call-syntax","title":"2. Access to streaming and print_f log call syntax","text":"Both streaming syntax LOG
and print_f LOGF
syntax are available.
LOGF(INFO, \"Hi log %d\", 123);\nLOG(INF) << \"Hi log \" << 123;\n\n
"},{"location":"#3-conditional-logging","title":"3. Conditional logging","text":"LOG_IF(INFO, (1 < 2)) << \"If true this message will be logged\";\nLOGF_IF(INFO, (1 < 2), \"If true, then this %s will be logged\", \"message\");\n
"},{"location":"#4-design-by-contract-framework","title":"4. Design-by-contract framework","text":"CHECK(less != more); // not fatal\nCHECK_F(less > more, \"CHECK(false) will trigger a fatal message\")\n
"},{"location":"#5-handling-of-fatal","title":"5. Handling of fatal","text":"By default g3log will capture fatal events such as LOG(FATAL)
, CHECK(false)
and otherwise fatal signals such as:
SIGABRT\n SIGFPE\n SIGILL\n SIGSEGV\n SIGTERM\n
When a fatal event happens the not-yet written log activity will be flushed to the logging sinks. Only when all logging activity up to the point of the fatal event has happend, will g3log allow the fatal event to proceed and exit the process.
If object
symbols are available the fatal handler will attempt to push the stacktrace up to the fatal reason to the logging sink.
For overriding fatal error handling to use your own, or to add code hooks
that you want to execute please see the API.md doc.
The default logging levels are DEBUG
, INFO
, WARNING
and FATAL
. You can define your own logging levels or completely replace the logging levels. Ref: API.md
Log filtering is handled in g3log if dynamic logging levels are enabled in the configuration. See the API.md for information. Log filtering can also be handled through the sink as can be seen in github/Kjellod/g3sinks
"},{"location":"#8-3rd-party-and-custom-logging-sinks","title":"8. 3rd party and custom logging sinks","text":"The default logging sink has no external 3rd party dependencies. For more logging sinks please see github/Kjellod/g3sinks
See the API.md for more information about the simple steps to creating your own logging sink.
"},{"location":"#9-log-instantiation","title":"9. Log instantiation","text":"With the default application name left as is (i.e. \"g3log\") a creation of the logger could look something like this:
const std::string directory = \"./\";\n const std::string name = \"TestLogFile\";\n auto worker = g3::LogWorker::createLogWorker();\n auto handle = worker->addDefaultLogger(name, directory);\n
The resulting filename would be something like:
./TestLogFile.g3log.20160217-001406.log\n
"},{"location":"#performance","title":"Performance","text":"G3log aims to keep all background logging to sinks with as little log overhead as possible to the logging sink and with as small \"worst case latency\" as possible. For this reason g3log is a good logger for many systems that deal with critical tasks. Depending on platform the average logging overhead will differ. On my 2010 laptop the average call, when doing extreme performance testing, will be about ~2 us.
The worst case latency is kept stable with no extreme peaks, in spite of any sudden extreme pressure. I have a blog post regarding comparing worst case latency for g3log and other loggers which might be of interest. You can find it here: https://kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log/
"},{"location":"#continuos-integration","title":"Continuos Integration","text":"The g3log repository is evaluating both github actions and CircleCI for executing test coverage, installation and document generation. For windows the repo is still relying on appveyor. In case you want to look into change any of these setups the following files are the ones of interest.
1. appveyor --> g3log/appveyor.yml\n2. circleCI --> g3log/.circleci/config.yml\n3. github actions --> g3log/.github/workflows/*.yml\n\n\n
"},{"location":"#feedback","title":"Feedback","text":"If you like this logger (or not) it would be nice with some feedback. That way I can improve g3log and it is always nice to hear when and how someone is using it.
If you have ANY questions or problems please do not hesitate in contacting me at Hedstrom @ Kjellod. cc
This logger is available for free and all of its source code is public domain. A great way of saying thanks is to send a donation. It would go a long way not only to show your support but also to boost continued development.
Cheers
Kjell (a.k.a. KjellKod)
introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"API/","title":"API description","text":"introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"API/#high-level-description-of-g3log","title":"High Level Description of g3log","text":"The g3log
logger is an asynchronous, crash-safe logging library designed for C++ applications. It allows for logging messages to various sinks without blocking the main application thread. Below is a high-level overview of how the g3log
logger works.
The logger operates on a separate thread, ensuring that the main application thread is not blocked by I/O operations when logging messages. This is achieved by using a background worker (LogWorker
) that queues log messages and processes them asynchronously.
The LogWorker
is responsible for managing the logging sinks. A sink is an object that defines where and how log messages are outputted (e.g., to a file, console, or over the network). Users can add custom sinks to the LogWorker
using the addSink
method, which takes a unique pointer to a sink object and a function pointer to the method that will save the log message.
The logger includes a signal handler for Unix-like systems that captures fatal signals (e.g., SIGSEGV
, SIGABRT
) and ensures that all pending log messages are flushed to the sinks before the application exits. The signal handler function (signalHandler
) is registered to handle these signals and will attempt to generate a stack trace when a fatal signal is received. This stack trace is then logged, providing valuable debugging information.
Upon receiving a fatal signal, the signalHandler
function will call stackdump
to generate a stack trace. This function uses platform-specific calls to retrieve the stack frames and attempts to demangle the function names to make the stack trace more readable.
Log messages can be formatted using either a streaming API (e.g., LOG(INFO) << \"message\";
) or a printf-like syntax (e.g., LOGF(INFO, \"message %d\", value);
). This provides flexibility in how messages are constructed.
The library supports various log levels (e.g., DEBUG
, INFO
, WARNING
, FATAL
). Users can define custom log levels or modify the existing ones. The log levels can be dynamically enabled or disabled at runtime if the G3_DYNAMIC_LOGGING
preprocessor definition is set.
In the event of a crash, the logger is designed to be crash-safe by catching fatal events and ensuring that all log messages are flushed to the sinks before the process exits.
"},{"location":"API/#customization","title":"Customization","text":"The library allows for extensive customization, including adding custom log levels, creating custom sinks, and overriding the default signal handling behavior.
"},{"location":"API/#thread-safety","title":"Thread Safety","text":"The g3log
logger is thread-safe, meaning it can be used from multiple threads without the need for additional synchronization.
The g3log
code is released into the public domain, allowing users to use, modify, and distribute it freely without restrictions.
diagrams created with https://mermaid.live
"},{"location":"API/#api-description","title":"API description","text":"Most of the API that you need for using g3log is described in this readme. For more API documentation and examples please continue to read the API readme. Examples of what you will find here are:
"},{"location":"API/#logging-api-log-calls","title":"Logging API: LOG calls","text":"LOG calls can follow streaming LOG(INFO) << \"some text\"
or printf-like syntax LOGF(WARNING, \"some number %d\", 123);
Conditional logging is made with LOG_IF(INFO, <boolean-expression>) << \" some text\"
or LOGF_IF(WARNING, <boolean-expression>) << \" some text\".
Only if the expressions evaluates to true
will the logging take place.
Example: LOG_IF(INFO, 1 != 200) << \" some text\";
or LOG_IF(FATAL, SomeFunctionCall()) << \" some text\";
A call using FATAL logging level, such as the LOG_IF(FATAL,...)
example above, will after logging the message at FATAL
level also kill the process. It is essentially the same as a CHECK(<boolea-expression>) << ...
with the difference that the CHECK(<boolean-expression)
triggers when the expression evaluates to false
.
The contract API follows closely the logging API with CHECK(<boolean-expression>) << ...
for streaming or (*) CHECKF(<boolean-expression>, ...);
for printf-style.
If the <boolean-expression>
evaluates to false then the the message for the failed contract will be logged in FIFO order with previously made messages. The process will then shut down after the message is sent to the sinks and the sinks have dealt with the fatal contract message.
CHECK_F(<boolean-expression>, ...);
was the the previous API for printf-like CHECK. It is still kept for backwards compatability but is exactly the same as CHECKF
Fatal logging or failed `CHECK calls follows the same handling.
"},{"location":"API/#logging-levels","title":"Logging levels","text":"The default logging levels are DEBUG
, INFO
, WARNING
and FATAL
(see FATAL usage above). The logging levels are defined in loglevels.hpp.
For some windows framework there is a clash with the DEBUG
logging level. One of the CMake Build options can be used to then change offending default level from DEBUG
TO DBUG
.
**CMake option: (default OFF) ** cmake -DCHANGE_G3LOG_DEBUG_TO_DBUG=ON ..
### disable/enabled levels at runtime Logging levels can be disabled at runtime. The logic for this happens in loglevels.hpp, loglevels.cpp and g3log.hpp.
There is a cmake option to enable the dynamic enable/disable of levels. When the option is enabled there will be a slight runtime overhead for each LOG
call when the enable/disable status is checked. For most intent and purposes this runtime overhead is negligable.
There is no runtime overhead for internally checking if a level is enabled//disabled if the cmake option is turned off. If the dynamic logging cmake option is turned off then all logging levels are enabled.
CMake option: (default OFF) cmake -DUSE_DYNAMIC_LOGGING_LEVELS=ON ..
### custom logging levels Custom logging levels can be created and used. When defining a custom logging level you set the value for it as well as the text for it. You can re-use values for other levels such as INFO, WARNING etc or have your own values. Any value with equal or higher value than the FATAL value will be considered a FATAL logging level.
To keep in mind when adding your own custom levels. 1. If the cmake option G3_DYNAMIC_LOGGING
is enabled then you must use g3::only_change_at_initialization::addLogLevel(...)
to give g3log a record of your logging level and if it is an enabled or disbled logging level. 1. If the cmake G3_DYNAMIC_LOGGING
is turned OFF, then giving g3log a record of your logging level with 'addLogLevel(...) is not needed since no \"disbled/enabled\"
check will happen - all logging levels will be considered enabled.
Example: ```cpp // In CustomLoggingLevels.hpp #include
// all values with a + 1 higher than their closest equivalet // they could really have the same value as well.
const LEVELS FYI {DEBUG.value + 1, {\"For Your Information\"}}; const LEVELS CUSTOM {INFO.value + 1, {\"CUSTOM\"}}; const LEVELS SEVERE {WARNING.value +1, {\"SEVERE\"}}; const LEVELS DEADLY {FATAL.value + 1, {\"DEADLY\"}}; ```
More examples can be viwed in the unit tests.
"},{"location":"API/#sink-creation-and-utilization","title":"Sink creation and utilization","text":"The default sink for g3log is the one as used in g2log. It is a simple file sink with a limited API. The details for the default file sink can be found in filesink.hpp, filesink.cpp, filesinkhelper.ipp
More sinks can be found at g3sinks (log rotate, log rotate with filtering on levels)
A logging sink is not required to be a subclass of a specific type. The only requirement of a logging sink is that it can receive a logging message of
"},{"location":"API/#using-the-default-sink","title":"Using the default sink","text":"Sink creation is defined in logworker.hpp and used in logworker.cpp. For in-depth knowlege regarding sink implementation details you can look at sinkhandle.hpp and sinkwrapper.hpp
std::unique_ptr<FileSinkHandle> addDefaultLogger(\n const std::string& log_prefix\n , const std::string& log_directory\n , const std::string& default_id = \"g3log\");\n
With the default id left as is (i.e. \"g3log\") a creation of the logger in the unit test \"test_filechange\" would look like this
const std::string directory = \"./\";\n const std::string name = \"(ReplaceLogFile)\";\n auto worker = g3::LogWorker::createLogWorker();\n auto handle = worker->addDefaultLogger(name, directory);\n
The resulting filename would be something like:
./(ReplaceLogFile).g3log.20160217-001406.log\n
"},{"location":"API/#designate-the-sink-functions-log-entry-receving-function","title":"Designate the sink function's log entry receving function","text":"The default log formatting look can be overriden by any sink. If the sink receiving function calls toString()
then the default log formatting will be used. If the sink receiving function calls toString(&XFunc)
then the XFunc
will be used instead (see LogMessage.h/cpp
for code details if it is not clear). (XFunc
is a place holder for your formatting function of choice).
The API for the function-ptr to pass in is
std::string (*) (const LogMessage&)\n
or for short as defined in LogMessage.h
using LogDetailsFunc = std::string (*) (const LogMessage&);\n
"},{"location":"API/#log-format-customization","title":"Log format customization","text":"Please seeAPI_custom_formatting.md
"},{"location":"API/#log-flushing","title":"LOG flushing","text":"The default file sink will flush each log entry at set intervals. The default buffer size for flushing is set to 100 entries. You can adjust this down to 1, or as high as makes sense for your system. Please see FileSink
Even more flushing policies and log rotations can be found at g3sinks logrotate and LogRotateWithFilters.
At shutdown all enqueued logs will be flushed to the sink. At a discovered fatal event (SIGSEGV et.al) all enqueued logs will be flushed to the sink.
A programmatically triggered abrupt process exit such as a call to exit(0)
will of course not get the enqueued log entries flushed. Similary a bug that does not trigger a fatal signal but a process exit will also not get the enqueued log entries flushed. G3log can catch several fatal crashes and it deals well with RAII exits but magic is so far out of its' reach.
Example usage where a logrotate sink (g3sinks) is added. In the example it is shown how the logrotate API is called. The logrotate limit is changed from the default to instead be 10MB. The limit is changed by calling the sink handler which passes the function call through to the actual logrotate sink object.
\n// main.cpp\n#include <g3log/g3log.hpp>\n#include <g3log/logworker.h>\n#include <g3sinks/LogRotate.h>\n#include <memory>\n\nint main(int argc, char**argv) {\n using namespace g3;\n std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };\n auto sinkHandle = logworker->addSink(std::make_unique<LogRotate>(),\n &LogRotate::save);\n\n // initialize the logger before it can receive LOG calls\n initializeLogging(logworker.get()); \n\n // You can call in a thread safe manner public functions on the logrotate sink\n // The call is asynchronously executed on your custom sink.\n const int k10MBInBytes = 10 * 1024 * 1024;\n std::future<void> received = sinkHandle->call(&LogRotate::setMaxLogSize, k10MBInBytes);\n\n // Run the main part of the application. This can be anything of course, in this example\n // we'll call it \"RunApplication\". Once this call exits we are in shutdown mode\n RunApplication();\n\n // If the LogWorker is initialized then at scope exit the g3::shutDownLogging() will be \n // called automatically. \n // \n // This is important since it protects from LOG calls from static or other entities that will go out of\n // scope at a later time. \n //\n // It can also be called manually if for some reason your setup is different then the one highlighted in\n // this example\n g3::shutDownLogging();\n}\n
"},{"location":"API/#dynamic-message-sizing","title":"Dynamic Message Sizing","text":"The default build uses a fixed size buffer for formatting messages. The size of this buffer is 2048 bytes. If an incoming message results in a formatted message that is greater than 2048 bytes, it will be bound to 2048 bytes and will have the string [...truncated...]
appended to the end of the bound message. There are cases where one would like to dynamically change the size at runtime. For example, when debugging payloads for a server, it may be desirable to handle larger message sizes in order to examine the whole payload. Rather than forcing the developer to rebuild the server, dynamic message sizing could be used along with a config file which defines the message size at runtime.
This feature supported as a CMake option:
CMake option: (default OFF) cmake -DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=ON ..
The following is an example of changing the size for the message.
g3::only_change_at_initialization::setMaxMessageSize(10000);\n
"},{"location":"API/#fatal-handling","title":"Fatal handling","text":"The default behaviour for G3log is to catch several fatal events before they force the process to exit. After catching a fatal event a stack dump is generated and all log entries, up to the point of the stack dump are together with the dump flushed to the sink(s).
"},{"location":"API/#linuxnix","title":"Linux/*nix","text":"The default fatal handling on Linux deals with fatal signals. At the time of writing these signals were SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM
. The Linux fatal handling is handled in crashhandler.hpp and crashhandler_unix.cpp
A signal that commonly is associated with voluntarily process exit is SIGINT
(ctrl + c) G3log does not deal with it.
The fatal signals can be disabled or changed/added .
An example of a Linux stackdump as shown in the output from the fatal example g3log-FATAL-sigsegv. ``` * FATAL SIGNAL RECEIVED * \"Received fatal signal: SIGSEGV(11) PID: 6571
***** SIGNAL SIGSEGV(11)\n\n******* STACKDUMP *******\n stack dump [1] ./g3log-FATAL-sigsegv() [0x42a500]\n stack dump [2] /lib/x86_64-linux-gnu/libpthread.so.0+0x10340 [0x7f83636d5340]\n\n stack dump [3] ./g3log-FATAL-sigsegv : example_fatal::tryToKillWithAccessingIllegalPointer(std::unique_ptr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)+0x119 [0x4107b9]\n stack dump [4] ./g3log-FATAL-sigsegvmain+0xdec [0x40e51c]\n stack dump [5] /lib/x86_64-linux-gnu/libc.so.6__libc_start_main+0xf5 [0x7f8363321ec5]\n stack dump [6] ./g3log-FATAL-sigsegv() [0x40ffa2]\n\nExiting after fatal event (FATAL_SIGNAL). Fatal type: SIGSEGV\nLog content flushed sucessfully to sink\n\n\"\ng3log g3FileSink shutdown at: 16:33:18\n\n```\n
"},{"location":"API/#custom-fatal-handling-override-defaults","title":"Custom fatal handling - override defaults","text":"By default the fatal signals are defined in https://github.com/KjellKod/g3log/tree/master/src/g3log.cpp as SIGABRT SIGFPE SIGILL SIGSEGV SIGTERM
If you want to define your own set of fatal signals, override the default ones, then this can be done as shown in src/g3log/crashhandler.hpp cpp // Example when SIGTERM is skipped due to ZMQ usage g3::overrideSetupSignals({ {SIGABRT, \"SIGABRT\"}, {SIGFPE, \"SIGFPE\"}, {SIGILL, \"SIGILL\"}, {SIGSEGV, \"SIGSEGV\"}});
You can define a custom call back function that will be called before the fatal signal handling re-emits the fatal
signal. See src/g3log/g3log.hpp for details. // Example of how to enforce important shutdown cleanup even in the event of a fatal crash: g3::setFatalPreLoggingHook([]{ cleanup(); });
Fatal signal handling can be disabled with a CMake option: ENABLE_FATAL_SIGNALHANDLING
. See Options.cmake for more details
If you are using g3log on a PID1 process then you absolutely should provide your own signal handling (ref: issue 269) as g3log re-emits the fatal signal after it has restored the previous signal handler for that signal. PID1 processed do not shutdown the process for a normal fatal signal so the choice to exit the PID1 process after such a signal must be taken by the coder - not by g3log.
"},{"location":"API/#windows","title":"Windows","text":"Windows fatal handling also deals with fatal signals just like Linux. In addition to fatal signals it also deals with unhandled exceptions, vectored exceptions. Windows fatal handling is handled in crashhandler.hpp, crashhandler_windows.cpp, stacktrace_windows.hpp, stacktrace_windows.cpp
An example of a Windows stackdump as shown in the output from the fatal example g3log-FATAL-sigsegv.
introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"API_custom_formatting/","title":"API for custom log formatting","text":"introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"API_custom_formatting/#custom-log-formatting","title":"Custom LOG formatting","text":""},{"location":"API_custom_formatting/#overriding-the-default-file-sinks-file-header","title":"Overriding the Default File Sink's file header","text":"The default file header can be customized in the default file sink in calling
FileSink::overrideLogHeader(std::string);\n
"},{"location":"API_custom_formatting/#overriding-the-default-filesinks-log-formatting","title":"Overriding the Default FileSink's log formatting","text":"The default log formatting is defined in LogMessage.hpp
static std::string DefaultLogDetailsToString(const LogMessage& msg);\n
"},{"location":"API_custom_formatting/#adding-thread-id-to-the-log-formatting","title":"Adding thread ID to the log formatting","text":"An \"all details\" log formatting function is also defined - this one also adds the \"calling thread's ID\"
static std::string FullLogDetailsToString(const LogMessage& msg);\n
"},{"location":"API_custom_formatting/#override-default-sink-log-formatting","title":"Override default sink log formatting","text":"For convenience the Default sink has a function for doing exactly this
void overrideLogDetails(LogMessage::LogDetailsFunc func);\n
Example code for replacing the default log formatting for \"full details\" formatting (it adds thread ID)
auto worker = g3::LogWorker::createLogWorker();\n auto handle= worker->addDefaultLogger(argv[0], path_to_log_file);\n g3::initializeLogging(worker.get());\n handle->call(&g3::FileSink::overrideLogDetails, &LogMessage::FullLogDetailsToString);\n
See test_message.cpp for details and testing
Example code for overloading the formatting of a custom sink. The log formatting function will be passed into the LogMessage::toString(...)
this will override the default log formatting
Example
namespace {\n std::string MyCustomFormatting(const LogMessage& msg) {\n ... how you want it ...\n }\n }\n\n void MyCustomSink::ReceiveLogEntry(LogMessageMover message) {\n std::string formatted = message.get().toString(&MyCustomFormatting) << std::flush;\n }\n...\n...\n auto worker = g3::LogWorker::createLogWorker();\n auto sinkHandle = worker->addSink(std::make_unique<MyCustomSink>(),\n &MyCustomSink::ReceiveLogMessage);\n // ReceiveLogMessage(...) will used the custom formatting function \"MyCustomFormatting(...)\n\n
introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"building/","title":"Configure, Build, Package, Install and Test","text":"introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"building/#configure-build-package-install-and-test-g3log","title":"Configure, build, package, install and test g3log","text":""},{"location":"building/#example-project-with-g3log","title":"Example Project with g3log","text":"An example project integration of g3log, both statially and dynamically built can be found at g3log_example_integration
"},{"location":"building/#building-it-standalone-to-try-out-is-as-easy-as","title":"Building it standalone to try out is as easy as:","text":"git clone https://github.com/KjellKod/g3log\ncd g3log\nmkdir build\ncd build\n
"},{"location":"building/#prerequisites","title":"Prerequisites","text":"You also need these tools to build g3log from source: - CMake (Required)
g3log uses CMake as a one-stop solution for configuring, building, installing, packaging and testing on Windows, Linux and OSX.
When building g3log it uses git to calculate the software version from the commit history of this repository. If you don't want that, or your setup does not have access to git, or you download g3log source archive from the GitHub Releases page so that you do not have the commit history downloaded, you can instead pass in the version as part of the CMake build arguments. See this issue for more information. cmake -DVERSION=1.3.2 ..
g3log provides following CMake options (and default values):
$ cmake -LAH # List non-advanced cached variables. See `cmake --help` for more details.\n\n...\n\n// Fatal (fatal-crashes/contract) examples\nADD_FATAL_EXAMPLE:BOOL=ON\n\n// g3log performance test\nADD_G3LOG_BENCH_PERFORMANCE:BOOL=OFF\n\n// g3log unit tests\nADD_G3LOG_UNIT_TEST:BOOL=OFF\n\n// Use DBUG logging level instead of DEBUG.\n// By default DEBUG is the debugging level\nCHANGE_G3LOG_DEBUG_TO_DBUG:BOOL=OFF\n\n\n// Windows only: Use __FUNCSIG__ instead of the default __FUNCTION__ \n// to show LOG function location\n// WARNING: using this in heavily templated code, like boost can expand\n// the function name into massive size\nWINDOWS_FUNCSIG:BOOL=OFF\n\n\n// gcc/clang only: Use __PRETTY_FUNCTION__ instead of the default __FUNCTION__ \n// to show LOG function location\n// WARNING: using this in heavily templated code, like boost can expand\n// the function name into massive size\nPRETTY_FUNCTION:BOOL=OFF\n\n\n// Specifies the build type on single-configuration generators.\n// Possible values are empty, Debug, Release, RelWithDebInfo, MinSizeRel, \u2026\nCMAKE_BUILD_TYPE:STRING=\n\n// Install path prefix, prepended onto install directories.\n// This variable defaults to /usr/local on UNIX\n// and c:/Program Files/${PROJECT_NAME} on Windows.\nCMAKE_INSTALL_PREFIX:PATH=\n\n// The prefix used in the built package.\n// On Linux, if this option is not set:\n// 1) If CMAKE_INSTALL_PREFIX is given, then it will be\n// set with the value of CMAKE_INSTALL_PREFIX by g3log.\n// 2) Otherwise, it will be set as /usr/local by g3log.\nCPACK_PACKAGING_INSTALL_PREFIX:PATH=\n\n// Enable Visual Studio break point when receiving a fatal exception.\n// In __DEBUG mode only\nDEBUG_BREAK_AT_FATAL_SIGNAL:BOOL=OFF\n\n// Vectored exception / crash handling with improved stack trace\nENABLE_FATAL_SIGNALHANDLING:BOOL=ON\n\n// Vectored exception / crash handling with improved stack trace\nENABLE_VECTORED_EXCEPTIONHANDLING:BOOL=ON\n\n// iOS version of library.\nG3_IOS_LIB:BOOL=OFF\n\n// Log full filename\nG3_LOG_FULL_FILENAME:BOOL=OFF\n\n// Build shared library\nG3_SHARED_LIB:BOOL=ON\n\n// Build shared runtime library MSVC\nG3_SHARED_RUNTIME:BOOL=ON\n\n// Turn ON/OFF log levels.\n// An disabled level will not push logs of that level to the sink.\n// By default dynamic logging is disabled\nUSE_DYNAMIC_LOGGING_LEVELS:BOOL=OFF\n\n// Use dynamic memory for message buffer during log capturing\nUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE:BOOL=OFF\n\n...\n
For additional option context and comments please also see Options.cmake
If you want to leave everything as it was, then you should:
cmake ..\n
You may also specify one or more of those options listed above from the command line. For example, on Windows:
cmake .. -G \"Visual Studio 15 2017\"\n -DG3_SHARED_LIB=OFF\n -DCMAKE_INSTALL_PREFIX=C:/g3log\n -DADD_G3LOG_UNIT_TEST=ON\n -DADD_FATAL_EXAMPLE=OFF\n
will use a Visual Studio 2017 solution generator, build g3log as a static library, headers and libraries will be installed to C:\\g3log
when installed from source, enable unit testing, but do not build fatal example.
MinGW users on Windows may find they should use a different generator:
cmake .. -G \"MinGW Makefiles\"\n
By default, headers and libraries will be installed to /usr/local
on Linux when installed from build tree via make install
. You may overwrite it by:
cmake .. -DCMAKE_INSTALL_PREFIX=/usr\n
This will install g3log to /usr
instead of /usr/local
.
Linux/OSX package maintainers may be interested in the CPACK_PACKAGING_INSTALL_PREFIX
. For example:
cmake .. -DCPACK_PACKAGING_INSTALL_PREFIX=/usr/local\n
"},{"location":"building/#build-commands","title":"Build Commands","text":"Once the configuration is done, you may build g3log with:
# Suppose you are still in the `build` directory. I won't repeat it anymore!\ncmake --build . --config Release\n
You may also build it with a system-specific way.
On Linux, OSX and MinGW:
make\n
On Windows:
msbuild g3log.sln /p:Configuration=Release\n
Windows users can also open the generated Visual Studio solution file and build it happily.
"},{"location":"building/#installation","title":"Installation","text":"Install from source in a CMake way:
cmake --build . --target install\n
Linux users may also use:
sudo make install\n
You may also create a package first and install g3log with it. See the next section.
"},{"location":"building/#packaging","title":"Packaging","text":"A CMake way:
cmake --build . --config Release --target package\n
or
cpack -C Release\n
if the whole library has been built in the previous step. It will generate a ZIP package on Windows, and a DEB package on Linux.
Linux users may also use a Linux way:
make package\n
If you want to use a different package generator, you should specify a -G
option.
On Windows:
cpack -C Release -G NSIS;7Z\n
this will create a installable NSIS package and a 7z package.
Note: To use the NSIS generator, you should install NSIS
first.
On Linux:
cpack -C Release -G TGZ\n
this will create a .tar.gz archive for you.
Once done, you may install or uncompress the package file to the target machine. For example, on Debian or Ubuntu:
sudo dpkg -i g3log-<version>-Linux.deb\n
will install the g3log library to CPACK_PACKAGING_INSTALL_PREFIX
.
By default, tests will be built. To disable unit testing, you should turn off ADD_G3LOG_UNIT_TEST
.
Suppose the build process has completed, then you can run the tests with:
ctest -C Release\n
or:
make test\n
for Linux users. or for a detailed gtest output of all the tests:
cd build;\n../scripts/runAllTests.sh\n
"},{"location":"building/#cmake-module","title":"CMake module","text":"g3log comes with a CMake module. Once installed, it can be found under ${CMAKE_INSTALL_PREFIX}/lib/cmake/g3log
. Users can use g3log in a CMake-based project this way:
find_package(g3log CONFIG REQUIRED)\ntarget_link_libraries(main PRIVATE g3log)\n
To make sure that CMake can find g3log, you also need to tell CMake where to search for it:
cmake .. -DCMAKE_PREFIX_PATH=<g3log's install prefix>\n
"},{"location":"building/#build-options","title":"Build Options","text":"The build options are defined in the file Options.cmake
build options are generated and saved to a header file. This avoid having to set the define options in the client source code
introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"codespaces/","title":"Codespaces","text":"You can experiment with codespaces and g3log.
"},{"location":"codespaces/#learn-about-github-codespaces","title":"Learn about Github Codespaces","text":"For an introduction to codespaces you can check out example c++ codespace and using-github-codespaces-with-github-cli
"},{"location":"codespaces/#commandline-codespaces-quick-reference","title":"Commandline codespaces Quick Reference","text":"gh codespace list
gh codespace create -r OWNER/REPO_NAME [-b BRANCH]
. Ref docs/github: Creating a codespace for a repositorygh codespace view
gh codespace stop -c CODESPACE-NAME
gh codespace delete -c CODESPACE-NAME
gh codespace rebuild
gh codespace edit -c CODESPACE-NAME -d DISPLAY-NAME
gh codespace ssh -c CODESPACE-NAME
gh codespace code -c CODESPACE-NAME
(ref: github:doc cs studio)gh codespace cp [-r] SOURCE(S) DESTINATION
. Example: Copy a file from the local machine to the $HOME directory of a codespace: gh codespace cp myfile.txt remote:
. Example Copy a file from a codespace to the current directory on the local machine: gh codespace cp remote:myfile.txt .
(more information available here)Please note that this will build g3log as if it's on a Debian Linux platform.
Dev Containers: Open Folder in Container...
command.Open a terminal in Visual Studio Code\nmkdir debianbuild\ncd debianbuild\ncmake -DADD_G3LOG_UNIT_TEST=ON -DADD_G3LOG_BENCH_PERFORMANCE=ON ..\nmake -j \n
"},{"location":"codespaces/#example-runs","title":"Example runs","text":"./g3log-performance-threaded_mean 4
ctest -v
./g3log-FATAL-contract
Without any need to set up environment on your local machine you can also use Codespaces to debug examples, unit tests etc of g3log. The pesky thing with VSCode, especially with cmake is to set up the launh.json. It's a little bit easier if you open a VSCode terminal and do the cmake configuration and build there. Then the launch.json
only needs to contain information about the pecific executable.
Here we try out the g3log-FATAL-contract
after cmake configure with -DCMAKE_BUILD_TYPE=Debug
{\n // Use IntelliSense to learn about possible attributes.\n // Hover to view descriptions of existing attributes.\n // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n // Remember to build the specific part of cmake with \n // \"cmake -DCMAKE_BUILD_TYPE=Debug\" if you want to be able to debug it. \n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"(gdb) Start\",\n \"type\": \"cppdbg\",\n \"request\": \"launch\",\n \"program\": \"${workspaceFolder}/build/g3log-FATAL-contract\",\n \"MIMode\": \"gdb\",\n \"cwd\": \"${workspaceFolder}/build\"\n \"setupCommands\": [\n {\n \"description\": \"Enable pretty-printing for gdb\",\n \"text\": \"-enable-pretty-printing\",\n \"ignoreFailures\": true\n },\n {\n \"description\": \"Set Disassembly Flavor to Intel\",\n \"text\": \"-gdb-set disassembly-flavor intel\",\n \"ignoreFailures\": true\n }\n ]\n }\n\n ]\n}\n
"},{"location":"contributing/","title":"Information for contributing to g3log","text":""},{"location":"contributing/#license","title":"License","text":"LICENSE
"},{"location":"contributing/#contributing","title":"Contributing","text":"CONTRIBUTING.md
"},{"location":"contributing/#code-of-conduct","title":"Code of conduct","text":"CODE_OF_CONDUCT.md
"},{"location":"contributing/#pull-request-template","title":"Pull request template","text":"PULL_REQUEST_TEMPLATE.md
"},{"location":"g3log_usage/","title":"G3log usage","text":"introduction | detailed information | Configure & Build | API description | Custom log formatting
"},{"location":"g3log_usage/#how-to-use-g3log","title":"How to use g3log","text":"G3log is an asynchronous logger with dynamic sinks
"},{"location":"g3log_usage/#example-usage","title":"Example USAGE","text":""},{"location":"g3log_usage/#optional-to-use-either-streaming-or-printf-like-syntax","title":"Optional to use either streaming or printf-like syntax","text":"LOG(INFO) << \"streaming API is as easy as ABC or \" << 123;\n\nLOGF(WARNING, \"Printf-style syntax is also %s\", \"available\");\n
"},{"location":"g3log_usage/#what-g3log-is","title":"What g3Log is","text":"int less = 1; int more = 2\nLOG_IF(INFO, (less<more)) <<\"If [true], then this text will be logged\";\n\n// or with printf-like syntax\nLOGF_IF(INFO, (less<more), \"if %d<%d then this text will be logged\", less,more);\n
"},{"location":"g3log_usage/#design-by-contract","title":"Design-by-Contract","text":"CHECK(false) will trigger a \"fatal\" message. It will be logged, and then the application will exit.
CHECK(less != more); // not FATAL\nCHECK(less > more) << \"CHECK(false) triggers a FATAL message\";\n
"},{"location":"g3log_usage/#detailed-api-documentation","title":"Detailed API documentation","text":"Please look at API.md for detailed API documentation
"},{"location":"g3log_usage/#benefits-you-get-when-using-g3log","title":"Benefits you get when using g3log","text":"Easy to use, clean syntax and a blazing fast logger.
All the slow log I/O disk access is done in a background thread. This ensures that the LOG caller can immediately continue with other tasks and do not have to wait for the LOG call to finish.
G3log provides logging, Design-by-Contract [#CHECK], and flush of log to file at shutdown. Buffered logs will be written to the sink before the application shuts down.
It is thread safe, so using it from multiple threads is completely fine.
It is CRASH SAFE. It will save the made logs to the sink before it shuts down. The logger will catch certain fatal events (Linux/OSX: signals, Windows: fatal OS exceptions and signals) , so if your application crashes due to, say a segmentation fault, SIGSEGV, it will log and save the crash and all previously buffered log entries before exiting.
It is cross platform. Tested and used by me or by clients on OSX, Windows, Ubuntu, CentOS
G3log and G2log are used worldwide in commercial products as well as hobby projects. G2log was introduced in early 2011 and is now retired.
The code is given for free as public domain. This gives the option to change, use, and do whatever with it, no strings attached.
g3log : is made to facilitate easy adding of custom log receivers. Its tested on at least the following platforms with Linux(Clang/gcc), Windows (mingw, visual studio) and OSX. My recommendation is to go with g3log if you have full C++17 support
C++11 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.1).
C++14 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.4
"},{"location":"g3log_usage/#g3log-with-sinks","title":"G3log with sinks","text":"Sinks are receivers of LOG calls. G3log comes with a default sink (the same as g3log uses) that can be used to save log to file. A sink can be of any class type without restrictions as long as it can either receive a LOG message as a std::string or as a g3::LogMessageMover.
The std::string comes pre-formatted. The g3::LogMessageMover is a wrapped struct that contains the raw data for custom handling in your own sink.
A sink is owned by the g3log and is added to the logger inside a std::unique_ptr
. The sink can be called though its public API through a handler which will asynchronously forward the call to the receiving sink.
It is crazy simple to create a custom sink. This example show what is needed to make a custom sink that is using custom log formatting but only using that for adding color to the default log formatting. The sink forwards the colored log to cout
// in file Customsink.hpp\n#pragma once\n#include <string>\n#include <iostream>\n#include <g3log/logmessage.hpp>\n\nstruct CustomSink {\n\n// Linux xterm color\n// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal\n enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};\n\n FG_Color GetColor(const LEVELS level) const {\n if (level.value == WARNING.value) { return YELLOW; }\n if (level.value == DEBUG.value) { return GREEN; }\n if (g3::internal::wasFatal(level)) { return RED; }\n\n return WHITE;\n }\n\n void ReceiveLogMessage(g3::LogMessageMover logEntry) {\n auto level = logEntry.get()._level;\n auto color = GetColor(level);\n\n std::cout << \"\\033[\" << color << \"m\"\n << logEntry.get().toString() << \"\\033[m\" << std::endl;\n }\n};\n\n// in main.cpp, main() function\n\nauto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),\n &CustomSink::ReceiveLogMessage);\n\n
"},{"location":"g3log_usage/#adding-and-removing-sinks","title":"Adding and Removing Sinks","text":"You can safely remove and add sinks during the running of your program.
Keep in mind
Adding Sinks
auto sinkHandle1 = logworker->addSink(std::make_unique<CustomSink>(),\n &CustomSink::ReceiveLogMessage);\n auto sinkHandle2 = logworker->addDefaultLogger(argv[0],\n path_to_log_file);\n logworker->removeSink(std::move(sinkHandle1)); // this will in a thread-safe manner remove the sinkHandle1\n logworker->removeAllSinks(); // this will in a thread-safe manner remove any sinks. \n
More sinks can be found in the repository github.com/KjellKod/g3sinks.
"},{"location":"g3log_usage/#code-examples","title":"Code Examples","text":"Example usage where a custom sink is added. A function is called though the sink handler to the actual sink object.
// main.cpp\n#include <g3log/g3log.hpp>\n#include <g3log/logworker.hpp>\n#include <memory>\n\n#include \"CustomSink.h\"\n\nint main(int argc, char**argv) {\n using namespace g3;\n std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };\n auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),\n &CustomSink::ReceiveLogMessage);\n\n // initialize the logger before it can receive LOG calls\n initializeLogging(logworker.get());\n LOG(WARNING) << \"This log call, may or may not happend before\"\n << \"the sinkHandle->call below\";\n\n\n // You can call in a thread safe manner public functions on your sink\n // The call is asynchronously executed on your custom sink.\n std::future<void> received = sinkHandle->call(&CustomSink::Foo,\n param1, param2);\n\n // If the LogWorker is initialized then at scope exit the g3::internal::shutDownLogging() will be called.\n // This is important since it protects from LOG calls from static or other entities that will go out of\n // scope at a later time.\n //\n // It can also be called manually:\n g3::internal::shutDownLogging();\n}\n\n\n// some_file.cpp : To show how easy it is to get the logger to work\n// in other parts of your software\n\n#include <g3log/g3log.hpp>\n\nvoid SomeFunction() {\n ...\n LOG(INFO) << \"Hello World\";\n}\n
Example usage where a the default file logger is used and a custom sink is added
// main.cpp\n#include <g3log/g3log.hpp>\n#include <g3log/logworker.hpp>\n#include <memory>\n\n#include \"CustomSink.h\"\n\nint main(int argc, char**argv) {\n using namespace g3;\n auto worker = LogWorker::createLogWorker();\n auto defaultHandler = worker->addDefaultLogger(argv[0],\n path_to_log_file);\n\n // logger is initialized\n g3::initializeLogging(worker.get());\n\n LOG(DEBUG) << \"Make log call, then add another sink\";\n\n worker->addSink(std::make_unique<CustomSink>(),\n &CustomSink::ReceiveLogMessage);\n\n ...\n}\n
introduction | detailed information | Configure & Build | API description | Custom log formatting
"}]}