It is an attempt to create simple, readable, flexible
and universal logger for personal purposes.
The main idea is implement useful tool,
which can be easy added to any C++
project.
First ideas, which were implemented here, were come up and developed in the SQL to CypherQL Converter.
Now, you can download this repository and manually integrate
Logger
into your project.
- Add
logger/include
to the project include paths; - Import
logger/log.hpp
, where you want to useLogger
; - Import header with special initializer like
file_appender_initializer.hpp
to init the logger (only once); - Write your first log:
#include "logger/log.hpp" #include "logger/initializers/file_appender_initializer.hpp" int main() { logger::init(logger::info, "../log"); LOG(logger::info) << "Hello, world!"; LOGI << "Short form"; return 0; }
- Read logs in the
2022-09-25-22:26:16.log
file:2022-09-25 22:26:16 [INFO] main.cpp main() at line 7: Hello, world! 2022-09-25 22:26:16 [INFO] main.cpp main() at line 8: Short form
This tools contains a lot of macros.
You can choose any (See file log.hpp
).
The most important and "root" macros are LOG(severity)
and
LOG_IF(condition, severity)
.
Original macro | Long form | Short form | Message |
---|---|---|---|
LOG(logger::fatal) | LOG_FATAL | LOGF | fatal error |
LOG(logger::error) | LOG_ERROR | LOGE | error |
LOG(logger::warn) | LOG_WARN | LOGW | warn |
LOG(logger::info) | LOG_INFO | LOGI | info |
LOG(logger::trace) | LOG_TRACE | LOGT | trace |
LOG(logger::debug) | LOG_DEBUG | LOGD | debug |
The same table of macros, but with condition:
Original macro | Long form | Short form | Message |
---|---|---|---|
LOG_IF(condition, logger::fatal) | LOG_FATAL_IF(condition) | LOGF_IF(condition) | fatal error |
LOG_IF(condition, logger::error) | LOG_ERROR_IF(condition) | LOGE_IF(condition) | error |
LOG_IF(condition, logger::warn) | LOG_WARN_IF(condition) | LOGW_IF(condition) | warn |
LOG_IF(condition, logger::info) | LOG_INFO_IF(condition) | LOGI_IF(condition) | info |
LOG_IF(condition, logger::trace) | LOG_TRACE_IF(condition) | LOGT_IF(condition) | trace |
LOG_IF(condition, logger::debug) | LOG_DEBUG_IF(condition) | LOGD_IF(condition) | debug |
You can write logs in the several places at the same time.
Just add new appender to the logger
instance:
logger::init(logger::debug, "../log");
logger::init(logger::error, logger::cerr);
LOGF << "fatal error";
Log "fatal error" will be written in the file inside the ../log
directory and in the cerr
stream too.
Notice: if you set different severity levels to appenders, you will have logs in the output stream according to message's severity and severity of each appender.
logger::init(logger::debug, "../log");
logger::init(logger::error, logger::cerr);
LOGE << "Something went wrong!"; // will be written in both
// ...
LOGD << "try to open file..."; // will be written only in the file
open(file);
This appender writes logs in the special .log
file,
path of which was specified during logger::init
call.
When you invoke logger::init()
, you pass path to the log's directory
or to the desired regular file as the second argument.
This path is processed by internal functions and as result
new folder for the logs will be created.
New folder path will be according to this table:
Existence | Your path | Result folder | Result path |
---|---|---|---|
[exists] | /path/dir/file.cpp |
[parent path] | /path/dir |
[exists] | /path/dir |
[current path] | /path/dir |
[doesn't exist] | /path/dir/not_exists.cpp |
[parent path] | /path/dir |
[doesn't exist] | /path/dir |
[current path] | /path/dir |
[doesn't exist] | /path/dir/ |
[path to subdir] | /path/dir/dir |
This appender writes logs in the console stream (stdout
or stderr
),
which was specified during logger::init
call.
Logs recorded with the ConsoleAppender
have special colours
according to the Severity
level.
You can colour every message with special severity as you want.
Just use method set_console_colour
in the Logger
class:
void set_console_colour(Severity severity, const MessageColours& msg_cols);
where MessageColours
is a struct, which consist of two colours:
for the text and its background.
struct MessageColours {
Colour text;
Colour bg;
};
Also, you can turn coloured output off, just use the following methods:
void turn_colours_on();
void turn_colours_off();
logger::Logger::get()->set_console_colour(logger::info,
{logger::yellow, logger::common});
where logger::common
equals to "without colour"
(transparent background or common text colour).
Each formatter is a class, which has special static method format
:
static std::string format(const Record& r);
The Formatters can represent log records in different forms.
When you use init
function to initializing the logger this formatter
is set by default. Log messages represents in the following format:
2022-09-25 22:26:16 [INFO] main.cpp main() at line 11: Hello, world!
as you can see, there are timestamp, severity, file, function, line and message.
This formatter contains only message with the function, which sent it, and line.
main.cpp@11: Hello, world!
You can use this formatter, if you want see only the log messages.
Hello, world!
This formatter represents logs as json array:
[
{
"timestamp":"2023-02-17T12:46:31.237Z",
"severity":"FATAL",
"file":"main.cpp",
"function":"main",
"line":"9",
"message":"Fatal"
},
{
"timestamp":"2023-02-17T12:46:31.237Z",
"severity":"ERROR",
"file":"main.cpp",
"function":"main",
"line":"10",
"message":"Error"
}
]
Some ideas of implementation was inspired by PLOG project, which is more complicated and thoughtful for now :)
This project is licensed under the
MIT license.
You can freely use Logger
in your commercial or opensource software.