KasperskyOS Community Edition 1.3

Компонент LogRR

Компонент LogRR – система для журналирования информации о работе программ. Компонент включает в себя программу-сервер, которому другие программы передают сообщения о своем состоянии, и вспомогательные каналы вывода для журналирования. Для отправки сообщений серверу прикладные программы используют библиотеку logrr_clog (для C++ доступна библиотека logrr_cpp), которая фильтрует сообщения по уровню журналирования и отправляет их серверу. Сервер передаёт сообщения каналам вывода. Канал вывода сохраняет сообщения журнала в файлы.

В SDK API программы LogRR представлены статическими и динамическими библиотеками, компонуемыми с программами, информация о работе которых журналируется:

  • в программах на языке C используется библиотека logrr_clog и заголовочный файл sysroot-*-kos/include/component/logrr/clog/clog.h.
  • в программах на языке С++ используется библиотека logrr_cpp и заголовочный файл sysroot-*-kos/include/component/logrr/cpp/logger.h.

В этом разделе

Добавление сервера журналирования и каналов вывода в решение

Получение записей журнала при работе в QEMU

Отправка сообщений в журнал с помощью макросов

Дополнительные возможности при отправке сообщений в журнал

Уровни журналирования

API программы LogRR

В начало
[Topic logrr_component]

Добавление сервера журналирования и каналов вывода в решение

Программа LogrrServer отправляет сообщения одному или нескольким каналам вывода. Вы можете записывать сообщения журнала в файлы, используя канал вывода FsOutputChannel.

Добавление и настройка сервера журналирования

Команда создания и настройки сервера журналирования create_logrr_server() может содержать следующие параметры:

LOG_LEVEL
Устанавливает указанный уровень журналирования. Доступные значения LOG_LEVEL: CRITICAL, ERROR, WARNING, INFO, DEBUG и TRACE. По умолчанию, сервер журналирования обрабатывает сообщения с уровнем Info.
CONFIG_PATH
Указывает путь до конфигурационного файла сервера журналирования.
RECV_CORE_LOGS
Включает сбор журналов ядра.
WRITE_TO_CORE
Включает передачу журналов в ядро. Не исключает передачу журналов серверу журналирование и далее в канал вывода. Требуется для вывода журналов в UART.
OUTPUT_CHANNELS
Подключает один или несколько указанных каналов вывода к серверу.
DENY_DYNAMIC_CONN_TYPES
Включает отклонение динамических подключений к серверу журналирования.
DENY_STATIC_CONN_TYPES
Включает отклонение статических подключений к серверу журналирования.

Чтобы добавить программу LogrrServer в решение,

отредактируйте корневой файл с CMake-командами сборки решения или файл с CMake-командами сборки инициализирующей программы Einit:

CMakeLists.txt

find_package (logrr_server REQUIRED COMPONENTS ENTITY) # ... set (TASKS # ... ${logrr_server_ENTITY}) # ... # Добавление сервера, использующего канал вывода FsOutputChannel create_logrr_server( LOG_LEVEL DEBUG WRITE_TO_CORE ON OUTPUT_CHANNELS logrr.FsOutputChannel) # Добавление сервера и канала вывода в решение list(APPEND ENTITIES logrr_server::default_entity logrr_fs_output_channel::default_entity) # Создание статических IPC-каналов для программ-источников с сервером 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})

Опцию PACK_DEPS требуется включить при вызове команды build_kos_qemu_image() или build_kos_hw_image() для включения автоматической сборки библиотек в образ диска.

Добавление и настройка каналов вывода

Команда создания и настройки канала вывода журналов в файлы create_logrr_fs_output_channel() может содержать следующие параметры:

CONFIG_PATH
Указывает путь до конфигурационного файла канала вывода.
SERVER_TARGET
Указывает сервер журналирования, к которому требуется подключить создаваемый канал вывода.
APP_LOG_DIR
Указывает директорию хранения файлов журналов для программ. Обязательный параметр.
SYS_LOG_DIR
Указывает директорию хранения файлов журналов системы. Если параметр не задан, файлы журналов системы не сохраняются.

Чтобы добавить канал вывода FsOutputChannel в решение,

отредактируйте корневой файл с CMake-командами сборки решения или файл с CMake-командами сборки инициализирующей программы Einit:

CMakeLists.txt

find_package (logrr_fs_output_channel REQUIRED COMPONENTS ENTITY) # Добавление канала вывода FsOutputChannel пишущего в файл create_logrr_fs_output_channel ( APP_LOG_DIR "/log/apps" SYS_LOG_DIR "/log/sys")

Создание IPC-каналов и разрешение взаимодействия программ

Система сборки обеспечивает автоматическое создание IPC-каналов, необходимых для работы системы журналирования, а также генерирует описание политики безопасности в части, которая разрешает взаимодействие между процессами.

Для создания статического подключения к серверу журналирования, вы можете использовать CMake-команду connect_to_logrr_server (ENTITIES <имена_программ_для_подключения>).

В начало
[Topic logrr_component_add]

Получение записей журнала при работе в QEMU

Клиентские библиотеки logrr_clog и logrr_cpp отправляют сообщения в ядру, которое пересылает их в UART-порт. Вы можете перенаправить данные из эмулируемого UART-порта в стандартный поток ввода-вывода, указав флаг -serial stdio при запуске QEMU. При этом сообщения журнала будут отображаться в терминале, в котором запущен QEMU.

Укажите флаги запуска QEMU в значении параметра QEMU_FLAGS, передаваемого команде build_kos_qemu_image():

CMakeLists.txt

build_kos_qemu_image (kos-qemu-image # ... QEMU_FLAGS "-m 4096 -serial stdio" # ... )
В начало
[Topic logrr_component_qemu]

Отправка сообщений в журнал с помощью макросов

Программа LogRR предоставляет макросы для быстрого доступа к функциям журналирования с определенным уровнем.

Пример использования макросов в программе на языке C:

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.");

Для использования этих макросов требуется скомпоновать программу с библиотекой logrr_clog.

Пример использования макросов в программе на языке C++:

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.");

Для использования этих макросов требуется скомпоновать программу с библиотекой logrr_cpp.

См. также

Дополнительные возможности при отправке сообщений в журнал

В начало
[Topic logrr_component_macros]

Дополнительные возможности при отправке сообщений в журнал

В большинстве случаев, для отправки сообщений в журнал достаточно использовать макросы быстрого доступа к функциям журналирования.

В этом разделе описаны дополнительные возможности API библиотеки logrr_cpp: объединение сообщений, отправка сообщений по условию и отложенная отправка.

Объединение сообщений

Чтобы поэтапно получить текст записи журнала из частей и затем отправить запись в журнал одним вызовом:

  1. Скомпонуйте программу с библиотекой logrr_cpp.
  2. Подключите заголовочный файл component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Создайте экземпляр класса LogIface.

    C++

    auto logger = LogIface(logrr::LogLevel::Warning);
  4. Заполните буфер сообщений одним или несколькими вызовами метода LogIface::Push().

    C++

    logger.Push("a={}", a); // ... logger.Push(", b={}", b); // ... logger.Push(", c={}", c);
  5. Отправьте ранее полученные сообщения в журнал с помощью метода LogIface::Flush().

    C++

    logger.Flush();

Отправка сообщения в журнал по условию

Чтобы отправить сообщение в журнал только при выполнении указанного условия:

  1. Скомпонуйте программу с библиотекой logrr_cpp.
  2. Подключите заголовочный файл component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Передайте логическое значение, один из перечислителей LogLevel и текст сообщения в макрос LOG_IF().

    C++

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

Отложенная отправка сообщений в журнал

Макрос LOG_DEFER(), объявленный в заголовочном файле component/logrr/cpp/tools.h, позволяет избежать дублирования кода для журналирования в блоках if...else.

Чтобы отправить предварительно отформатированное сообщение в журнал в момент выхода из функции:

  1. Скомпонуйте программу с библиотекой logrr_cpp.
  2. Подключите заголовочный файл component/logrr/cpp/tools.h.

    C++

    #include <component/logrr/cpp/tools.h>
  3. Добавьте вызов макроса LOG_DEFER() в начало кода функции, изменяющей значения, которые нужно отправить в журнал. В макрос передайте значение LogLevel, строку форматирования сообщения и аргументы для подстановки в строку форматирования.

    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; } }

В этом примере, сообщение отправляется в журнал при вызове деструктора объекта logger на выходе из функции DeferredLoggingExample(). В строку форматирования сообщения подставляются значения a и b, актуальные на момент выхода из функции.

В начало
[Topic logrr_component_additional]

Уровни журналирования

Атрибутом каждого сообщения в системе журналирования является уровень журналирования. Уровень используется при фильтрации сообщений в клиенте и настраивается через сервер.

Critical
Критический сбой в работе программы, после которого продолжение работы программы невозможно.
Error
Ошибка в работе программы, после которой все еще возможно продолжение работы. Этот уровень применяется для журналирования неожиданного завершения текущей операции. Не рекомендуется применять для журналирования ошибочных действий пользователя.
Warning
Проблемная ситуация, возникновение которой предусмотрено, и обрабатывается программой в обычном режиме.
Info (установлен по умолчанию)
Информация о текущем функционировании программы, без дополнительных подробностей. Например, переход в новое окно в пользовательском интерфейсе или успешная запись данных в базу.
Debug
Более подробный уровень журналирования, чем Info. Предоставляет больше деталей о событиях программы и может быть полезен при отладке.
Trace
Самый подробный уровень журналирования, используемый для наиболее детального отслеживания событий программы. При включении может значительно влиять на производительность.

Каждый последующий уровень включает в себя все предыдущие. Например, если сервер настроен на уровень Warning, то в журнал передаются сообщения с уровнями Critical, Error и Warning, а сообщения с уровнями Info, Debug и Trace игнорируются.

Установка уровня журналирования при отправке сообщения программой может осуществляться:

  • использованием макроса с параметром, соответствующем выбранному уровню;
  • передачей значения перечислителя LogrrLogLevel или LogLevel при вызове функций журналирования.
В начало
[Topic logrr_component_loglevels]

API программы LogRR

Библиотеки программы LogRR, предоставляют API для отправки сообщений в журнал через сервер журналирования, а также API для управления работой сервера журналирования.

В этом разделе справки

Библиотека logrr_clog

Библиотека logrr_cpp

В начало
[Topic logrr_api]

Библиотека logrr_clog

Библиотека logrr_clog предоставляет API для отправки сообщений в журнал.

Библиотека logrr_clog предназначена для использования в программах на языке C. В программах на языке C++ используйте библиотеку logrr_cpp.

Чтобы получить доступ к API этой библиотеки,

скомпонуйте вашу программу с библиотекой, используя CMake-команду target_link_libraries().

CMakeLists.txt

target_link_libraries (${TARGET_NAME} ${logrr_clog_LIB})

В этом разделе справки

Функция ClogLog() и макрос CLOG

Перечисляемый тип LogrrLogLevel

В начало
[Topic logrr_api_clog]

Функция ClogLog() и макрос CLOG

Функция ClogLog() выполняет запись в журнал.

Функция ClogLog() предназначена для использования в программах на языке C. В программах на языке C++ используйте функцию Logger::Log() или макросы LOG_*.

Описание функции ClogLog() и макросов для быстрого доступа к ней представлено в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/clog/clog.h.

component/logrr/clog/clog.h (фрагмент)

__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__)

Параметры функции ClogLog():

level
Уровень журналирования LogrrLogLevel.
file
Имя файла.
line
Номер строки в файле.
func
Имя функции.
message
Текст сообщения или строка форматирования текста сообщения.
...
Параметры для подстановки в строку форматирования message.

Макрос быстрого доступа к функции ClogLog()

Вместо вызова функции ClogLog() вы можете использовать макрос, описание которого представлено в файле component/logrr/clog/clog.h. Этот макрос является вариационным (принимает переменное число параметров), что позволяет не указывать все параметры функции ClogLog(). При вызове макроса достаточно указать уровень журналирования и текст сообщения или строку форматирования сообщения со значениями параметров. Используемый уровень журналирования level определяется первым параметром макроса. Пример использования этого макроса представлен в разделе "Отправка сообщений в журнал с помощью макросов".

В начало
[Topic logrr_api_clog_macro]

Перечисляемый тип LogrrLogLevel

Перечисляемый тип LogrrLogLevel содержит поля, имена которых соответствуют уровням журналирования, доступным в программе LogRR.

Перечисляемый тип LogrrLogLevel предназначен для использования в программах на языке C. В программах на языке C++ используйте класс LogLevel.

Перечислители LogrrLogLevel могут передаваться в функцию ClogLog() для отправки сообщения с указанным уровнем.

Описание перечисления LogrrLogLevel представлено в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/core/log_level_c.h.

component/logrr/core/log_level_c.h (фрагмент)

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;
В начало
[Topic logrr_api_logrrloglevel]

Библиотека logrr_cpp

Библиотека logrr_cpp предоставляет API для отправки сообщений в журнал.

Библиотека logrr_cpp предназначена для использования в программах на языке C++. В программах на языке C используйте библиотеку logrr_clog.

Чтобы получить доступ к API этой библиотеки,

скомпонуйте вашу программу с библиотекой, используя CMake-команду target_link_libraries().

CMakeLists.txt

target_link_libraries (${TARGET_NAME} ${logrr_cpp_LIB})

В этом разделе справки

Метод Log() и макрос LOG

Класс LogLevel

Класс LogIface

В начало
[Topic logrr_api_cpp]

Метод Log() и макрос LOG

Метод logrr::Log() выполняет запись в журнал.

Параметры метода:

logLevel
Уровень журналирования LogLevel.
sourceLocation
Объект, определяющий местоположение в исходном коде (имя файла, имя функции, номер строки и номер столбца). В C++20 используется класс std::source_location, в более ранних версиях используется класс std::experimental::source_location.
format
Строка форматирования текста сообщения.
args
Параметры для подстановки в строку форматирования format.

Метод logrr::Log() предназначен для использования в программах на языке C++. В программах на языке C используйте статическую функцию ClogLog() или макрос CLOG.

Описание метода logrr::Log() и макроса быстрого доступа к нему представлены в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/cpp/logger.h.

component/logrr/cpp/logger.h (фрагмент)

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__)

Макрос быстрого доступа к методу Log()

Вместо вызова статического метода Logger::Log() вы можете использовать макрос, описание которого представлено в файле component/logrr/cpp/logger.h. Этот макрос является вариационным (принимает переменное число параметров), что позволяет не указывать все параметры метода Logger::Log(). При вызове макроса достаточно указать только уровень журналирования и строку форматирования сообщения со значениями параметров. Используемый уровень журналирования logLevel определяется первым параметром макроса: Пример использования этого макросов представлен в разделе "Отправка сообщений в журнал с помощью макросов".

В начало
[Topic logrr_api_cpp_log]

Класс LogLevel

Класс LogLevel является перечислением (enum class) и содержит поля, имена которых соответствуют уровням журналирования, доступным в программе LogRR.

Класс LogLevel предназначен для использования в программах на языке C++. В программах на языке C используйте перечисляемый тип LogrrLogLevel.

Значения перечисления LogLevel могут передаваться в:

  • статический метод Log() класса Logger;
  • статические методы ChangeLogLevel() и ChangeGlobalLogLevel() структуры Controller;
  • конструктор класса LogIface;

Описание класса LogLevel представлено в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/core/log_level.h.

component/logrr/core/log_level.h (фрагмент)

enum class LogLevel : int8_t { Critical = 0, Error, Warning, Info, Debug, Trace };
В начало
[Topic logrr_api_cpp_loglevel]

Класс LogIface

Класс LogIface содержит методы, позволяющие поэтапно получить текст записи журнала из частей, и затем отправить запись в журнал одним вызовом:

  • Для установки уровня журналирования отправляемых сообщений используется метод SetLogLevel().
  • Для добавления текста к сообщению используется метод Push().
  • Для отправки составленного одним или несколькими вызовами метода Push() сообщения в журнал используется метод Flush().

    При вызове деструктора ~LogIface() в журнал также отправляется составленное вызовами Push() сообщение, если оно не было ранее отправлено с помощью Flush().

  • Для немедленной отправки отдельного сообщения (без использования составленного вызовами Push() текста) используется метод Log().

Чтобы создать экземпляр класса LogIface, передайте один из перечислителей LogLevel в конструктор класса. Пример использования функций класса LogIface представлен в подразделе "Объединение сообщений" раздела "Дополнительные возможности при отправке сообщений в журнал".

Описание класса LogIface представлено в файле /opt/KasperskyOS-Community-Edition-<version>/sysroot-*-kos/include/component/logrr/cpp/tools.h.

component/logrr/cpp/tools.h (фрагмент)

/** * @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); } } // ... };
В начало
[Topic logrr_api_cpp_logiface]