LogIt++
Loading...
Searching...
No Matches
LogIt++ Library

Defines the base path used for log file paths. If LOGIT_BASE_PATH is not defined or is empty ({}), the full path from __FILE__ will be used for log file paths.

Introduction

LogIt++ is a flexible and versatile C++ logging library that supports various backends and stream-based output. It provides an easy-to-use interface for logging messages with different severity levels and allows customization of log formats and destinations. The library combines the simplicity of macro-based logging similar to IceCream-Cpp and the configurability of logging backends and formats like spdlog.

LogIt++ is fully compatible with C++11, ensuring support for a wide range of compilers and systems.

Features

  • Flexible Log Formatting: Customize log message formats using patterns.
  • Macro-Based Logging: Easily log variables and messages using macros.
  • Multiple Backends Support: Configure loggers to output to console, files, servers, or databases.
  • Asynchronous Logging: Improve performance by logging in asynchronous mode.
  • Stream-Based Logging: Use stream operators for logging complex messages.
  • Thread-Safe: Designed to be used in multi-threaded applications.
  • Extensible: Create custom loggers and formatters to suit your needs.

Usage

Here's a simple example demonstrating how to use LogIt++ in your application:

#define LOGIT_SHORT_NAME
#include <log-it/LogIt.hpp>
int main() {
// Initialize the logger with default console output
float a = 123.456f;
int b = 789;
const char* someStr = "Hello, World!";
// Basic logging using short macros
LOG_I("Starting the application");
LOG_D(a, b);
LOG_W("This is a warning message");
// Formatted logging using short macros
LOG_IPF("Formatted log: value of a = %.2f", a);
LOG_WPF("Warning! Values: a = %.2f, b = %d", a, b);
// Error and fatal logs using short macros
LOG_EP("An error occurred with value b =", b);
LOG_F("Fatal error. Terminating application.");
// Conditional logging
LOGIT_INFO_IF(b < 0, "Value of b is negative");
LOGIT_WARN_IF(a > 100, "Value of a exceeds 100");
// Stream-based logging with short and long names
LOG_S_INFO() << "Logging a float: " << a << ", and an int: " << b;
LOG_S_ERROR() << "Error occurred in the system";
LOGIT_STREAM_WARN() << "Warning: potential issue detected with value: " << someStr;
// Using LOGIT_TRACE for tracing function execution
LOG_TRACE0(); // Trace without arguments
LOG_T("Entering main function with variable", a);
// Wait for all asynchronous logs to be processed
return 0;
}
Main header file for the LogIt++ library.
#define LOGIT_ADD_CONSOLE_DEFAULT()
Macro for adding the default console logger. This logger uses the default format pattern and asynchro...
#define LOGIT_WAIT()
Macro for waiting for all asynchronous loggers to finish processing.
#define LOGIT_INFO_IF(condition,...)
#define LOGIT_STREAM_WARN()
Definition LogMacros.hpp:29
#define LOGIT_WARN_IF(condition,...)
int main()

Log Message Formatting Flags

LogIt++ supports customizable log message formatting using format flags. You can define how each log message should appear by including placeholders for different pieces of information such as the timestamp, log level, file name, function name, and message.

Below is a list of all supported format flags and their meanings:

Date and Time Flags

  • %Y: Year (e.g., 2024)
  • %m: Month (01-12)
  • %d: Day of the month (01-31)
  • %H: Hour (00-23)
  • %M: Minute (00-59)
  • %S: Second (00-59)
  • %e: Millisecond (000-999)
  • %C: Two-digit year (e.g., 24 for 2024)
  • %c: Full date and time (e.g., Mon Oct 4 12:45:30 2024)
  • %D: Short date (e.g., 10/04/24)
  • %T, %X: Time in ISO 8601 format (e.g., 12:45:30)
  • %F: Date in ISO 8601 format (e.g., 2024-10-04)
  • %s, %E: Unix timestamp in seconds
  • %ms: Unix timestamp in milliseconds

Weekday and Month Names

  • %b: Abbreviated month name (e.g., Jan)
  • %B: Full month name (e.g., January)
  • %a: Abbreviated weekday name (e.g., Mon)
  • %A: Full weekday name (e.g., Monday)

Log Level

  • %l: Full log level (e.g., INFO, ERROR)
  • %L: Short log level (e.g., I for INFO, E for ERROR)

File and Function Information

  • %f, %fn, %bs: Base name of the source file (e.g., main.cpp)
  • %g, %ffn: Full file path (e.g., /home/user/project/src/main.cpp)
  • %@: Source file and line number (e.g., main.cpp:45)
  • %#: Line number (e.g., 45)
  • %!: Function name (e.g., main)

Thread Information

  • %t: Thread identifier

Color Formatting

  • %^: Start color formatting
  • %$: End color formatting
  • %SC: Start removing color codes (Strip Color)
  • %EC: End removing color codes (End Color)

Message Content

  • %v: The log message content

Example Format

To define a custom format for your log messages, you can use the following method:

("[%Y-%m-%d %H:%M:%S.%e] [%ffn:%#] [%!] [thread:%t] [%l] %^%v%$"));
// or...
std::make_unique<logit::ConsoleLogger>(),
std::make_unique<logit::SimpleLogFormatter>("[%Y-%m-%d %H:%M:%S.%e] [%ffn:%#] [%!] [thread:%t] [%l] %^%v%$"));
#define LOGIT_ADD_LOGGER(logger_type, logger_args, formatter_type, formatter_args)
Macro for adding a logger with a specific formatter.
Logger that outputs log messages to the console with optional color coding.
void add_logger(std::unique_ptr< ILogger > logger, std::unique_ptr< ILogFormatter > formatter, const bool &single_mode=false)
Adds a logger and its corresponding formatter.
Definition Logger.hpp:47
static Logger & get_instance()
Retrieves the singleton instance of Logger.
Definition Logger.hpp:26
A simple log formatter that formats log messages based on a user-defined pattern.

Alternatively, you can use the LOGIT_ADD_CONSOLE macro for an even simpler setup:

LOGIT_ADD_CONSOLE("[%Y-%m-%d %H:%M:%S.%e] [%ffn:%#] [%!] [thread:%t] [%l] %^%v%$", true);
#define LOGIT_ADD_CONSOLE(pattern, async)
Macro for adding a console logger with a specific pattern and mode.

This example format will produce log messages like:

[2024-10-04 12:45:30.123] [main.cpp:45] [main] [thread:1400] [INFO] This is a log message

You can adjust the format string by changing or rearranging the format flags according to your needs. For example, if you prefer short log levels and don't need thread information, you could use:

LOGIT_ADD_CONSOLE("[%Y-%m-%d %H:%M:%S.%e] [%L] %^%v%$", true);

This will produce more compact log messages like:

[2024-10-04 12:45:30.123] [I] This is a log message

You can also include static text and other custom formatting options by mixing text with the flags.

Shortened Logging Macros

LogIt++ provides shortened versions of logging macros when LOGIT_SHORT_NAME is defined. These macros allow for concise logging across different log levels, including both standard and stream-based logging.

Available TRACE-level macros:

  • Basic logging:
    • LOG_T(...): Logs a TRACE-level message.
    • LOG_T0(): Logs a TRACE-level message without arguments.
    • LOG_0T(): Alias for LOG_T0().
    • LOG_0_T(): Alias for LOG_T0().
    • LOG_T_NOARGS(): Alias for LOG_T0().
    • LOG_NOARGS_T(): Alias for LOG_T0().
  • Formatted logging:
    • LOG_TF(fmt, ...): Logs a formatted TRACE-level message using format strings.
    • LOG_FT(fmt, ...): Alias for LOG_TF(fmt, ...).
    • LOG_T_PRINT(...): Logs a TRACE-level message by printing each argument.
    • LOG_PRINT_T(...): Alias for LOG_T_PRINT(...).
    • LOG_T_PRINTF(fmt, ...): Logs a formatted TRACE-level message using printf-style formatting.
    • LOG_PRINTF_T(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
    • LOG_TP(...): Alias for LOG_T_PRINT(...).
    • LOG_PT(...): Alias for LOG_T_PRINT(...).
    • LOG_TPF(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
    • LOG_PFT(fmt, ...): Alias for LOG_T_PRINTF(fmt, ...).
  • Alternative TRACE-level macros:
    • LOG_TRACE(...): Logs a TRACE-level message (same as LOG_T(...)).
    • LOG_TRACE0(): Logs a TRACE-level message without arguments (same as LOG_T0()).
    • LOG_0TRACE(): Alias for LOG_TRACE0().
    • LOG_0_TRACE(): Alias for LOG_TRACE0().
    • LOG_TRACE_NOARGS(): Logs a TRACE-level message with no arguments (same as LOG_T_NOARGS()).
    • LOG_NOARGS_TRACE(): Alias for LOG_TRACE_NOARGS().
    • LOG_TRACEF(fmt, ...): Logs a formatted TRACE-level message (same as LOG_TF(fmt, ...)).
    • LOG_FTRACE(fmt, ...): Alias for LOG_TRACEF(fmt, ...).
    • LOG_TRACE_PRINT(...): Logs a TRACE-level message by printing each argument (same as LOG_T_PRINT(...)).
    • LOG_PRINT_TRACE(...): Alias for LOG_TRACE_PRINT(...).
    • LOG_TRACE_PRINTF(fmt, ...): Logs a formatted TRACE-level message using printf-style formatting (same as LOG_T_PRINTF(fmt, ...)).
    • LOG_PRINTF_TRACE(fmt, ...): Alias for LOG_TRACE_PRINTF(fmt, ...).

These macros provide flexibility and convenience when logging messages at the TRACE level. They allow you to choose between different logging styles, such as standard logging, formatted logging, and printing each argument separately.

Note:

Similar macros are available for other log levels — INFO (LOG_I, LOG_INFO), DEBUG (LOG_D, LOG_DEBUG), WARN (LOG_W, LOG_WARN), ERROR (LOG_E, LOG_ERROR), and FATAL (LOG_F, LOG_FATAL). The naming conventions are consistent across levels, you only need to replace the level letter or word in the macro name.

LOG_T("Trace message using short macro");
LOG_FT("%.4d", 999);
LOG_PRINT_T("Printing trace message with multiple variables: ", var1, var2);
LOG_TRACE("Trace message (alias for LOG_T)");
LOG_PRINTF_TRACE("Formatted trace: value = %d", value);

Configuration Macros

LogIt++ provides several macros that allow for customization and configuration. Below are the available configuration macros:

  • LOGIT_BASE_PATH:
// Defines the base path for project folder.
#define LOGIT_BASE_PATH "/path/to/your/project"
  • LOGIT_DEFAULT_COLOR:

Sets the default color for console output. If LOGIT_DEFAULT_COLOR is not defined, it defaults to TextColor::LightGray.

// Sets the default log message color to green.
#define LOGIT_DEFAULT_COLOR TextColor::Green
  • LOGIT_COLOR_<LOG_LEVEL>:

Defines the console text color for each log level. By default, each log level is associated with a specific color, but these can be customized.

Available log levels:

  • TRACE: Defaults to TextColor::DarkGray
  • DEBUG: Defaults to TextColor::Blue
  • INFO: Defaults to TextColor::Green
  • WARN: Defaults to TextColor::Yellow
  • ERROR: Defaults to TextColor::Red
  • FATAL: Defaults to TextColor::Magenta
// Customize the color for different log levels
#define LOGIT_COLOR_TRACE TextColor::Blue
#define LOGIT_COLOR_ERROR TextColor::Cyan
  • LOGIT_CURRENT_TIMESTAMP_MS:

Macro to get the current timestamp in milliseconds. By default, it uses std::chrono for time calculation. You can override this to customize the timestamp generation.

// Customize timestamp calculation if needed.
#define LOGIT_CURRENT_TIMESTAMP_MS() my_custom_timestamp_function()
  • LOGIT_CONSOLE_PATTERN:

Defines the default log pattern for the console logger. If LOGIT_CONSOLE_PATTERN is not defined, it defaults to %H:%M:%S.%e | %^%v%$.

// Customize the console log message pattern.
#define LOGIT_CONSOLE_PATTERN "%H:%M:%S.%e | %v"
  • LOGIT_FILE_LOGGER_PATH:

Defines the default directory path for log files. If LOGIT_FILE_LOGGER_PATH is not defined, it defaults to "data/logs".

// Specify a custom path for log files.
#define LOGIT_FILE_LOGGER_PATH "/custom/log/directory"
  • LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS:

Defines the number of days after which old log files are deleted. If LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS is not defined, it defaults to 30 days.

// Set the number of days to keep log files.
#define LOGIT_FILE_LOGGER_AUTO_DELETE_DAYS 60
  • LOGIT_FILE_LOGGER_PATTERN:

Defines the default log pattern for file-based loggers. If LOGIT_FILE_LOGGER_PATTERN is not defined, it defaults to [%Y-%m-%d %H:%M:%S.%e] [%ffn:%#] [%!] [thread:%t] [%l] %SC%v.

// Customize the log file message pattern.
#define LOGIT_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v"
  • LOGIT_UNIQUE_FILE_LOGGER_PATH:

Defines the default directory path for unique log files. If LOGIT_UNIQUE_FILE_LOGGER_PATH is not defined, it defaults to "data/logs/unique_logs".

// Specify a custom path for unique log files.
#define LOGIT_UNIQUE_FILE_LOGGER_PATH "/custom/unique/log/directory"
  • LOGIT_UNIQUE_FILE_LOGGER_PATTERN:

Defines the default log pattern for unique file-based loggers. If LOGIT_UNIQUE_FILE_LOGGER_PATTERN is not defined, it defaults to v.

// Customize the unique file log message pattern.
#define LOGIT_UNIQUE_FILE_LOGGER_PATTERN "[%Y-%m-%d %H:%M:%S.%e] [%l] %v"
  • LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH:

Defines the length of the hash used in the unique log file names. If LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH is not defined, it defaults to 8 characters.

This macro controls the length of the hash part in the filenames for unique log files, ensuring unique names for each log.

// Set the hash length to 12 characters for unique file names.
#define LOGIT_UNIQUE_FILE_LOGGER_HASH_LENGTH 12
  • LOGIT_SHORT_NAME:

Enables short names for logging macros, such as LOG_T, LOG_D, LOG_E, etc., for concise logging.

// Enable short macro names for logging.
#define LOGIT_SHORT_NAME
  • LOGIT_USE_FMT_LIB:

Enables the use of the fmt library for string formatting. If defined, the logging system will use fmt for advanced formatting of log messages.

// Enable use of the fmt library for formatting.
#define LOGIT_USE_FMT_LIB

Custom Logger Backend and Formatter

LogIt++ allows you to extend the logging system by creating your own loggers and formatters. This section explains how to implement a custom backend for logging and a custom log formatter.

Custom Logger Example

To create a custom logger backend, you need to implement the ILogger interface, which requires defining the log() and wait() methods. Here's an example of a simple custom logger that logs messages to a text file:

#include <fstream>
#include <mutex>
#include <log-it/LogIt.hpp>
class FileLogger : public logit::ILogger {
public:
// Constructor to initialize the file logger with a file name
FileLogger(const std::string& file_name) : m_file_name(file_name) {
m_log_file.open(file_name, std::ios::out | std::ios::app);
}
~FileLogger() {
if (m_log_file.is_open()) {
m_log_file.close();
}
}
// Logs the message to the file
void log(const logit::LogRecord& record, const std::string& message) override {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_log_file.is_open()) {
m_log_file << message << std::endl;
}
}
// Waits for any asynchronous log operations (none in this case)
void wait() override {
// No async processing, so no need to implement
}
private:
std::string m_file_name;
std::ofstream m_log_file;
std::mutex m_mutex;
};
Interface for loggers that handle log message output.
Definition ILogger.hpp:13
virtual void log(const LogRecord &, const std::string &)=0
Logs a message.
virtual void wait()=0
Waits for all asynchronous logging operations to complete.
Stores log metadata and content.
Definition LogRecord.hpp:15

This FileLogger class writes log messages to a specified file. You can add this logger to your logging system like this:

FileLogger, ("logfile.txt"),
// or...
std::make_unique<FileLogger>("logfile.txt"),
std::make_unique<logit::SimpleLogFormatter>());

Custom Formatter Example

In addition to creating custom loggers, you can also create custom formatters by implementing the ILogFormatter interface. Here's an example of a simple formatter that outputs log messages in JSON format:

#include <log-it/LogIt.hpp>
#include <json/json.h> // Or your preferred JSON library
class JsonLogFormatter : public logit::ILogFormatter {
public:
// Formats the log record into a JSON string
std::string format(const logit::LogRecord& record) const override {
Json::Value log_entry;
log_entry["level"] = static_cast<int>(record.log_level);
log_entry["timestamp_ms"] = record.timestamp_ms;
log_entry["file"] = record.file;
log_entry["line"] = record.line;
log_entry["function"] = record.function;
log_entry["message"] = record.format;
Json::StreamWriterBuilder writer;
return Json::writeString(writer, log_entry);
}
};
Interface for formatting log records.
virtual std::string format(const LogRecord &record) const =0
Formats a log record into a string.
const std::string function
Function name.
Definition LogRecord.hpp:20
const int line
Line number in the source file.
Definition LogRecord.hpp:19
const LogLevel log_level
Log level (severity).
Definition LogRecord.hpp:16
const int64_t timestamp_ms
Timestamp in milliseconds.
Definition LogRecord.hpp:17
const std::string file
Source file name.
Definition LogRecord.hpp:18
const std::string format
Format string for the message.
Definition LogRecord.hpp:21

This JsonLogFormatter formats log messages as JSON objects. You can combine it with any logger, including the FileLogger, as shown below:

FileLogger, ("logfile.json"),
logit::JsonLogFormatter, ());
// or...
std::make_unique<FileLogger>("logfile.json"),
std::make_unique<JsonLogFormatter>());

Summary

By implementing your own ILogger and ILogFormatter, you can extend the functionality of LogIt++ to log messages to various destinations or in different formats. You can combine custom loggers and formatters to create powerful logging solutions tailored to your application's needs.

Here's a quick summary:

  • ILogger: Defines where the logs should be sent (e.g., file, console, database, network).
  • ILogFormatter: Defines how the logs should be formatted (e.g., plain text, JSON, XML).
  • Adding to Logger: Use logit::Logger::get_instance().add_logger() to add your custom logger and formatter to the logging system.

Installation

LogIt++ is a header-only library, which means it can be easily included in your project without the need for compilation or linking. Below are the steps to integrate it into your project.

Step 1: Clone the Repository

First, clone the LogIt++ repository from GitHub along with its submodules. The library has dependencies on other header-only libraries, such as time-shield-cpp (for time utilities) and fmt (for string formatting, if LOGIT_USE_FMT_LIB is enabled).

To clone the repository with submodules, use the following command:

git clone --recurse-submodules https://github.com/NewYaroslav/log-it-cpp.git

If you have already cloned the repository without submodules, you can initialize and update the submodules by running the following commands:

git submodule init
git submodule update

Step 2: Include the LogIt++ Headers in Your Project

Since LogIt++ is a header-only library, you can simply include the main header in your project:

#include <log-it/LogIt.hpp>

This will give you access to the entire logging system.

Step 3: Configure the Path for Dependencies

LogIt++ depends on time-shield-cpp, which is located in the libs folder as a submodule. Ensure that the path to libs\time-shield-cpp\include is added to your project's include directories. If you are using an IDE like Visual Studio or CLion, you can add the include path in the project settings.

Step 4: Using fmt (Optional)

LogIt++ supports the fmt library for advanced string formatting, which is also included as a submodule. To enable fmt in LogIt++, define the macro LOGIT_USE_FMT_LIB in your project:

#define LOGIT_USE_FMT_LIB

This will allow you to use fmt-style formatting within your log messages. The fmt library is also located in the libs folder of the repository.

Step 5: Build and Run Your Project

After adding the necessary include paths, you can proceed to build and run your project. LogIt++ is designed to be easy to integrate and requires no linking since it's header-only.

Repository

The LogIt++ library is open-source and hosted on GitHub: LogIt++ GitHub Repository.

License

This library is licensed under the MIT License. See the LICENSE file in the repository for more details.