简中 | English
elog4cpp
: means that this is a very easy
to use and very efficient
in performance c++ logging library. It supports c++11 and above, and is fully cross-platform.
The use of easy
is reflected in:
- Simple api, you only need to focus on an
elog::Log
class, or static methodLog::<LEVEL>
, or macro definitionELG_<LEVEL>
. - Formatting output is simple because the fmt library is used for formatting output.
- Custom formatting is simple because custom
formatter
is supported, and fourformatters
are preconfigured, including defaultFormatter, colorfulFormatter, jsonFormatter, and customFormatter. - Easy to configure, supports reading configuration items via
json
file with one click. - Easy to introduce, support
cmake
command to introduce and use the project with one click.
Performance efficiency
is reflected in:
- The latency of outputting a log is only
180ns
synchronously and120ns
asynchronously, which is at least 4 times the performance of spdlog.
For benchmark, see tests/bench_start.cc
- C++11 and above, which is cross-platform
The following two methods are recommended for introduction.
-
Method 1: Introduce via the
FetchContent
module in cmake.- add the following code to the project cmake to introduce, domestic if the network problems can not use this gitee image source: https://gitee.com/acking-you/elog4cpp.git
include(FetchContent) FetchContent_Declare( elog4cpp GIT_REPOSITORY https://github.com/ACking-you/elog4cpp.git GIT_TAG origin/fetch GIT_SHALLOW TRUE) FetchContent_MakeAvailable(elog4cpp)
- Link
elog
in the target that needs to use the library.target_link_libraries(target elog)
- add the following code to the project cmake to introduce, domestic if the network problems can not use this gitee image source: https://gitee.com/acking-you/elog4cpp.git
-
Method 2: Download the source code manually and then introduce it via the cmake command.
-
download the project source code via the git command
git clone https://github.com/ACking-you/elog4cpp.git --recursive
-
Add the project to a subproject.
add_subdirectory(elog4cpp)
-
Link
elog
in the target that needs to use the library.target_link_libraries(target elog)
-
-
Without any configuration, we can directly call the static method output to the terminal with the following code.
#include <elog/logger.h> using namespace elog; int main() { Log::trace("hello elog4cpp"); Log::debug("hello elog4cpp"); Log::info("hello elog4cpp"); Log::warn("hello elog4cpp"); Log::error("hello elog4cpp"); Log::fatal("hello elog4cpp"); }
The output is as follows. Through the above example, we need to understand the following three points.
- The output levels of this log library are
trace
,debug
,info
,warn
,error
,fatal
. - The default output level is
debug
, which means that thetrace
level is not output. - The
fatal
level of output will throw an exception.
In fact, if there is an error in
errno
at theerror
orfatal
level of output, then the corresponding error will be output, which is useful some time. - The output levels of this log library are
-
In the previous example, we were unable to output the log at
trace
level, now we try to change its minimum output level and then add more information to the output (such as file name, line number, function name, etc.) and output the output in color highlighting.The code is as follows:
#include <elog/logger.h> using namespace elog; int main() { GlobalConfig::Get() .setLevel(Levels::kTrace) .setFormatter(formatter::colorfulFormatter); Log::trace(loc::current(), "hello elog4cpp"); Log::debug(loc::current(), "hello elog4cpp"); Log::info(loc::current(), "hello elog4cpp"); Log::warn(loc::current(), "hello elog4cpp"); Log::error(loc::current(), "hello elog4cpp"); }
The output looks like this: From the above example code, we found that if we need to get information such as file name, we need to pass
loc::current()
in the first parameter, obviously most of the time we will find it troublesome to use this, so we can solve this problem through macros, you can do like the following, before introducing<elog/logger.h>
defineENABLE_ELG_LOG
macro before introducing<ELG_<LEVEL>
to use the shorter macro definitionELG_<LEVEL>
.#define ENABLE_ELG_LOG #include <elog/logger.h> using namespace elog; int main() { GlobalConfig::Get() .setLevel(Levels::kTrace) .setFormatter(formatter::colorfulFormatter); ELG_TRACE("hello elog4cpp"); ELG_DEBUG("hello elog4cpp"); ELG_INFO("hello elog4cpp"); ELG_WARN("hello elog4cpp"); ELG_ERROR("hello elog4cpp"); }
The code generated by this macro definition is equivalent to the code in the previous example.
-
The previous examples all just output to the console, we now output the content to a file. The code is as follows:
#define ENABLE_ELG_LOG #include <elog/logger.h> using namespace elog; int main() { GlobalConfig::Get() .setFilepath(". /log/") .setLevel(Levels::kTrace) .setFormatter(formatter::colorfulFormatter); ELG_TRACE("hello elog4cpp"); ELG_DEBUG("hello elog4cpp"); ELG_INFO("hello elog4cpp"); ELG_WARN("hello elog4cpp"); ELG_ERROR("hello elog4cpp"); }
The output of the above code is output both to the file and to the console,
setFilepath(". /log/")
specifies that the output file is in thelog
folder at the next level. Note that the file path passed here can only be the output file's folder path, meaning that file output only supports scrolling logs. If the parameter is changed to". /log"
then the output folder path is the parent directory, and the output file names are prefixed withlog
. The output folder is named in the following format:.<DATE TIME>.<USERNAME>.<PID>.log
.If you want to disable output to the console, just add the following configuration:GlobalConfig::Get().enableConsole(false)
. Similarly, if you don't need to output to a file, you need to keeplog_filepath
at the default value ofnullptr
.
After the above three practices, you should have understood the basic use of this library, and if you need to understand the corresponding use in detail, you can continue to learn more about the following contents.
All configurations are based on the Config
class or the GlobalConfig
class. Note the relationship between these two classes, the Config
class acts as a base class for GlobalConfig
, Config
contains some output generic configuration, which is generally used for local configuration, and GlobalConfig
contains some special one-time configuration, which is generally used as a global singleton for global configuration.
If no local configuration is set, the global configuration is used by default. If you are using static methods or macros for log printing, then you can only use configuration via global configuration.
All global configurations are configured through a global singleton GlobalConfig
, which can be obtained by calling GlobalConfig::Get
.
-
call the methods of
GlobalConfig
to configure it, as follows.The special methods are as follows:
GlobalConfig::setRollSize(int size)
: Sets the maximum size over which a single file will create a new file for log printing, with mb as the base unit.GlobalConfig::setFlushInterval(int flushinterval)
: Sets how often to flush the log to disk, in seconds.GlobalConfig::setFilepath(const char* basedir)
: set the output path of the scrolling log, note that the path passed in is not a single file path, but a folder path, this log library only supports scrolling log.GlobalConfig::enableConsole(bool s)
: set whether to output to console.
The methods inherited from
config
are as follows:Config::setFlag(Flags flag)
: Sets flags, which can be used to control the content of the log output in a more fine-grained way, for flags there are the following enumerations.kDate
: whether to output the date.kTime
: whether to output the time.kLongname
: whether to output long file names.kShortname
: whether to output short file names.kLine
: whether output the line number.kFuncName
: whether output the function name.kThreadId
: whether output the thread id.kStdFlags
: representskDate | kTime | kShortname | kLine | kFuncName
, the or operation inside means the corresponding function is enabled.
Config::setLevel(Levels level)
: set the minimum log output level.Config::setName(const char* name)
: Set the name of the logger, which will be added to the output.Config::setBefore(callback_t const& cb)
: Sets the callback function that occurs before formatting.Config::setAfter(callback_t const& cb)
: Sets the callback function that occurs after formatting.Config::setFormatter(formatter_t const& formatter)
: Sets the formatter, which is already written by default as follows.defaultFormatter
: The default formatter.colorfulFormatter
: bring color to the output of the console desk, based on the default formatter.jsonFormatter
: Output in json format.customFromString(str) -> formatter_t
: This is a custom formatter that you can get from the string you pass in, please see the subsequent description for details on how to use it.
-
configure by passing in the json configuration file, the details are as follows. The key methods are
loadFromJSON
andloadToJSON
, which are used to read information from the json file to set the variable value ofGlobalConfig
and invert the value ofGlobalConfig
according to the value of the variable. to generate the corresponding json file. The specificjson
configuration file is as follows, and all usage is described in thecomments
.{ "comments": [ "The following values are all comments generated by default to explain the considerations for filling in the parameters", "name:optional parameter, if not filled by default, the log output will have no name", "roll_size: the threshold value for rolling the log, in mb", "flush_interval: the time in seconds to flush the log background", "out_console: whether to turn on the output console, is bool value", "out_file: if or not to turn on the output log file, use null value if not, use a folder directory if you turn on", "flag: used to turn on the log corresponding to the output data content, there are date, time, line, file, short_file, tid, func seven, can be turned on at the same time through the + sign, of course, you can also directly use default, which indicates that all options other than tid", "level:used to specify the global minimum output level, there are trace,debug,info,warn,error,fatal, the default use debug", "format: used to specify the global log formatting, there are default, colorful, custom three, the default take default, if you use custom, you need to add fmt_string", "fmt_string: only when the formatter select custom used to set the custom formatter, the corresponding data is expressed as follows: %T:time,%t:tid,%F:filepath,%f:func,%e:error info,%L:long levelText,%l: short levelText,%v:message ,%c color start %C color end" ], "elog": { "flag": "default", "flush_interval": 3, "formatter": "default", "level": "debug", "out_console": true, "out_file": "null", "roll_size": 20 } }
Two simple and complete usage examples are as follows.
-
configuration via the
GlobalConfig
method.#define ENABLE_ELG_LOG #include <elog/logger.h> using namespace elog; int main() { GlobalConfig::Get() .setRollSize(4) .setFlushInterval(3) .setFilepath(". /log/") .enableConsole(true) .setFlag(kStdFlags + kThreadId) .setLevel(kTrace) .setName("elog") .setBefore([](output_buf_t& buf) { buf.append("before"); }) .setAfter([](output_buf_t& buf) { buf.append("after"); }) .setFormatter(formatter::customFromString("%c[%L][%T][tid:%t][name:%n][file:%F][func:%f]:%v%C")); ELG_TRACE("hello elog4cpp"); ELG_DEBUG("hello elog4cpp"); ELG_INFO("hello elog4cpp"); ELG_WARN("hello elog4cpp"); ELG_ERROR("hello elog4cpp"); }
-
Similarly, you can directly load the corresponding configuration items using the equivalent
json
configuration file.The configuration items are as follows:
{ "elog": { "flag": "default+tid", "flush_interval": 3, "name": "elog", "formatter": "custom", "fmt_string": "%c[%L][%T][tid:%t][name:%n][file:%F][func:%f]:%v%C", "level": "trace", "out_console": true, "out_file": ". /log/", "roll_size": 4 } }
The code is as follows:
#define ENABLE_ELG_LOG #include <elog/logger.h> using namespace elog; int main() { GlobalConfig::Get() .loadFromJSON(". /config.json") .setBefore([](output_buf_t& buf) { buf.append("before"); }) .setAfter([](output_buf_t& buf) { buf.append("after"); }); ELG_TRACE("hello elog4cpp"); ELG_DEBUG("hello elog4cpp"); ELG_INFO("hello elog4cpp"); ELG_WARN("hello elog4cpp"); ELG_ERROR("hello elog4cpp"); }
A local configuration means that a separate Config
configuration can be used by creating a separate class. Some configurations are only available globally, specifically roolSize
, flushInterval
, outConsole
, outFile
, and because the thread responsible for output on the backend can only be a single instance, these configurations can also only be configured once.
The steps on how to use the local configuration are as follows.
- Through
Log::RegisterConfig
into your customConfig
. - Create a
Log
using the configuration with theConfig
name you inject. - Using the
Log
object, call its correspondingprintln
andprintf
methods to print.
The sample code is as follows.
#include <elog/logger.h>
#include <memory>
#include <vector>
using namespace elog;
void config_global()
{
GlobalConfig::Get()
.loadFromJSON(". /config.json")
.setBefore([](output_buf_t& buf) {
buf.append("before");
})
.setAfter([](output_buf_t& buf) {
buf.append("after");
});
}
void register_local_config()
{
auto config = make_unique<Config>();
config->log_formatter = formatter::colorfulFormatter;
config->log_name = "local_config";
config->log_level = kTrace;
config->log_flag = kStdFlags + kThreadId;
config->log_before = [](output_buf_t& buf) {
buf.append("before");
};
config->log_after = [](output_buf_t& buf) {
buf.append("after");
};
// Register Config
Log::RegisterConfig("local_config",std::move(config));
}
int main()
{
config_global();
register_local_config();
// Create Log object and set the corresponding Config and level
auto trace = Log(kTrace, "local_config");
trace.printf("hello {}", "world");
trace.println("hello", std::vector<int>{1, 2, 32});
//Change the log output level
trace.set_level(kDebug);
trace.printf("hello {}", "world");
trace.println("hello", std::vector<int>{1, 2, 32});
//Can be safely copied to continue to use
auto info = trace;
info.set_level(kInfo);
info.printf("hello {}", "world");
info.println("hello", std::vector<int>{1, 2, 32});
}
Note: Registering Config is not thread-safe, make sure you complete the registration of Config before logging out.
If you have read the previous section, then you should have some idea about the role of formatter
, which is an interface implementation for controlling formatted output.
defaultFormatter
: This is the default formatter, with a fixed format.jsonFormatter
: This is the default formatter with a fixed format.colorfulFormatter
: The output is in the same format as the formatter, but with color highlighting when output to the console.customFromString
: can customize the output format according to the string passed in by the user. Specific description.- %T: indicates the whole date and time, also includes the time zone.
- %t: indicates the thread id.
- %F: indicates which file the log output comes from.
- %f: indicates which function the log output came from.
- %e: indicates the error message if there is an error in
errno
, otherwise it is empty. - %n: indicates the name of the current logger, or null if it does not exist.
- %L: indicates a long string representing the logging level, such as
TRACE
. - %l: indicates a short string representing the log level, such as
TRC
. - %v: indicates the content of the log output.
- %c and %C: indicates the start and end of the color, valid only in terminals that support
\033
.
Since you want formatter
, it is important to be clear about what exactly formatter
is designed to do in this log library. In fact, formatter
is simply a callback function in this log library, with the following function signature.
using formatter_t = std::function<void(Config* config, context const& ctx, buffer_t&buf,Appenders apender_type)>;
The meaning of each parameter is as follows.
config
: The current configuration used for log output.ctx
: the content of the current log output, including the contents of the log to be output, the log level and line number, and other information.buf
: thebuffer
that the current log will be output to after final formatting.appder_type
: this is an enumeration representing the destination of the current log formatted output, specifically either file or console.
Based on the above explanation, if you want to implement a formatter
of your own, you can customize the formatted output to buffer
by using the configuration information of config
and the output information of ctx
and the destination information of appender_type
.
With the above understanding, we can implement our own formatter
by looking at the already implemented formatter
, for example, the source code link for defaultFormatter
is as follows: src/formatter.cc
In order to make the output of file location information without manually adding the loc::current()
parameter, the log library provides ELG_<LEVEL>
to simplify this process, so if file location information is needed you can replace Log::<Level>
with the following macro.
- ELG_TRACE
- ELG_DEBUG
- ELG_INFO
- ELG_WARN
- ELG_ERROR
- ELG_FATAL
Note: Before using the above macro, you need to define the
ENABLE_ELG_LOG
macro before#include<elog/logger.h>
.
By defining the ENABLE_ELG_CHECK
macro, we can use the following macro definitions to more easily check the relationship between values.
- Assertion macro that throws an exception if the condition is not met.
ELG_CHECK_EQ(a,b)
is equivalent toELG_ASSERT_IF(a == b)
.ELG_CHECK_NQ(a,b)
is equivalent toELG_ASSERT_IF(a != b)
.ELG_CHECK_GE(a,b)
is equivalent toELG_ASSERT_IF(a > b)
.ELG_CHECK_GT(a,b)
is equivalent toELG_ASSERT_IF(a >= b)
.ELG_CHECK_LE(a,b)
is equivalent toELG_ASSERT_IF(a < b)
.ELG_CHECK_LT(a,b)
is equivalent toELG_ASSERT_IF(a <= b)
.ELG_CHECK_NOTNULL(a)
is equivalent toELG_ASSERT_IF(a != nullptr)
.
- Judgment assertion, custom printing.
After passing in the judgment condition, an object will be returned for you to print the prompt message, and you can choose different levels to print, such as the following example to print the
trace
level.ELG_CHECK(1 == 2).trace("1 != 2");
There are also the following functions that provide convenience.
elog::Ptr
: Used to force arbitrary pointers tovoid*
, this is to facilitate printing the value of the pointer directly.elog::WaitForDone
: waits for a background thread to flush log information to disk, which is useful at times.