KasperskyOS Community Edition 1.3

LogRR component

The LogRR component provides a system for logging information about program operation. The component includes a server program to which other programs forward messages about their state, and auxiliary output channels used for logging. Messages are sent to the server by using the logrr_clog library (the logrr_cpp library is available for C++), which filters messages according to the log level and sends them to the server. The server relays messages to output channels. An output channel saves log messages to files.

In the SDK, the LogRR program APIs are represented by static and dynamic libraries linked to the programs whose operating information is logged:

  • The logrr_clog library and the header file sysroot-*-kos/include/component/logrr/clog/clog.h are used in C-language programs.
  • The logrr_cpp library and the header file sysroot-*-kos/include/component/logrr/cpp/logger.h are used in C++ programs.

In this section

Adding a log server and output channels to a solution

Getting log entries when running in QEMU

Using macros to send messages to a log

Advanced capabilities when sending messages to a log

Log levels

LogRR program API

Page top
[Topic logrr_component]

Adding a log server and output channels to a solution

The LogrrServer program sends messages to one or more output channels. You can write log messages to files by using the output channel named FsOutputChannel.

Adding and configuring logging server

The command for creating and configuring the log server create_logrr_server() may contain the following parameters:

LOG_LEVEL
Sets the specified log level. The available values for LOG_LEVEL are CRITICAL, ERROR, WARNING, INFO, DEBUG and TRACE. By default, the log server handles messages with the Info level.
CONFIG_PATH
Specifies the path to the configuration file of the log server.
RECV_CORE_LOGS
Enables collection of kernel logs.
WRITE_TO_CORE
Enables forwarding of logs to the kernel. Does not exclude forwarding of logs to the log server or further to the output channel. Required for printing logs to UART.
OUTPUT_CHANNELS
Connects one or more specified output channels to the server.
DENY_DYNAMIC_CONN_TYPES
Enables rejection of dynamic connections to the log server.
DENY_STATIC_CONN_TYPES
Enables rejection of static connections to the log server.

To add the LogrrServer program to a solution:

Edit the root file containing the CMake commands for building the solution or the file containing the CMake commands for building the Einit initializing program:

CMakeLists.txt

find_package (logrr_server REQUIRED COMPONENTS ENTITY) # ... set (TASKS # ... ${logrr_server_ENTITY}) # ... # Add the server that uses the output channel FsOutputChannel create_logrr_server( LOG_LEVEL DEBUG WRITE_TO_CORE ON OUTPUT_CHANNELS logrr.FsOutputChannel) # Adding a server and output channel to a solution list(APPEND ENTITIES logrr_server::default_entity logrr_fs_output_channel::default_entity) # Create static IPC channels for source programs to connect to the server connect_to_logrr_server (ENTITIES ClientOne) build_kos_qemu_image (kos-qemu-image CONNECTIONS_CFG ${INIT_YAML_FILE} SECURITY_PSL ${SECURITY_PSL_FILE} PACK_DEPS ON ${TASKS})

The PACK_DEPS option must be included when calling the build_kos_qemu_image() or build_kos_hw_image() command to include an automatic build of the libraries in the disk image.

Adding and configuring output channels

The command for creating and configuring the channel for printing logs to files create_logrr_fs_output_channel() may contain the following parameters:

CONFIG_PATH
Specifies the path to the configuration file of the output channel.
SERVER_TARGET
Specifies the log server to which the created output channel must connect.
APP_LOG_DIR
Specifies the directory for storing log files for programs. Required parameter.
SYS_LOG_DIR
Specifies the directory for storing system log files. If this parameter is not defined, system log files are not saved.

To add the FsOutputChannel to a solution:

Edit the root file containing the CMake commands for building the solution or the file containing the CMake commands for building the Einit initializing program:

CMakeLists.txt

find_package (logrr_fs_output_channel REQUIRED COMPONENTS ENTITY) # Add the FsOutputChannel that writes to the file create_logrr_fs_output_channel ( APP_LOG_DIR "/log/apps" SYS_LOG_DIR "/log/sys")

Creating IPC channels and allowing interaction between programs

The build system automatically creates IPC channels required for the log system to work, and generates a security policy description that allows interaction between processes.

To create a static connection to the log server, you can use the CMake command connect_to_logrr_server (ENTITIES <names_of_programs_to_connect>).

Page top
[Topic logrr_component_add]

Getting log entries when running in QEMU

The client libraries logrr_clog and logrr_cpp send messages to the kernel, which forwards them to the UART port. You can forward data from an emulated UART port to a standard I/O stream by specifying the -serial stdio flag when starting QEMU. In this case, log messages will be displayed in the terminal in which QEMU is running.

Specify the QEMU startup flags in the value of the QEMU_FLAGS parameter that is passed to the build_kos_qemu_image() command:

CMakeLists.txt

build_kos_qemu_image (kos-qemu-image # ... QEMU_FLAGS "-m 4096 -serial stdio" # ... )
Page top
[Topic logrr_component_qemu]

Using macros to send messages to a log

The LogRR program provides macros for quickly accessing logging functions with a specific log level.

Example use of macros in a C-language program:

C

#include <component/logrr/clog/clog.h> // ... CLOG(CRITICAL, "Critical message. Exit code = %d", 404); CLOG(ERROR, "Error message. Error code = %d", 13); CLOG(WARNING, "Warning message. Details: %s", "operation not permitted."); CLOG(INFO, "Info message. Status: %s", "connected."); CLOG(DEBUG, "Debug message."); CLOG(TRACE, "Trace message.");

To use these macros, you need to link the program to the logrr_clog library.

Example use of macros in a C++ program:

C++

#include <component/logrr/cpp/logger.h> // ... LOG(CRITICAL, "Critical message. Exit code = {}", 404); LOG(ERROR, "Error message. Error code = {}", 13); LOG(WARNING, "Warning message. Details: {}", "operation not permitted."); LOG(INFO, "Info message. Status: {}", "connected."); LOG(DEBUG, "Debug message."); LOG(TRACE, "Trace message.");

To use these macros, you need to link the program to the logrr_cpp library.

See also:

Advanced capabilities when sending messages to a log

Page top
[Topic logrr_component_macros]

Advanced capabilities when sending messages to a log

In most cases, you can send messages to the log by simply using macros for quick access to logging functions.

This section describes the additional capabilities of the logrr_cpp library API: merging messages, condition-based message forwarding, and deferred forwarding of messages.

Merging messages

To incrementally build the text of a log entry from parts and then send the entry to the log with one call:

  1. Link the program to the logrr_cpp library.
  2. Include the header file component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Create an instance of the LogIface class.

    C++

    auto logger = LogIface(logrr::LogLevel::Warning);
  4. Fill the message buffer with one or more calls of the LogIface::Push() method.

    C++

    logger.Push("a={}", a); // ... logger.Push(", b={}", b); // ... logger.Push(", c={}", c);
  5. Send the previously received messages to the log by using the LogIface::Flush() method.

    C++

    logger.Flush();

Sending a message to the log based on a condition

To send a message to the log only when a specified condition is fulfilled:

  1. Link the program to the logrr_cpp library.
  2. Include the header file component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Pass the logical value, one of the LogLevel enumerators, and the message text to the LOG_IF() macro.

    C++

    LOG_IF(IsWorldBroken(), logrr::LogLevel::Critical, "World is broken!");

Deferred forwarding of messages to the log

The LOG_DEFER() macro declared in the header file component/logrr/cpp/tools.h lets you avoid duplicating code for logging in the if...else blocks.

To send a pre-formatted message to the log when exiting a function:

  1. Link the program to the logrr_cpp library.
  2. Include the header file component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Add a LOG_DEFER() macro call to the beginning of the code for the function that changes the values that need to be sent to the log. Pass the LogLevel value, message formatting string and arguments to be inserted in the formatting string to the macro.

    C++

    int DeferredLoggingExample() { auto logger = LOG_DEFER(logrr::LogLevel::Info, "a={}, b={}", a, b); if (someCondition) { a = 1; b = 2; return -1; } else { a = 3; b = 4; return 0; } }

In this example, a message is sent to the log when the logger object's destructor is called on exit from the DeferredLoggingExample() function. The values a and b at the time of exit from the function are inserted into the message formatting string.

Page top
[Topic logrr_component_additional]

Log levels

A log level is an attribute of each message in the logging system. The log level is configured through the server and is used when filtering messages in a client.

Critical
Critical malfunction in program operation that makes it impossible for the program to continue working.
Error
Program operating error that does not completely prevent the program from continuing to work. This level is applied for logging an unexpected termination of the current operation. It is not recommended to apply this level for logging erroneous user actions.
Warning
Problem situation that is anticipated and normally handled by the program.
Info (default)
Information about the current functional performance of the program without additional details. For example, this info can include switching to a new window in the user interface or successfully writing an entry in the database.
Debug
More detailed log level than Info. It provides more details on program events and may be useful for debugging.
Trace
The most detailed log level that is used for the most detailed tracking of program events. When this level is enabled, it can have a substantial impact on performance.

Each successive level includes all previous levels. For example, if a server is configured for the Warning level, it forwards messages with the Critical, Error and Warning levels to the log while ignoring messages with the Info, Debug and Trace levels.

The log level when the program sends a message can be defined by doing the following:

  • Using the macro with the parameter corresponding to the selected level.
  • Passing the value of the LogrrLogLevel or LogLevel enumerator when logging functions are called.
Page top
[Topic logrr_component_loglevels]

LogRR program API

The libraries of the LogRR program provide APIs for sending messages to the log through the log server and APIs for managing the log server.

In this Help section

logrr_clog library

logrr_cpp library

Page top
[Topic logrr_api]

logrr_clog library

The logrr_clog library provides the API for sending messages to the log.

The logrr_clog library is intended for use in C-language programs. Use the logrr_cpp library in C++ programs.

To get access to the API of this library:

Link your program to the library by using the target_link_libraries() CMake command.

CMakeLists.txt

target_link_libraries (${TARGET_NAME} ${logrr_clog_LIB})

In this Help section

ClogLog() function and CLOG macro

LogrrLogLevel enumerated type

Page top
[Topic logrr_api_clog]

ClogLog() function and CLOG macro

The ClogLog() function writes to the log.

The ClogLog() function is intended for use in C-language programs. In C++ programs, use the Logger::Log() function or LOG_* macros.

A description of the ClogLog() function and macros for quick access to it are provided in the file /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/clog/clog.h.

component/logrr/clog/clog.h (fragment)

__attribute__((format(printf, 6, 7))) void ClogLog(const char *module, LogLevel level, const char *file, int line, const char *func, const char *message, ...); #define CLOG_TRACE_IMPL_EX(level, file, line, func, ...) \ ClogLog(LOG_MODULE, level, file, line, func, __VA_ARGS__) #define CLOG_TRACE_IMPL(level, ...) \ CLOG_TRACE_IMPL_EX((level), \ __FILENAME__, \ __LINE__, \ __func__, \ __VA_ARGS__) #define __CLOG_LEVEL_TRACE__ LogrrLogLevel_Trace #define __CLOG_LEVEL_DEBUG__ LogrrLogLevel_Debug #define __CLOG_LEVEL_INFO__ LogrrLogLevel_Info #define __CLOG_LEVEL_WARNING__ LogrrLogLevel_Warning #define __CLOG_LEVEL_ERROR__ LogrrLogLevel_Error #define __CLOG_LEVEL_CRITICAL__ LogrrLogLevel_Critical #define CLOG(level, ...) CLOG_TRACE_IMPL(__CLOG_LEVEL_ ## level ## __, __VA_ARGS__)

Parameters of the ClogLog() function:

level
Log level LogrrLogLevel.
file
File name.
line
Number of the line in the file.
func
Function name.
message
Message text or message text formatting string.
...
Parameters to be inserted into the message formatting string.

Macro for quick access to the ClogLog() function

Instead of calling the ClogLog() function, you can use the macro whose description is provided in the file component/logrr/clog/clog.h. This macros is variadic (takes a variable number of parameters), which lets you avoid specifying all parameters of the ClogLog() function. When calling this macro, you only need to specify the log level and message text or the message formatting string with the values of parameters. The applied log level is determined by the first parameter of the macro. An example of using this macro is provided in the section titled Using macros to send messages to a log.

Page top
[Topic logrr_api_clog_macro]

LogrrLogLevel enumerated type

The enumerated type LogrrLogLevel contains fields whose names correspond to the log levels available in the LogRR program.

The enumerated type LogrrLogLevel is intended for use in C-language programs. In C++ programs, use the LogLevel class.

LogrrLogLevel enumerators can be passed to the ClogLog() function to send a message with the specified log level.

A description of LogrrLogLevel enumeration is provided in the file /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/core/log_level_c.h.

component/logrr/core/log_level_c.h (fragment)

typedef enum LogrrLogLevel { LogrrLogLevel_Critical, /*!< Critical errors when process can't continue to work. */ LogrrLogLevel_Error, /*!< Some issues that allow to continue application execution. */ LogrrLogLevel_Warning, /*!< Some regular errors that application can handle. */ LogrrLogLevel_Info, /*!< Some useful information about application work/state. */ LogrrLogLevel_Debug, /*!< Detailed log to understand/fix some specific issues. */ LogrrLogLevel_Trace, /*!< To "trace" some function execution. May affect performance. */ } LogLevel;
Page top
[Topic logrr_api_logrrloglevel]

The logrr_cpp library

The logrr_cpp library provides the API for sending messages to the log.

The logrr_cpp library is intended for use in C++ programs. In C-language programs, use the logrr_clog library.

To get access to the API of this library:

Link your program to the library by using the target_link_libraries() CMake command.

CMakeLists.txt

target_link_libraries (${TARGET_NAME} ${logrr_cpp_LIB})

In this Help section

Log() method and LOG macro

LogLevel class

LogIface class

Page top
[Topic logrr_api_cpp]

Log() method and LOG macro

The logrr::Log() method writes to the log.

Method parameters:

logLevel
Log level LogLevel.
sourceLocation
Object that determines the location in the source code (file name, function name, line number and column number). The std::source_location class is used in C++20, while the std::experimental::source_location class is used in earlier versions.
format
Message text formatting string.
args
Parameters to be inserted into the format formatting string.

The logrr::Log() method is intended for use in C++ programs. In C-language programs, use the static function ClogLog() or CLOG macro.

A description of the logrr::Log() method and macros for quick access to it are provided in the file /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/cpp/logger.h.

component/logrr/cpp/logger.h (fragment)

namespace logrr { namespace details { __rtl_public void PrintErrorMessage(std::string_view fileName, std::uint32_t line, std::string_view exMsg) noexcept; } // namespace details __rtl_public void Init(std::string_view providerName) noexcept; __rtl_public bool ShouldLog(logrr::LogLevel logLevel) noexcept; __rtl_public void SendMessage( std::string_view module, LogLevel logLevel, std::string_view file, const uint32_t line, std::string_view function, std::string_view msg) noexcept; template <typename... Args> __rtl_public void Log( logrr::LogLevel logLevel, kos::rtl::SourceLocation sourceLocation, std::string_view format, Args&&... args) noexcept { Log(logLevel, sourceLocation.file_name(), sourceLocation.line(), sourceLocation.function_name(), format, std::forward<Args>(args)...); } template <typename... Args> __rtl_public void Log( std::string_view module, logrr::LogLevel logLevel, kos::rtl::SourceLocation sourceLocation, std::string_view format, Args&&... args) noexcept { Log(module, logLevel, sourceLocation.file_name(), sourceLocation.line(), sourceLocation.function_name(), format, std::forward<Args>(args)...); } template <typename... Args> __rtl_public void Log( logrr::LogLevel logLevel, std::string_view file, const uint32_t line, std::string_view function, std::string_view format, Args&&... args) noexcept { Log("", logLevel, file, line, function, format, std::forward<Args>(args)...); } template <typename... Args> __rtl_public void Log( std::string_view module, logrr::LogLevel logLevel, std::string_view file, const uint32_t line, std::string_view function, std::string_view format, Args&&... args) noexcept { if (ShouldLog(logLevel)) try { constexpr auto MaxLength = static_cast<std::size_t>(LOGRR_LOG_MESSAGE_MAX_SIZE - 1); if constexpr (!sizeof...(args)) { SendMessage(module, logLevel, file, line, function, format.substr(0, MaxLength)); } else { std::array<std::uint8_t, MaxLength> fmtBuf; const auto endIt{fmt::format_to_n( fmtBuf.begin(), MaxLength, format, std::forward<Args>(args)...).out}; const std::string_view formattedStr{ reinterpret_cast<const char*>(fmtBuf.data()), static_cast<std::size_t>(std::distance(fmtBuf.begin(), endIt))}; SendMessage(module, logLevel, file, line, function, formattedStr); } } catch (const std::exception& e) { details::PrintErrorMessage(file, line, e.what()); } } } // namespace logrr namespace { const std::string_view LOG_MODULE; } // namespace #define __CPPLOG_LEVEL_TRACE__ logrr::LogLevel::Trace #define __CPPLOG_LEVEL_DEBUG__ logrr::LogLevel::Debug #define __CPPLOG_LEVEL_INFO__ logrr::LogLevel::Info #define __CPPLOG_LEVEL_WARNING__ logrr::LogLevel::Warning #define __CPPLOG_LEVEL_ERROR__ logrr::LogLevel::Error #define __CPPLOG_LEVEL_CRITICAL__ logrr::LogLevel::Critical #define LOG_INIT(providerName) \ logrr::Init(providerName) #define CALL_LOG(level, ...) \ logrr::Log(LOG_MODULE, level, kos::rtl::SourceLocation::current(), __VA_ARGS__) #define CALL_LOG_SL(level, file, line, func, ...) \ logrr::Log(LOG_MODULE, level, file, line, func, __VA_ARGS__) #define LOG(level, ...) CALL_LOG(__CPPLOG_LEVEL_ ## level ## __, __VA_ARGS__) #define LOG_SL(level, file, line, func, ...) CALL_LOG_SL(__CPPLOG_LEVEL_ ## level ## __, file, line, func, __VA_ARGS__)

A macro for quick access to the Log() method

Instead of calling the static method Logger::Log(), you can use the macro whose description is provided in the file component/logrr/cpp/logger.h. This macro is variadic (takes a variable number of parameters), which lets you avoid specifying all parameters of the Logger::Log() method. When calling this macro, you only need to specify the log level and message formatting string with the values of parameters. The applied log level logLevel is determined by the first parameter of the macro: An example of using these macros is provided in the section titled Using macros to send messages to a log.

Page top
[Topic logrr_api_cpp_log]

LogLevel class

The LogLevel class is an enumeration (enum class) and contains fields whose names correspond to the log levels available in the LogRR program.

The LogLevel class is intended for use in C++ programs. In C-language programs, use the enumerated type LogrrLogLevel.

Values of LogLevel enumeration can be passed to the following:

  • Static method Log() of the Logger class
  • Static methods ChangeLogLevel() and ChangeGlobalLogLevel() of the Controller structure
  • LogIface class constructor

A description of the LogLevel class is provided in the file /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/core/log_level.h.

component/logrr/core/log_level.h (fragment)

enum class LogLevel : int8_t { Critical = 0, Error, Warning, Info, Debug, Trace };
Page top
[Topic logrr_api_cpp_loglevel]

LogIface class

The LogIface class contains methods that let you incrementally build the text of a log entry from parts and then send the entry to the log with one call:

  • The SetLogLevel() method is used to set the log level of sent messages.
  • The Push() method is used to add text to a message.
  • The Flush() method is used to send a message composed of one or more Push() method calls to the log.

    When the ~LogIface() destructor is called, the message composed of Push() calls is also sent to the log if the message was not previously sent using Flush().

  • The Log() method is used to immediately send a separate message (without using the text composed of Push() calls).

To create a LogIface class instance, pass one of the LogLevel enumerators to the class constructor. An example of using functions of the LogIface class is provided in the "Merging messages" subsection under Advanced capabilities when sending messages to a log.

A description of the LogIface class is provided in the file /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/cpp/tools.h.

component/logrr/cpp/tools.h (fragment)

/** * @brief C++ provider interface for logrr for simple printing and queuing logs * */ class LogIface { // ... public: LogIface(logrr::LogLevel level, sl::source_location loc = sl::source_location::current()) : m_level(level), m_defaultSourceLocation(loc) {} void SetLogLevel(logrr::LogLevel new_level) { m_level = new_level; } /** * @brief Append new format with args to current message template * */ template <typename... Args> void Push(std::string_view frmt, Args&&... args) { AppendFormat(m_message, frmt, std::forward<Args>(args)...); } /** * @brief Log instantly through separate Log command * */ template <typename... Args> void Log(FormatWithLocation frmt, Args&&... args) { Flush_(frmt.loc, frmt.frmt, std::forward<Args>(args)...); } /** * @brief Flush current message, built with Push, to Log * */ void Flush(const sl::source_location& loc = sl::source_location::current()) { Flush_(loc, m_message); m_message.clear(); } ~LogIface() { if (!m_message.empty()) { Flush_(m_defaultSourceLocation, m_message); } } // ... };
Page top
[Topic logrr_api_cpp_logiface]