From 42c89ddd97d8cf2a6d09f496af0a43d597c5ed2c Mon Sep 17 00:00:00 2001 From: ANYKS Date: Fri, 18 Oct 2024 16:26:10 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=B0=D1=82?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=B5=D0=BC=20=D0=BF=D0=B0=D1=80=D1=81=D0=B5?= =?UTF-8?q?=D1=80=20SysLog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- html/download.html | 2 +- include/grok.hpp | 20 +- include/lib.hpp | 2 +- include/syslog.hpp | 56 +- src/csv.cpp | 14 +- src/grok.cpp | 32 +- src/syslog.cpp | 1824 +++++++++++++++++++++++++++++--------------- 7 files changed, 1302 insertions(+), 648 deletions(-) diff --git a/html/download.html b/html/download.html index b8fa025..5e087af 100644 --- a/html/download.html +++ b/html/download.html @@ -78,7 +78,7 @@ ANYKS - formatter -
v1.0.1
+
v1.0.2
diff --git a/include/grok.hpp b/include/grok.hpp index 99375c6..b1de930 100644 --- a/include/grok.hpp +++ b/include/grok.hpp @@ -31,9 +31,9 @@ #include #include #include +#include #include #include -#include /** * Модули AWH @@ -84,9 +84,9 @@ namespace anyks { * Mutex структура рабочих мютексов */ typedef struct Mutex { - mutex cache; // Мютекс контроля кэша - mutex mapping; // Мютекс контроля собранных соответствий - mutex patterns; // Мютекс контроля собранных шаблонов + std::mutex cache; // Мютекс контроля кэша + std::mutex mapping; // Мютекс контроля собранных соответствий + std::mutex patterns; // Мютекс контроля собранных шаблонов } mtx_t; /** * Var Класс работы с переменными @@ -99,7 +99,7 @@ namespace anyks { friend class Grok; private: // Мютекс для блокировки потока - mutex _mtx; + std::mutex _mtx; private: // Список имён переменных vector _names; @@ -157,15 +157,15 @@ namespace anyks { mutable var_t _variables; private: // Список ключей добавленных шаблонов - set _keys; + std::set _keys; private: // Схема соответствий ключей - unordered_map _mapping; + std::unordered_map _mapping; // Список шаблонов для работы - unordered_map _patterns; + std::unordered_map _patterns; private: // Объект кэша работы модуля - map > _cache; + std::map > _cache; private: // Объект фреймворка const fmk_t * _fmk; @@ -250,7 +250,7 @@ namespace anyks { * mapping Метод извлечения карты полученных значений * @return карта полученных значений */ - const unordered_map & mapping() const noexcept; + const std::unordered_map & mapping() const noexcept; public: /** * get Метод извлечения записи по ключу diff --git a/include/lib.hpp b/include/lib.hpp index 9549bd5..4327aad 100644 --- a/include/lib.hpp +++ b/include/lib.hpp @@ -15,7 +15,7 @@ #define __ACU_CONFIG__ // Версия приложения -#define ACU_VERSION "1.0.1" +#define ACU_VERSION "1.0.2" // Короткое название библиотеки #define ACU_SHORT_NAME "ACU" // Название библиотеки diff --git a/include/syslog.hpp b/include/syslog.hpp index 34651e0..f78f843 100644 --- a/include/syslog.hpp +++ b/include/syslog.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ */ #include #include +#include // Объявляем пространство имен using namespace std; @@ -64,6 +66,28 @@ namespace anyks { RFC3164 = 0x01, // Стандарт RFC 3164 RFC5424 = 0x02 // Стандарт RFC 5424 }; + /** + * Поддерживаемые режимы парсинга + */ + enum class mode_t : uint8_t { + NONE = 0x00, // Режим парсинга не установлен + NATIVE = 0x01, // Режим парсинга установлен как нативный + REGEXP = 0x02 // Режим парсинга установлен как регулярные выражения + }; + private: + /** + * RegExp Структура регулярных выражений + */ + typedef struct RegExp { + regexp_t::exp_t mess; // Регулярное выражение для извлечения сообщений для RFC5424 + regexp_t::exp_t items; // Регулярное выражение для извлечения параметров сообщения RFC5424 + regexp_t::exp_t date1; // Регулярное выражение для распознавания формат даты (Sat Jan 8 20:07:41 2011) + regexp_t::exp_t date2; // Регулярное выражение для распознавания формат даты (2024-10-04 13:29:47) + regexp_t::exp_t date3; // Регулярное выражение для распознавания формат даты (2003-10-11T22:14:15.003Z) + regexp_t::exp_t params; // Регулярное выражение для извлечения параметров сообщений RFC5424 + regexp_t::exp_t rfc3164; // Регулярное выражение для парсинга всего сообщения RFC3164 + regexp_t::exp_t rfc5424; // Регулярное выражение для парсинга части сообщения RFC5424 + } exp_t; private: // Поддерживаемый стандарт std_t _std; @@ -72,6 +96,9 @@ namespace anyks { uint8_t _ver; // Приоритет сообщения uint16_t _pri; + private: + // Режим парсинга + mode_t _mode; private: // Название сообщения string _app; @@ -90,9 +117,17 @@ namespace anyks { string _format; // Штамп времени сообщения time_t _timestamp; + private: + // Объект собранных регулярных выражений + exp_t _exp; + // Объект работы с регулярными выражениями + regexp_t _reg; + private: + // Мютекс для блокировки потока + std::recursive_mutex _mtx; private: // Список структурированных данных - unordered_map > _sd; + std::unordered_map > _sd; private: // Объект фреймворка const fmk_t * _fmk; @@ -140,13 +175,13 @@ namespace anyks { * @param id идентификатор структурированных данных * @return список структурированных данных */ - const unordered_map & sd(const string & id) const noexcept; + const std::unordered_map & sd(const string & id) const noexcept; /** * sd Метод установки структурированных данных * @param id идентификатор структурированных данных * @param sd список структурированных данных */ - void sd(const string & id, const unordered_map & sd) noexcept; + void sd(const string & id, const std::unordered_map & sd) noexcept; public: /** * std Метод получения стандарта сообщения @@ -277,6 +312,17 @@ namespace anyks { * @param dump данные в формате JSON */ void dump(const json & dump) noexcept; + public: + /** + * mode Метод получения установленного режима парсинга + * @return установленный режим парсинга + */ + mode_t mode() const noexcept; + /** + * mode Метод установки режима парсинга + * @param mode режим парсинга для установки + */ + void mode(const mode_t mode) noexcept; public: /** * Оператор вывода данные контейнера в качестве строки @@ -315,9 +361,7 @@ namespace anyks { * @param fmk объект фреймворка * @param log объект для работы с логами */ - SysLog(const fmk_t * fmk, const log_t * log) noexcept : - _std(std_t::AUTO), _ver(1), _pri(0), _app{"-"}, _host{"-"}, _pid(0), - _mid{"-"}, _message{""}, _format{FORMAT}, _timestamp(0), _fmk(fmk), _log(log) {} + SysLog(const fmk_t * fmk, const log_t * log) noexcept; } syslog_t; /** * Оператор [>>] чтения из потока SysLog контейнера diff --git a/src/csv.cpp b/src/csv.cpp index fb229b6..3bdaa63 100644 --- a/src/csv.cpp +++ b/src/csv.cpp @@ -495,11 +495,11 @@ json anyks::CSV::dump() const noexcept { // Добавляем полученное значение в массив result[key].push_back(::stod(item)); // Если число является булевым истинным значением - else if(item.compare("true") == 0) + else if(this->_fmk->compare("true", item)) // Добавляем полученное значение в массив result[key].push_back(true); // Если число является булевым ложным значением - else if(item.compare("false") == 0) + else if(this->_fmk->compare("false", item)) // Добавляем полученное значение в массив result[key].push_back(false); // Добавляем полученное значение в массив @@ -520,9 +520,7 @@ json anyks::CSV::dump() const noexcept { // Выполняем перебор всего списка строк for(auto j = 0; j < this->_mapping.at(i).size(); j++){ // Получаем строку значения - const string item = this->_mapping.at(i).at(j); - // Выполняем приведение строки к нижнему регистру - this->_fmk->transform(item, fmk_t::transform_t::LOWER); + const string & item = this->_mapping.at(i).at(j); // Если запись является числом if(this->_fmk->is(item, fmk_t::check_t::NUMBER)){ // Получаем переданное число @@ -538,15 +536,15 @@ json anyks::CSV::dump() const noexcept { // Добавляем полученное значение в массив result.back().push_back(::stod(item)); // Если число является булевым истинным значением - else if(item.compare("true") == 0) + else if(this->_fmk->compare("true", item)) // Добавляем полученное значение в массив result.back().push_back(true); // Если число является булевым ложным значением - else if(item.compare("false") == 0) + else if(this->_fmk->compare("false", item)) // Добавляем полученное значение в массив result.back().push_back(false); // Добавляем полученное значение в массив - else result.back().push_back(this->_mapping.at(i).at(j)); + else result.back().push_back(item); } } } diff --git a/src/grok.cpp b/src/grok.cpp index c42ae0a..f6e12dc 100644 --- a/src/grok.cpp +++ b/src/grok.cpp @@ -20,7 +20,7 @@ */ void anyks::Grok::Var::reset() noexcept { // Выполняем блокировку потока - const lock_guard lock(this->_mtx); + const lock_guard lock(this->_mtx); // Выполняем удаление названий переменных this->_names.clear(); // Выполняем очистку шаблонов переменных @@ -56,7 +56,7 @@ string anyks::Grok::Var::get(const string & text, const uint8_t index) noexcept // Получаем строку текста для поиска const char * str = text.c_str(); // Создаём объект матчинга - unique_ptr match(new regmatch_t [i->second.re_nsub + 1]); + std::unique_ptr match(new regmatch_t [i->second.re_nsub + 1]); // Выполняем разбор регулярного выражения if(pcre2_regexec(&i->second, str, i->second.re_nsub + 1, match.get(), REG_NOTEMPTY) == 0){ // Название полученной переменной @@ -104,7 +104,7 @@ void anyks::Grok::Var::push(const string & name, const string & pattern) noexcep // Если название переменной и шаблон регулярного выражения переданы if(!name.empty() && !pattern.empty()){ // Выполняем блокировку потока - const lock_guard lock(this->_mtx); + const lock_guard lock(this->_mtx); // Добавляем название переменной this->_names.push_back(name); // Добавляем шаблон регулярного выражения @@ -142,7 +142,7 @@ void anyks::Grok::Var::push(const string & name, const string & pattern) noexcep */ void anyks::Grok::init() noexcept { // Выполняем блокировку потока - const lock_guard lock(this->_mtx.patterns); + const lock_guard lock(this->_mtx.patterns); // Если список шаблонов не собран if(this->_patterns.empty()){ // Выполняем добавление базовых шаблонов @@ -218,7 +218,7 @@ void anyks::Grok::clear() noexcept { // Выполняем сброс собранных данных this->reset(); // Выполняем блокировку потока - const lock_guard lock(this->_mtx.patterns); + const lock_guard lock(this->_mtx.patterns); // Выполняем удаление списка ключей this->_keys.clear(); // Очищаем список шаблонов @@ -229,7 +229,7 @@ void anyks::Grok::clear() noexcept { */ void anyks::Grok::reset() noexcept { // Выполняем блокировку потока - const lock_guard lock(this->_mtx.mapping); + const lock_guard lock(this->_mtx.mapping); // Очищаем схему соответствий ключей this->_mapping.clear(); // Выполняем сброс параметров переменной @@ -242,7 +242,7 @@ void anyks::Grok::clearPatterns() noexcept { // Если список ключей существует if(!this->_keys.empty()){ // Выполняем блокировку потока - const lock_guard lock(this->_mtx.patterns); + const lock_guard lock(this->_mtx.patterns); // Выполняем перебор списка ключей for(auto i = this->_keys.begin(); i != this->_keys.end();){ // Выполняем удаление шаблона @@ -261,7 +261,7 @@ void anyks::Grok::pattern(const string & key, const string & val) noexcept { // Если параметры шаблона переданы if(!key.empty() && !val.empty()){ // Выполняем блокировку потока - const lock_guard lock(this->_mtx.patterns); + const lock_guard lock(this->_mtx.patterns); // Выполняем добавление шаблона this->_keys.emplace(key); // Выполняем добавление шаблона @@ -357,7 +357,7 @@ uint64_t anyks::Grok::build(string & text, const bool pure, const bool init, con // Получаем строку текста для поиска const char * str = text.c_str(); // Создаём объект матчинга - unique_ptr match(new regmatch_t [this->_reg1.re_nsub + 1]); + std::unique_ptr match(new regmatch_t [this->_reg1.re_nsub + 1]); // Если возникла ошибка if(pcre2_regexec(&this->_reg1, str, this->_reg1.re_nsub + 1, match.get(), REG_NOTEMPTY) > 0) // Выходим из цикла корректировки @@ -384,7 +384,7 @@ uint64_t anyks::Grok::build(string & text, const bool pure, const bool init, con // Получаем строку текста для поиска const char * str = text.c_str(); // Создаём объект матчинга - unique_ptr match(new regmatch_t [this->_reg2.re_nsub + 1]); + std::unique_ptr match(new regmatch_t [this->_reg2.re_nsub + 1]); // Если возникла ошибка if(pcre2_regexec(&this->_reg2, str, this->_reg2.re_nsub + 1, match.get(), REG_NOTEMPTY) > 0) // Выходим из цикла корректировки @@ -484,7 +484,7 @@ uint64_t anyks::Grok::build(string & text, const bool pure, const bool init, con // Выполняем блокировку потока this->_mtx.cache.lock(); // Выполняем создании записи кэша - auto ret = const_cast (this)->_cache.emplace(cid, unique_ptr (new cache_t)); + auto ret = const_cast (this)->_cache.emplace(cid, std::unique_ptr (new cache_t)); // Выполняем разблокировку потока this->_mtx.cache.unlock(); // Выполняем установку регулярного выражения @@ -627,7 +627,7 @@ bool anyks::Grok::parse(const string & text, const uint64_t cid) noexcept { // Получаем строку текста для поиска const char * str = text.c_str(); // Создаём объект матчинга - unique_ptr match(new regmatch_t [i->second->reg.re_nsub + 1]); + std::unique_ptr match(new regmatch_t [i->second->reg.re_nsub + 1]); // Выполняем разбор регулярного выражения const int error = pcre2_regexec(&i->second->reg, str, i->second->reg.re_nsub + 1, match.get(), REG_NOTEMPTY); // Если ошибок не получено @@ -647,7 +647,7 @@ bool anyks::Grok::parse(const string & text, const uint64_t cid) noexcept { // Если название переменной получено if(!key.empty()){ // Выполняем блокировку потока - const lock_guard lock(this->_mtx.mapping); + const lock_guard lock(this->_mtx.mapping); // Выполняем добавления полученных данных в схему соответствий this->_mapping.emplace(key, value); } @@ -726,7 +726,7 @@ bool anyks::Grok::parse(const string & text, const string & rule) noexcept { // Получаем строку текста для поиска const char * str = text.c_str(); // Создаём объект матчинга - unique_ptr match(new regmatch_t [reg.re_nsub + 1]); + std::unique_ptr match(new regmatch_t [reg.re_nsub + 1]); // Выполняем разбор регулярного выражения const int error = pcre2_regexec(®, str, reg.re_nsub + 1, match.get(), REG_NOTEMPTY); // Если ошибок не получено @@ -746,7 +746,7 @@ bool anyks::Grok::parse(const string & text, const string & rule) noexcept { // Если название переменной получено if(!key.empty()){ // Выполняем блокировку потока - const lock_guard lock(this->_mtx.mapping); + const lock_guard lock(this->_mtx.mapping); // Выполняем добавления полученных данных в схему соответствий this->_mapping.emplace(key, value); } @@ -812,7 +812,7 @@ json anyks::Grok::dump() const noexcept { * mapping Метод извлечения карты полученных значений * @return карта полученных значений */ -const unordered_map & anyks::Grok::mapping() const noexcept { +const std::unordered_map & anyks::Grok::mapping() const noexcept { // Выводим список полученных значений return this->_mapping; } diff --git a/src/syslog.cpp b/src/syslog.cpp index 14346cb..ed4c44c 100644 --- a/src/syslog.cpp +++ b/src/syslog.cpp @@ -18,8 +18,10 @@ * clear Метод очистки данных */ void anyks::SysLog::clear() noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Устанавливаем версию сообщения - this->_ver = 1; + this->_ver = 0; // Устанавливаем приоритет сообщения this->_pri = 0; // Устанавливаем идентификатор процесса @@ -45,355 +47,747 @@ void anyks::SysLog::clear() noexcept { void anyks::SysLog::parse(const string & syslog, const std_t std) noexcept { // Если даныне переданы if(!syslog.empty()){ - // Идентификатор структурированных данных - string sid = ""; - // Позиция начала строки - size_t pos = 0; - // Статус поиска - uint8_t status = 0; - // Количество пробелов в штампе времени - uint8_t spaces = 0; - // Выполняем перебор всех символов - for(size_t i = 0; i < syslog.length(); i++){ - // Если мы получили первый символ - if(i == 0){ - // Если первый символ не является экранирование приоритета - if(syslog.front() != '<'){ - // Увеличиваем значение статуса - status += 2; - // Если установлен стандарт как автоматический - if(std == std_t::AUTO){ - // Если символ является числом - if(this->_fmk->is(string(1, syslog.front()), fmk_t::check_t::NUMBER)) - // Устанавливаем стандарт RFC5424 - (* const_cast (&std)) = std_t::RFC5424; - // Устанавливаем стандарт RFC3164 - else (* const_cast (&std)) = std_t::RFC3164; - // Устанавливаем стандарт - this->_std = std; - } - // Выполняем смещение позиции поиска - } else pos = (i + 1); - // Если это не первый символ - } else { - // Если статус поиска установлен как поиск приоритета или версии сообщения - if((status == 0) || (status == 1)){ - // Определяем статус парсинга - switch(status){ - // Если производится сбор приоритета - case 0: { - // Если обнаружен экранирующий символ приоритета - if(syslog.at(i) == '>'){ - // Извлекаем значение приоритета - this->_pri = static_cast (::stoi(syslog.substr(pos, i - pos))); - // Запоминаем начало строки с версией - pos = (i + 1); + /** + * Выполняем отлов ошибок + */ + try { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); + // Определяем активированный режим парсинга + switch(static_cast (this->_mode)){ + // Если активирован нативный режим парсинга + case static_cast (mode_t::NATIVE): { + // Идентификатор структурированных данных + string sid = ""; + // Позиция начала строки + size_t pos = 0; + // Статус поиска + uint8_t status = 0; + // Количество пробелов в штампе времени + uint8_t spaces = 0; + // Устанавливаем стандарт + this->_std = std; + // Выполняем перебор всех символов + for(size_t i = 0; i < syslog.length(); i++){ + // Если мы получили первый символ + if(i == 0){ + // Если первый символ не является экранирование приоритета + if(syslog.front() != '<'){ // Увеличиваем значение статуса - status++; - // Если следующие символы существуют - if((std == std_t::AUTO) && (pos < syslog.length())){ - // Если следующий символ является числом - if(this->_fmk->is(string(1, syslog.at(pos)), fmk_t::check_t::NUMBER)) + status += 2; + // Если установлен стандарт как автоматический + if(std == std_t::AUTO){ + // Если символ является числом + if(this->_fmk->is(string(1, syslog.front()), fmk_t::check_t::NUMBER)) // Устанавливаем стандарт RFC5424 (* const_cast (&std)) = std_t::RFC5424; - // Если версия не указана - else { - // Увеличиваем значение статуса - status++; - // Устанавливаем стандарт RFC3164 - (* const_cast (&std)) = std_t::RFC3164; - } + // Устанавливаем стандарт RFC3164 + else (* const_cast (&std)) = std_t::RFC3164; // Устанавливаем стандарт this->_std = std; } - } - } break; - // Если производится сбор версии - case 1: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Получаем версию сообщения - this->_ver = static_cast (::stoi(syslog.substr(pos, i - pos))); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - } - // Если статус поиска производится другой - } else { - // Определяем тип стандарта - switch(static_cast (std)){ - // Если установлен стандарт RFC3164 - case static_cast (std_t::RFC3164): { - // Определяем статус парсинга - switch(status){ - // Если производится сбор даты - case 2: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Если пробелов получено меньше двух - if(spaces < 2) - // Увеличиваем количество пробелов - spaces++; - // Иначе мы получили дату - else { - // Получаем текущее значение даты - const time_t timestamp = time(nullptr); - // Создаем структуру времени - std::tm * tm = ::localtime(×tamp); - // Получаем значение даты - string date = syslog.substr(pos, i - pos); - // Выполняем поиск пробела в дате - const size_t space = date.rfind(' '); - // Если позиция пробела в дате найдена - if(space != string::npos){ - // Выполняем вставку в строку года - date.replace(space, 1, " " + std::to_string(1900 + tm->tm_year) + " "); - // Устанавливаем дату сообщения - this->date(date, "%b %d %Y %H:%M:%S"); - } + // Выполняем смещение позиции поиска + } else pos = (i + 1); + // Если это не первый символ + } else { + // Если статус поиска установлен как поиск приоритета или версии сообщения + if((status == 0) || (status == 1)){ + // Определяем статус парсинга + switch(status){ + // Если производится сбор приоритета + case 0: { + // Если обнаружен экранирующий символ приоритета + if(syslog.at(i) == '>'){ + // Извлекаем значение приоритета + this->_pri = static_cast (::stoi(syslog.substr(pos, i - pos))); // Запоминаем начало строки с версией pos = (i + 1); // Увеличиваем значение статуса status++; - } - // Если мы перебрали все оставшиеся символы - } else if(i == (syslog.length() - 1)) - // Устанавливаем полученное сообщение - this->_message = syslog.substr(pos); - } break; - // Если производится сбор хоста сообщения - case 3: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Устанавливаем хост сообщения - this->_host = syslog.substr(pos, i - pos); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - // Если мы перебрали все оставшиеся символы - } else if(i == (syslog.length() - 1)) - // Устанавливаем полученное сообщение - this->_message = syslog.substr(pos); - } break; - // Если производится сбор названия приложения сообщения - case 4: { - // Если установлен разделитель тега - if(syslog.at(i) == ':'){ - // Устанавливаем название сообщения - this->_app = syslog.substr(pos, i - pos); - { - // Выполняем поиск идентификатора процесса - const size_t pos = this->_app.find('['); - // Если экранирование процесса найдено - if(pos != string::npos){ - // Устанавливаем название сообщения - const string & pid = this->_app.substr(pos + 1, this->_app.length() - (pos + 2)); - // Выполняем установку идентификатора процесса - if(this->_fmk->is(pid, fmk_t::check_t::NUMBER)) - // Выполняем получение идентификатора процесса - this->_pid = static_cast (::stoi(pid)); - // Устанавливаем идентификатор процесса по умолчанию - else this->_pid = 0; - // Удаляем лишние символы - this->_app.replace(pos, this->_app.length() - pos, ""); + // Если следующие символы существуют + if((std == std_t::AUTO) && (pos < syslog.length())){ + // Если следующий символ является числом + if(this->_fmk->is(string(1, syslog.at(pos)), fmk_t::check_t::NUMBER)) + // Устанавливаем стандарт RFC5424 + (* const_cast (&std)) = std_t::RFC5424; + // Если версия не указана + else { + // Увеличиваем значение статуса + status++; + // Устанавливаем стандарт RFC3164 + (* const_cast (&std)) = std_t::RFC3164; + } + // Устанавливаем стандарт + this->_std = std; + // Если версия протокола соответствует RFC3164 + } else if(std == std_t::RFC3164) + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор версии + case 1: { + // Если версия протокола соответствует RFC5424 + if(std == std_t::RFC5424){ + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Получаем версию сообщения + this->_ver = static_cast (::stoi(syslog.substr(pos, i - pos))); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + // Выводим сообщение, что стандарты перепутаны + } else this->_log->print("SysLog standards are mixed up", log_t::flag_t::CRITICAL); + } break; + } + // Если статус поиска производится другой + } else { + // Определяем тип стандарта + switch(static_cast (std)){ + // Если установлен стандарт RFC3164 + case static_cast (std_t::RFC3164): { + // Определяем статус парсинга + switch(status){ + // Если производится сбор даты + case 2: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Если пробелов получено меньше двух + if(spaces < 2) + // Увеличиваем количество пробелов + spaces++; + // Иначе мы получили дату + else { + // Получаем текущее значение даты + const time_t timestamp = time(nullptr); + // Создаем структуру времени + std::tm * tm = ::localtime(×tamp); + // Получаем значение даты + string date = syslog.substr(pos, i - pos); + // Выполняем поиск пробела в дате + const size_t space = date.rfind(' '); + // Если позиция пробела в дате найдена + if(space != string::npos){ + // Выполняем вставку в строку года + date.replace(space, 1, " " + std::to_string(1900 + tm->tm_year) + " "); + // Устанавливаем дату сообщения + this->date(date, "%b %d %Y %H:%M:%S"); + } + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + // Если мы перебрали все оставшиеся символы + } else if(i == (syslog.length() - 1)) + // Устанавливаем полученное сообщение + this->_message = syslog.substr(pos); + } break; + // Если производится сбор хоста сообщения + case 3: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем хост сообщения + this->_host = syslog.substr(pos, i - pos); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + // Если мы перебрали все оставшиеся символы + } else if(i == (syslog.length() - 1)) + // Устанавливаем полученное сообщение + this->_message = syslog.substr(pos); + } break; + // Если производится сбор названия приложения сообщения + case 4: { + // Если установлен разделитель тега + if(syslog.at(i) == ':'){ + // Устанавливаем название сообщения + this->_app = syslog.substr(pos, i - pos); + { + // Выполняем поиск идентификатора процесса + const size_t pos = this->_app.find('['); + // Если экранирование процесса найдено + if(pos != string::npos){ + // Устанавливаем название сообщения + const string & pid = this->_app.substr(pos + 1, this->_app.length() - (pos + 2)); + // Выполняем установку идентификатора процесса + if(this->_fmk->is(pid, fmk_t::check_t::NUMBER)) + // Выполняем получение идентификатора процесса + this->_pid = static_cast (::stoi(pid)); + // Устанавливаем идентификатор процесса по умолчанию + else this->_pid = 0; + // Удаляем лишние символы + this->_app.replace(pos, this->_app.length() - pos, ""); + } + } + // Увеличиваем значение статуса + status++; + // Запоминаем начало строки с версией + pos = (i + 2); + // Если установлен пробел + } else if(syslog.at(i) == ' ') + // Увеличиваем значение статуса + status++; + // Если мы перебрали все оставшиеся символы + else if(i == (syslog.length() - 1)) + // Устанавливаем полученное сообщение + this->_message = syslog.substr(pos); + } break; + // Если производится сбор сообщения + case 5: { + // Устанавливаем полученное сообщение + this->_message = syslog.substr(pos); + // Выходим из цикла + return; } } - // Увеличиваем значение статуса - status++; - // Запоминаем начало строки с версией - pos = (i + 2); - // Если установлен пробел - } else if(syslog.at(i) == ' ') - // Увеличиваем значение статуса - status++; - // Если мы перебрали все оставшиеся символы - else if(i == (syslog.length() - 1)) - // Устанавливаем полученное сообщение - this->_message = syslog.substr(pos); - } break; - // Если производится сбор сообщения - case 5: { - // Устанавливаем полученное сообщение - this->_message = syslog.substr(pos); - // Выходим из цикла - return; + } break; + // Если установлен стандарт RFC5424 + case static_cast (std_t::RFC5424): { + // Определяем статус парсинга + switch(status){ + // Если производится сбор даты сообщения + case 2: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем дату сообщения + this->date(syslog.substr(pos, i - pos), "%Y-%m-%dT%H:%M:%S"); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор хоста сообщения + case 3: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем хост сообщения + this->_host = syslog.substr(pos, i - pos); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор названия приложения сообщения + case 4: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем название сообщения + this->_app = syslog.substr(pos, i - pos); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор идентификатора процесса приславшего сообщения + case 5: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем название сообщения + const string & pid = syslog.substr(pos, i - pos); + // Если идентификатор процесса не установлен + if(pid.compare("-") == 0) + // Устанавливаем идентификатор процесса по умолчанию + this->_pid = 0; + // Выполняем установку идентификатора процесса + else if(this->_fmk->is(pid, fmk_t::check_t::NUMBER)) + // Устанавливаем идентификатор процесса + this->_pid = static_cast (::stoi(pid)); + // Устанавливаем идентификатор процесса по умолчанию + else this->_pid = 0; + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор идентификатора сообщения + case 6: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Устанавливаем идентификатор сообщения + this->_mid = syslog.substr(pos, i - pos); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор списка структурированных данных + case 7: { + // Если установлен пробел + if(syslog.at(i) == '['){ + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + // Если структурированные данные не установлены + } else if((syslog.at(i) == '-') || (syslog.at(i) == ' ')) { + // Запоминаем начало строки с версией + pos = (i + (syslog.at(i) == '-' ? 2 : 1)); + // Увеличиваем значение статуса + status = 10; + } + } break; + // Если производится сбор идентификатора структурированных данных + case 8: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Получаем идентификатор структурированных данных + sid = syslog.substr(pos, i - pos); + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status++; + } + } break; + // Если производится сбор параметров структурированных данных + case 9: { + // Если установлен пробел + if(syslog.at(i) == ' '){ + // Получаем строку параметров + const string & param = syslog.substr(pos, i - pos); + // Выполняем поиск разделителя + const size_t sep = param.find("="); + // Если разделитель найден + if(sep != string::npos){ + // Получаем ключ + string key = param.substr(0, sep); + // Получаем значение + string val = param.substr(sep + 1); + // Выполняем удаление кавычек + val.assign(val.begin() + 1, val.end() - 1); + // Получаем идентификатор структурированных данных + auto i = this->_sd.find(sid); + // Если идентификатор существует + if(i != this->_sd.end()) + // Устанавливаем структурированные данные + i->second.emplace(std::move(key), std::move(val)); + // Иначе добавляем новые структурированные данные + else this->_sd.emplace(sid, std::unordered_map {{std::move(key), std::move(val)}}); + } + // Запоминаем начало строки с версией + pos = (i + 1); + // Если установлен символ завершения сбора структурированных данных + } else if(syslog.at(i) == ']') { + // Получаем строку параметров + const string & param = syslog.substr(pos, i - pos); + // Выполняем поиск разделителя + const size_t sep = param.find("="); + // Если разделитель найден + if(sep != string::npos){ + // Получаем ключ + string key = param.substr(0, sep); + // Получаем значение + string val = param.substr(sep + 1); + // Выполняем удаление кавычек + val.assign(val.begin() + 1, val.end() - 1); + // Получаем идентификатор структурированных данных + auto i = this->_sd.find(sid); + // Если идентификатор существует + if(i != this->_sd.end()) + // Устанавливаем структурированные данные + i->second.emplace(std::move(key), std::move(val)); + // Иначе добавляем новые структурированные данные + else this->_sd.emplace(sid, std::unordered_map {{std::move(key), std::move(val)}}); + } + // Запоминаем начало строки с версией + pos = (i + 1); + // Увеличиваем значение статуса + status = 7; + } + } break; + // Если производится сбор сообщения + case 10: { + // Устанавливаем полученное сообщение + this->_message = syslog.substr(pos); + // Выходим из цикла + return; + } + } + } break; } } - } break; - // Если установлен стандарт RFC5424 - case static_cast (std_t::RFC5424): { - // Определяем статус парсинга - switch(status){ - // Если производится сбор даты сообщения - case 2: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Устанавливаем дату сообщения - this->date(syslog.substr(pos, i - pos), "%Y-%m-%dT%H:%M:%S"); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор хоста сообщения - case 3: { - // Если установлен пробел - if(syslog.at(i) == ' '){ + } + } + } break; + // Если активирован режим парсинга регулярными выражениями + case static_cast (mode_t::REGEXP): { + // Выполняем парсинг полученного сообщения + auto result = this->_reg.exec(syslog, this->_exp.rfc3164); + // Если результат получен, значит сообщение соответствует стандарту RFC3164 + if(!result.empty() && (result.size() > 1)){ + // Если стандарт установлен как 3164 + if(std == std_t::RFC5424) + // Выводим сообщение об ошибке + this->_log->print("SysLog parse: %s", log_t::flag_t::WARNING, "text does not comply with RFC5424 SysLog standard"); + // Устанавливаем стандарт + this->_std = std_t::RFC3164; + // Выполняем перебор всего всех полученных параметров + for(size_t i = 1; i < result.size(); i++){ + // Выполняем получение значения + const string & item = result.at(i); + // Если значение получено + if(!item.empty()){ + // Определяем номер элемента + switch(i){ + // Если мы получили приоритетное значение + case 1: + // Извлекаем значение приоритета + this->_pri = static_cast (::stoi(item)); + break; + // Если мы получили значение даты + case 2: { + // Выполняем парсинг даты + const auto & date = this->_reg.exec(item, this->_exp.date1); + // Если формат даты детектирован + if(!date.empty() && (date.size() > 1)){ + // Сформированный формат даты + string format = ""; + // Выполняем перебор всех параметров даты + for(size_t j = 1; j < date.size(); j++){ + // Если дата получена + if(!date.at(j).empty()){ + // Определяем тип полученных данных + switch(j){ + // Если мы получили день недели + case 1: + // Выполняем формирование формата даты + format = "%a"; + break; + // Если мы получили месяц + case 2: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%b"); + } break; + // Если мы получили день недели + case 3: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%d"); + } break; + // Если мы получили время + case 4: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%H:%M:%S"); + } break; + // Если мы получили год + case 5: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%Y"); + } break; + } + // Если мы получили год но он пустой + } else if(j == 5) { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%Y"); + // Получаем текущее значение даты + const time_t timestamp = ::time(nullptr); + // Создаем структуру времени + std::tm * tm = ::localtime(×tamp); + // Выполняем добавление разделителя + const_cast (item).append(1, ' '); + // Выполняем добавление текущего года + const_cast (item).append(std::to_string(1900 + tm->tm_year)); + } + } + // Устанавливаем дату сообщения + this->date(item, format); + // Если парсинг даты не выполнен + } else { + // Если формат даты детектирован + if(this->_reg.test(item, this->_exp.date2)) + // Устанавливаем дату сообщения + this->date(item, "%Y-%m-%d %H:%M:%S"); + // Если парсинг даты не выполнен + else { + // Если формат даты детектирован + if(this->_reg.test(item, this->_exp.date3)) + // Устанавливаем дату сообщения + this->date(item, "%Y-%m-%dT%H:%M:%S"); + // Если парсинг даты не выполнен + else this->_log->print("SysLog parse: %s", log_t::flag_t::WARNING, "date format is not defined"); + } + } + } break; + // Если мы получили хост машины + case 3: // Устанавливаем хост сообщения - this->_host = syslog.substr(pos, i - pos); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор названия приложения сообщения - case 4: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Устанавливаем название сообщения - this->_app = syslog.substr(pos, i - pos); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор идентификатора процесса приславшего сообщения - case 5: { - // Если установлен пробел - if(syslog.at(i) == ' '){ + this->_host = item; + break; + // Если мы получили название приложения + case 4: // Устанавливаем название сообщения - const string & pid = syslog.substr(pos, i - pos); - // Если идентификатор процесса не установлен - if(pid.compare("-") == 0) - // Устанавливаем идентификатор процесса по умолчанию - this->_pid = 0; + this->_app = item; + break; + // Если мы получили идентификатор процесса + case 5: { // Выполняем установку идентификатора процесса - else if(this->_fmk->is(pid, fmk_t::check_t::NUMBER)) - // Устанавливаем идентификатор процесса - this->_pid = static_cast (::stoi(pid)); + if(this->_fmk->is(item, fmk_t::check_t::NUMBER)) + // Выполняем получение идентификатора процесса + this->_pid = static_cast (::stoi(item)); // Устанавливаем идентификатор процесса по умолчанию else this->_pid = 0; - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор идентификатора сообщения - case 6: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Устанавливаем идентификатор сообщения - this->_mid = syslog.substr(pos, i - pos); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор списка структурированных данных - case 7: { - // Если установлен пробел - if(syslog.at(i) == '['){ - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - // Если структурированные данные не установлены - } else if((syslog.at(i) == '-') || (syslog.at(i) == ' ')) { - // Запоминаем начало строки с версией - pos = (i + (syslog.at(i) == '-' ? 2 : 1)); - // Увеличиваем значение статуса - status = 10; - } - } break; - // Если производится сбор идентификатора структурированных данных - case 8: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Получаем идентификатор структурированных данных - sid = syslog.substr(pos, i - pos); - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status++; - } - } break; - // Если производится сбор параметров структурированных данных - case 9: { - // Если установлен пробел - if(syslog.at(i) == ' '){ - // Получаем строку параметров - const string & param = syslog.substr(pos, i - pos); - // Выполняем поиск разделителя - const size_t sep = param.find("="); - // Если разделитель найден - if(sep != string::npos){ - // Получаем ключ - string key = param.substr(0, sep); - // Получаем значение - string val = param.substr(sep + 1); - // Выполняем удаление кавычек - val.assign(val.begin() + 1, val.end() - 1); - // Получаем идентификатор структурированных данных - auto i = this->_sd.find(sid); - // Если идентификатор существует - if(i != this->_sd.end()) - // Устанавливаем структурированные данные - i->second.emplace(std::move(key), std::move(val)); - // Иначе добавляем новые структурированные данные - else this->_sd.emplace(sid, unordered_map {{std::move(key), std::move(val)}}); - } - // Запоминаем начало строки с версией - pos = (i + 1); - // Если установлен символ завершения сбора структурированных данных - } else if(syslog.at(i) == ']') { - // Получаем строку параметров - const string & param = syslog.substr(pos, i - pos); - // Выполняем поиск разделителя - const size_t sep = param.find("="); - // Если разделитель найден - if(sep != string::npos){ - // Получаем ключ - string key = param.substr(0, sep); - // Получаем значение - string val = param.substr(sep + 1); - // Выполняем удаление кавычек - val.assign(val.begin() + 1, val.end() - 1); - // Получаем идентификатор структурированных данных - auto i = this->_sd.find(sid); - // Если идентификатор существует - if(i != this->_sd.end()) - // Устанавливаем структурированные данные - i->second.emplace(std::move(key), std::move(val)); - // Иначе добавляем новые структурированные данные - else this->_sd.emplace(sid, unordered_map {{std::move(key), std::move(val)}}); - } - // Запоминаем начало строки с версией - pos = (i + 1); - // Увеличиваем значение статуса - status = 7; + } break; + // Если мы получили текст сообщения + case 6: + // Устанавливаем полученное сообщение + this->_message = item; + break; + } + } + } + // Если результат не получен + } else { + // Если стандарт установлен как 3164 + if(std == std_t::RFC3164) + // Выводим сообщение об ошибке + this->_log->print("SysLog parse: %s", log_t::flag_t::WARNING, "text does not comply with RFC3164 SysLog standard"); + // Выполняем парсинг полученного сообщения + result = this->_reg.exec(syslog, this->_exp.rfc5424); + // Если результат получен, значит сообщение соответствует стандарту RFC5424 + if(!result.empty() && (result.size() > 1)){ + // Устанавливаем стандарт + this->_std = std_t::RFC5424; + // Выполняем перебор всего всех полученных параметров + for(size_t i = 1; i < result.size(); i++){ + // Выполняем получение значения + const string & item = result.at(i); + // Если значение получено + if(!item.empty()){ + // Определяем номер элемента + switch(i){ + // Если мы получили приоритетное значение + case 1: + // Извлекаем значение приоритета + this->_pri = static_cast (::stoi(item)); + break; + // Если мы получили версию сообщения + case 2: + // Получаем версию сообщения + this->_ver = static_cast (::stoi(item)); + break; + // Если мы получили значение даты + case 3: { + // Выполняем парсинг даты + const auto & date = this->_reg.exec(item, this->_exp.date1); + // Если формат даты детектирован + if(!date.empty() && (date.size() > 1)){ + // Сформированный формат даты + string format = ""; + // Выполняем перебор всех параметров даты + for(size_t j = 1; j < date.size(); j++){ + // Если дата получена + if(!date.at(j).empty()){ + // Определяем тип полученных данных + switch(j){ + // Если мы получили день недели + case 1: + // Выполняем формирование формата даты + format = "%a"; + break; + // Если мы получили месяц + case 2: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%b"); + } break; + // Если мы получили день недели + case 3: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%d"); + } break; + // Если мы получили время + case 4: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%H:%M:%S"); + } break; + // Если мы получили год + case 5: { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%Y"); + } break; + } + // Если мы получили год но он пустой + } else if(j == 5) { + // Если формат уже сформирован + if(!format.empty()) + // Выполняем добавление разделителя + format.append(1, ' '); + // Выполняем добавление месяца + format.append("%Y"); + // Получаем текущее значение даты + const time_t timestamp = ::time(nullptr); + // Создаем структуру времени + std::tm * tm = ::localtime(×tamp); + // Выполняем добавление разделителя + const_cast (item).append(1, ' '); + // Выполняем добавление текущего года + const_cast (item).append(std::to_string(1900 + tm->tm_year)); + } + } + // Устанавливаем дату сообщения + this->date(item, format); + // Если парсинг даты не выполнен + } else { + // Если формат даты детектирован + if(this->_reg.test(item, this->_exp.date2)) + // Устанавливаем дату сообщения + this->date(item, "%Y-%m-%d %H:%M:%S"); + // Если парсинг даты не выполнен + else { + // Если формат даты детектирован + if(this->_reg.test(item, this->_exp.date3)) + // Устанавливаем дату сообщения + this->date(item, "%Y-%m-%dT%H:%M:%S"); + // Если парсинг даты не выполнен + else this->_log->print("SysLog parse: %s", log_t::flag_t::WARNING, "date format is not defined"); + } + } + } break; + // Если мы получили хост машины + case 4: + // Устанавливаем хост сообщения + this->_host = item; + break; + // Если мы получили название приложения + case 5: + // Устанавливаем название сообщения + this->_app = item; + break; + // Если мы получили идентификатор процесса + case 6: { + // Выполняем установку идентификатора процесса + if(this->_fmk->is(item, fmk_t::check_t::NUMBER)) + // Выполняем получение идентификатора процесса + this->_pid = static_cast (::stoi(item)); + // Устанавливаем идентификатор процесса по умолчанию + else this->_pid = 0; + } break; + // Если мы получили идентификатор сообщения + case 7: + // Устанавливаем идентификатор сообщения + this->_mid = item; + break; + // Если мы получили параметры сообщения + case 8: { + // Смещение в сообщении + size_t offset = 0; + // Выполняем извлечение всех сообщений + for(;;){ + // Выполняем получение списка сообщений + const auto & messages = this->_reg.exec(item.substr(offset), this->_exp.mess); + // Если список сообщений получен + if(!messages.empty()){ + // Если параметры установлены + if(messages.front().front() != '-'){ + // Выполняем извлечение параметров + const auto & params = this->_reg.exec(messages.front(), this->_exp.params); + // Если список параметров получен + if(!params.empty() && (params.size() > 1)){ + // Идентификатор структурированных данных + string sid = ""; + // Выполняем перебор всего списка параметров + for(size_t i = 1; i < params.size(); i++){ + // Если идентификатор структурированных данных получен + if(i == 1) + // Устанавливаем идентификатор структурированных данных + sid = params.at(i); + // Выполняем перебор всех параметров + else { + // Смещение в сообщении + size_t offset = 0; + // Выполняем извлечение всех сообщений + for(;;){ + // Выполняем извлечение всего списка установленных параметров + const auto & items = this->_reg.exec(params.at(i).substr(offset), this->_exp.items); + // Если список параметров получен + if(!items.empty()){ + // Если элементов параметров получены 3 штуки + if(items.size() >= 3){ + // Получаем идентификатор структурированных данных + auto i = this->_sd.find(sid); + // Если идентификатор существует + if(i != this->_sd.end()) + // Устанавливаем структурированные данные + i->second.emplace(items.at(1), items.back().empty() ? items.at(2) : items.back()); + // Иначе добавляем новые структурированные данные + else this->_sd.emplace(sid, std::unordered_map {{items.at(1), items.back().empty() ? items.at(2) : items.back()}}); + } + // Увеличиваем длину сообщения + offset += items.front().size(); + // Выходим из цикла + } else break; + } + } + } + } + } + // Увеличиваем длину сообщения + offset += messages.front().size(); + // Выходим из цикла + } else break; + } + } break; + // Если мы получили текст сообщения + case 9: + // Устанавливаем полученное сообщение + this->_message = this->_fmk->transform(item, fmk_t::transform_t::TRIM); + break; } - } break; - // Если производится сбор сообщения - case 10: { - // Устанавливаем полученное сообщение - this->_message = syslog.substr(pos); - // Выходим из цикла - return; } } - } break; + // Выводим сообщение, что текст не соответствует стандартам SysLog + } else this->_log->print("SysLog parse: %s", log_t::flag_t::CRITICAL, "text does not comply with SysLog standards RFC3164 and RFC5424"); } - } + } break; } + /** + * Если возникает ошибка + */ + } catch(const std::exception & error) { + // Выводим сообщение об ошибке + this->_log->print("SysLog parse: %s", log_t::flag_t::CRITICAL, error.what()); } } } @@ -464,9 +858,9 @@ const string & anyks::SysLog::sd(const string & id, const string & key) const no * @param id идентификатор структурированных данных * @return список структурированных данных */ -const unordered_map & anyks::SysLog::sd(const string & id) const noexcept { +const std::unordered_map & anyks::SysLog::sd(const string & id) const noexcept { // Результат работы функции - static const unordered_map result; + static const std::unordered_map result; // Если идентификатор структурированных данных передан if(!id.empty()){ // Выполняем извлечение данных запрашиваемого идентификатора структурированных данных @@ -484,9 +878,11 @@ const unordered_map & anyks::SysLog::sd(const string & id) cons * @param id идентификатор структурированных данных * @param sd список структурированных данных */ -void anyks::SysLog::sd(const string & id, const unordered_map & sd) noexcept { +void anyks::SysLog::sd(const string & id, const std::unordered_map & sd) noexcept { // Если идентификатор и список структурированных данных переданы if(!id.empty() && !sd.empty()){ + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Выполняем извлечение данных запрашиваемого идентификатора структурированных данных auto i = this->_sd.find(id); // Если структурированные данные существуют @@ -501,7 +897,7 @@ void anyks::SysLog::sd(const string & id, const unordered_map & else i->second.emplace(item.first, item.second); } // Добавляем структурированные данные как они есть - } else this->_sd.emplace(std::forward (id), std::forward > (sd)); + } else this->_sd.emplace(std::forward (id), std::forward > (sd)); } } /** @@ -525,6 +921,8 @@ uint8_t anyks::SysLog::version() const noexcept { * @param version версия сообщения для установки */ void anyks::SysLog::version(const uint8_t version) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Устанавливаем версию сообщения this->_ver = version; } @@ -550,6 +948,8 @@ uint8_t anyks::SysLog::importance() const noexcept { * @param importance важность сообщения для установки */ void anyks::SysLog::pri(const uint8_t category, const uint8_t importance) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Выполняем установку приоритера сообщения this->_pri = (static_cast (category) * static_cast (8) + static_cast (importance)); } @@ -566,6 +966,8 @@ string anyks::SysLog::host() const noexcept { * @param host хост сообщения для установки */ void anyks::SysLog::host(const string & host) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Если хост передан if(host.empty()) // Выполняем установку пустого значения хоста @@ -586,6 +988,8 @@ string anyks::SysLog::application() const noexcept { * @param app назование приложения для установки */ void anyks::SysLog::application(const string & app) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Если название приложения передано if(app.empty()) // Выполняем установку пустого значения названия приложения @@ -606,6 +1010,8 @@ pid_t anyks::SysLog::pid() const noexcept { * @param pid идентификатор процесса для установки */ void anyks::SysLog::pid(const pid_t pid) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Устанавливаем идентификатор процесса this->_pid = pid; } @@ -622,6 +1028,8 @@ string anyks::SysLog::mid() const noexcept { * @param mid идентификатор сообщения для установки */ void anyks::SysLog::mid(const string & mid) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Если идентификатор сообщения передан if(mid.empty()) // Выполняем установку пустого значения идентификатора сообщения @@ -642,6 +1050,8 @@ string anyks::SysLog::message() const noexcept { * @param message сообщение для установки */ void anyks::SysLog::message(const string & message) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Устанавливаем сообщение this->_message = std::forward (message); } @@ -658,6 +1068,8 @@ string anyks::SysLog::format() const noexcept { * @param format формат даты для установки */ void anyks::SysLog::format(const string & format) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Если формат даты передан if(!format.empty()) // Выполняем установку формата даты @@ -692,6 +1104,8 @@ string anyks::SysLog::date(const string & format) const noexcept { void anyks::SysLog::date(const string & date, const string & format) noexcept { // Если данные даты переданы if(!date.empty() && !format.empty()){ + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Если формат даты сообщения установлен if(!format.empty()) // Выполняем парсинг даты @@ -705,234 +1119,295 @@ void anyks::SysLog::date(const string & date, const string & format) noexcept { * @return данные в формате SysLog */ string anyks::SysLog::syslog() const noexcept { - // Результат работы функции - string result = ""; - // Определяем стандарт SysLog - switch(static_cast (this->_std)){ - // Если установлен стандарт RFC3164 - case static_cast (std_t::RFC3164): { - // Если приоритет установлен - if(this->_pri > 0){ - // Устанавливаем начало экранирования - result.append(1, '<'); - // Устанавливаем значение приоритета - result.append(std::to_string(this->_pri)); - // Устанавливаем конец экранирования - result.append(1, '>'); - } - // Если штамп времени установлен - if(this->_timestamp > 0){ - // Устанавливаем дату сообщения - result.append(this->date("%b %d %H:%M:%S")); - // Если хост, название приложения или сообщение переданы - if(!this->_host.empty() || !this->_app.empty() || !this->_message.empty()) + /** + * Выполняем отлов ошибок + */ + try { + // Результат работы функции + string result = ""; + // Определяем стандарт SysLog + switch(static_cast (this->_std)){ + // Если установлен стандарт RFC3164 + case static_cast (std_t::RFC3164): { + // Если приоритет установлен + if(this->_pri > 0){ + // Устанавливаем начало экранирования + result.append(1, '<'); + // Устанавливаем значение приоритета + result.append(std::to_string(this->_pri)); + // Устанавливаем конец экранирования + result.append(1, '>'); + } + // Если штамп времени установлен + if(this->_timestamp > 0){ + // Получаем текущее значение даты + const time_t timestamp = ::time(nullptr); + // Создаем структуру времени + std::tm * tm = ::localtime(×tamp); + // Если установленный год совпадает с текущим годом + if(std::to_string(1900 + tm->tm_year).compare(this->date("%Y")) == 0) + // Устанавливаем дату сообщения + result.append(this->date("%b %d %H:%M:%S")); + // Выполняем установку года формирования лога + else result.append(this->date("%b %d %H:%M:%S %Y")); + // Если хост, название приложения или сообщение переданы + if(!this->_host.empty() || !this->_app.empty() || !this->_message.empty()) + // Устанавливаем разделитель + result.append(1, ' '); + } + // Если хост сообщения установлен + if(!this->_host.empty() && (this->_host.front() != '-')){ + // Устанавливаем хост сообщения + result.append(this->_host); + // Если хост, название приложения или сообщение переданы + if(!this->_app.empty() || !this->_message.empty()) + // Устанавливаем разделитель + result.append(1, ' '); + } + // Если название приложения установлено + if(!this->_app.empty() && (this->_app.front() != '-')){ + // Устанавливаем название сообщения + result.append(this->_app); + // Если идентификатор процесса передан + if(this->_pid > 0){ + // Устанавливаем открытие экранирования + result.append(1, '['); + // Устанавливаем идентификатор процесса + result.append(std::to_string(this->_pid)); + // Устанавливаем закрытие экранирования + result.append(1, ']'); + } // Устанавливаем разделитель - result.append(1, ' '); - } - // Если хост сообщения установлен - if(!this->_host.empty() && (this->_host.front() != '-')){ - // Устанавливаем хост сообщения - result.append(this->_host); - // Если хост, название приложения или сообщение переданы - if(!this->_app.empty() || !this->_message.empty()) + result.append(1, ':'); + // Если хост, название приложения или сообщение переданы + if(!this->_message.empty()) + // Устанавливаем разделитель + result.append(1, ' '); + } + // Если сообщение установлено + if(!this->_message.empty()) + // Устанавливаем сообщение + result.append(this->_message); + } break; + // Если установлен стандарт RFC5424 + case static_cast (std_t::RFC5424): { + // Если приоритет установлен + if(this->_pri > 0){ + // Устанавливаем начало экранирования + result.append(1, '<'); + // Устанавливаем значение приоритета + result.append(std::to_string(this->_pri)); + // Устанавливаем конец экранирования + result.append(1, '>'); + // Устанавливаем версию сообщения + result.append(std::to_string(this->_ver)); // Устанавливаем разделитель result.append(1, ' '); - } - // Если название приложения установлено - if(!this->_app.empty() && (this->_app.front() != '-')){ - // Устанавливаем название сообщения - result.append(this->_app); + } + // Если штамп времени установлен + if(this->_timestamp > 0) + // Устанавливаем дату сообщения + result.append(this->date(FORMAT)); + // Устанавливаем пропуск + else result.append(1, '-'); + // Устанавливаем разделитель + result.append(1, ' '); + // Если хост сообщения установлен + if(!this->_host.empty()) + // Устанавливаем хост сообщения + result.append(this->_host); + // Устанавливаем пропуск + else result.append(1, '-'); + // Устанавливаем разделитель + result.append(1, ' '); + // Если название приложения установлено + if(!this->_app.empty()) + // Устанавливаем название сообщения + result.append(this->_app); + // Устанавливаем пропуск + else result.append(1, '-'); + // Устанавливаем разделитель + result.append(1, ' '); // Если идентификатор процесса передан - if(this->_pid > 0){ - // Устанавливаем открытие экранирования - result.append(1, '['); + if(this->_pid > 0) // Устанавливаем идентификатор процесса result.append(std::to_string(this->_pid)); - // Устанавливаем закрытие экранирования - result.append(1, ']'); - } + // Устанавливаем пропуск + else result.append(1, '-'); // Устанавливаем разделитель - result.append(1, ':'); - // Если хост, название приложения или сообщение переданы - if(!this->_message.empty()) - // Устанавливаем разделитель - result.append(1, ' '); - } - // Если сообщение установлено - if(!this->_message.empty()) - // Устанавливаем сообщение - result.append(this->_message); - } break; - // Если установлен стандарт RFC5424 - case static_cast (std_t::RFC5424): { - // Если приоритет установлен - if(this->_pri > 0){ - // Устанавливаем начало экранирования - result.append(1, '<'); - // Устанавливаем значение приоритета - result.append(std::to_string(this->_pri)); - // Устанавливаем конец экранирования - result.append(1, '>'); - // Устанавливаем версию сообщения - result.append(std::to_string(this->_ver)); + result.append(1, ' '); + // Если идентификатор сообщения установлен + if(!this->_mid.empty()) + // Устанавливаем идентификатор сообщения + result.append(this->_mid); + // Устанавливаем пропуск + else result.append(1, '-'); // Устанавливаем разделитель result.append(1, ' '); - } - // Если штамп времени установлен - if(this->_timestamp > 0) - // Устанавливаем дату сообщения - result.append(this->date(FORMAT)); - // Устанавливаем пропуск - else result.append(1, '-'); - // Устанавливаем разделитель - result.append(1, ' '); - // Если хост сообщения установлен - if(!this->_host.empty()) - // Устанавливаем хост сообщения - result.append(this->_host); - // Устанавливаем пропуск - else result.append(1, '-'); - // Устанавливаем разделитель - result.append(1, ' '); - // Если название приложения установлено - if(!this->_app.empty()) - // Устанавливаем название сообщения - result.append(this->_app); - // Устанавливаем пропуск - else result.append(1, '-'); - // Устанавливаем разделитель - result.append(1, ' '); - // Если идентификатор процесса передан - if(this->_pid > 0) - // Устанавливаем идентификатор процесса - result.append(std::to_string(this->_pid)); - // Устанавливаем пропуск - else result.append(1, '-'); - // Устанавливаем разделитель - result.append(1, ' '); - // Если идентификатор сообщения установлен - if(!this->_mid.empty()) - // Устанавливаем идентификатор сообщения - result.append(this->_mid); - // Устанавливаем пропуск - else result.append(1, '-'); - // Устанавливаем разделитель - result.append(1, ' '); - // Если список структурированных данных установлен - if(!this->_sd.empty()){ - // Выполняем перебор структурированных данных - for(auto & item1 : this->_sd){ - // Флаг установки разделителя - bool separator = false; - // Устанавливаем начало разделителя - result.append(1, '['); - // Устанавливаем идентификатор структурированных данных - result.append(item1.first); - // Устанавливаем разделитель - result.append(1, ' '); - // Выполняем перебор оставшихся структур данных - for(auto & item2 : item1.second){ - // Если флаг установки разделителя не установлен - if(!separator) - // Устанавливаем флаг разделителя - separator = !separator; + // Если список структурированных данных установлен + if(!this->_sd.empty()){ + // Выполняем перебор структурированных данных + for(auto & item1 : this->_sd){ + // Флаг установки разделителя + bool separator = false; + // Устанавливаем начало разделителя + result.append(1, '['); + // Устанавливаем идентификатор структурированных данных + result.append(item1.first); // Устанавливаем разделитель - else result.append(1, ' '); - // Добавляем ключ структурированных данных - result.append(item2.first); - // Добавляем разделитель - result.append(1, '='); - // Добавляем начало экранирования - result.append(1, '"'); - // Добавляем значение - result.append(item2.second); - // Добавляем конец экранирования - result.append(1, '"'); + result.append(1, ' '); + // Выполняем перебор оставшихся структур данных + for(auto & item2 : item1.second){ + // Если флаг установки разделителя не установлен + if(!separator) + // Устанавливаем флаг разделителя + separator = !separator; + // Устанавливаем разделитель + else result.append(1, ' '); + // Добавляем ключ структурированных данных + result.append(item2.first); + // Добавляем разделитель + result.append(1, '='); + // Добавляем начало экранирования + result.append(1, '"'); + // Добавляем значение + result.append(item2.second); + // Добавляем конец экранирования + result.append(1, '"'); + } + // Устанавливаем конец разделителя + result.append(1, ']'); } - // Устанавливаем конец разделителя - result.append(1, ']'); + // Устанавливаем пропуск + } else result.append(1, '-'); + // Если сообщение установлено + if(!this->_message.empty()){ + // Устанавливаем разделитель + result.append(1, ' '); + // Устанавливаем сообщение + result.append(this->_message); } - // Устанавливаем пропуск - } else result.append(1, '-'); - // Если сообщение установлено - if(!this->_message.empty()){ - // Устанавливаем разделитель - result.append(1, ' '); - // Устанавливаем сообщение - result.append(this->_message); - } - } break; + } break; + } + // Выводим результат + return result; + /** + * Если возникает ошибка + */ + } catch(const std::exception & error) { + // Выводим сообщение об ошибке + this->_log->print("SysLog: %s", log_t::flag_t::CRITICAL, error.what()); } // Выводим результат - return result; + return ""; } /** * dump Метод извлечения данных в виде JSON * @return json объект дампа данных */ json anyks::SysLog::dump() const noexcept { - // Результат работы функции - json result = json::object(); - // Определяем стандарт SysLog - switch(static_cast (this->_std)){ - // Если установлен стандарт RFC3164 - case static_cast (std_t::RFC3164): - // Устанавливаем стандарт сообщения - result.emplace("RFC", 3164); - break; - // Если установлен стандарт RFC5424 - case static_cast (std_t::RFC5424): - // Устанавливаем стандарт сообщения - result.emplace("RFC", 5424); - break; - } - // Если штамп времени установлен - if(this->_timestamp > 0) - // Устанавливаем дату сообщения - result.emplace("date", this->date()); - // Если приоритет установлен - if(this->_pri > 0){ - // Устанавливаем категорию сообщения - result.emplace("category", this->category()); - // Устанавливаем важность сообщения - result.emplace("importance", this->importance()); - } - // Если хост установлен - if(!this->_host.empty() && (this->_host.compare("-") != 0)) - // Устанавливаем хост сообщения - result.emplace("host", this->_host); - // Если название приложения установлено - if(!this->_app.empty() && (this->_app.compare("-") != 0)) - // Устанавливаем название сообщения - result.emplace("application", this->_app); - // Если идентификатор процесса передан - if(this->_pid > 0) - // Устанавливаем идентификатор процесса - result.emplace("pid", this->_pid); - // Если идентификатор сообщения установлен - if(!this->_mid.empty() && (this->_mid.compare("-") != 0)) - // Устанавливаем идентификатор сообщения - result.emplace("mid", this->_mid); - // Если сообщение установлено - if(!this->_message.empty() && (this->_message.compare("-") != 0)) - // Устанавливаем полученное сообщение - result.emplace("message", this->_message); - // Если список структурированных данных установлен - if(!this->_sd.empty()){ - // Добавляем объект структурированных данных - result.emplace("sd", json::object()); - // Выполняем перебор структурированных данных - for(auto & item1 : this->_sd){ - // Устанавливаем идентификатор структурированных данных - result.at("sd").emplace(item1.first, json::object()); - // Выполняем перебор оставшихся структур данных - for(auto & item2 : item1.second) - // Добавляем полученные парасетры структурированных данных - result.at("sd").at(item1.first).emplace(item2.first, item2.second); + /** + * Выполняем отлов ошибок + */ + try { + // Результат работы функции + json result = json::object(); + // Определяем стандарт SysLog + switch(static_cast (this->_std)){ + // Если установлен стандарт RFC3164 + case static_cast (std_t::RFC3164): + // Устанавливаем стандарт сообщения + result.emplace("RFC", 3164); + break; + // Если установлен стандарт RFC5424 + case static_cast (std_t::RFC5424): + // Устанавливаем стандарт сообщения + result.emplace("RFC", 5424); + break; + } + // Если штамп времени установлен + if(this->_timestamp > 0) + // Устанавливаем дату сообщения + result.emplace("date", this->date()); + // Если приоритет установлен + if(this->_pri > 0){ + // Устанавливаем категорию сообщения + result.emplace("category", this->category()); + // Устанавливаем важность сообщения + result.emplace("importance", this->importance()); } + // Если версия сообщения получена + if(this->_ver > 0) + // Выполняем установку версии сообщения + result.emplace("version", this->_ver); + // Если хост установлен + if(!this->_host.empty() && (this->_host.compare("-") != 0)) + // Устанавливаем хост сообщения + result.emplace("host", this->_host); + // Если название приложения установлено + if(!this->_app.empty() && (this->_app.compare("-") != 0)) + // Устанавливаем название сообщения + result.emplace("application", this->_app); + // Если идентификатор процесса передан + if(this->_pid > 0) + // Устанавливаем идентификатор процесса + result.emplace("pid", this->_pid); + // Если идентификатор сообщения установлен + if(!this->_mid.empty() && (this->_mid.compare("-") != 0)) + // Устанавливаем идентификатор сообщения + result.emplace("mid", this->_mid); + // Если сообщение установлено + if(!this->_message.empty() && (this->_message.compare("-") != 0)) + // Устанавливаем полученное сообщение + result.emplace("message", this->_message); + // Если список структурированных данных установлен + if(!this->_sd.empty()){ + // Добавляем объект структурированных данных + result.emplace("sd", json::object()); + // Выполняем перебор структурированных данных + for(auto & item1 : this->_sd){ + // Устанавливаем идентификатор структурированных данных + result.at("sd").emplace(item1.first, json::object()); + // Выполняем перебор оставшихся структур данных + for(auto & item2 : item1.second){ + // Если запись является числом + if(this->_fmk->is(item2.second, fmk_t::check_t::NUMBER)){ + // Получаем переданное число + const long long number = std::stoll(item2.second); + // Если число положительное + if(number > 0) + // Добавляем полученные парасетры структурированных данных + result.at("sd").at(item1.first).emplace(item2.first, ::stoull(item2.second)); + // Добавляем полученные парасетры структурированных данных + else result.at("sd").at(item1.first).emplace(item2.first, number); + // Если запись является числом с плавающей точкой + } else if(this->_fmk->is(item2.second, fmk_t::check_t::DECIMAL)) + // Добавляем полученные парасетры структурированных данных + result.at("sd").at(item1.first).emplace(item2.first, ::stod(item2.second)); + // Если число является булевым истинным значением + else if(this->_fmk->compare("true", item2.second)) + // Добавляем полученные парасетры структурированных данных + result.at("sd").at(item1.first).emplace(item2.first, true); + // Если число является булевым ложным значением + else if(this->_fmk->compare("false", item2.second)) + // Добавляем полученные парасетры структурированных данных + result.at("sd").at(item1.first).emplace(item2.first, false); + // Добавляем полученные парасетры структурированных данных + else result.at("sd").at(item1.first).emplace(item2.first, item2.second); + } + } + } + // Выводим результат + return result; + /** + * Если возникает ошибка + */ + } catch(const std::exception & error) { + // Выводим сообщение об ошибке + this->_log->print("SysLog dump: %s", log_t::flag_t::CRITICAL, error.what()); } // Выводим результат - return result; + return json::object(); } /** * dump Метод установки данных в формате JSON @@ -941,85 +1416,163 @@ json anyks::SysLog::dump() const noexcept { void anyks::SysLog::dump(const json & dump) noexcept { // Если данные получены if(!dump.empty() && dump.is_object()){ - // Категория и важность сообщения - uint8_t category = 0, importance = 0; - // Если стандарт сообщения передан - if(dump.contains("RFC") && dump.at("RFC").is_number()){ - // Определяем тип переданного стандарта - switch(dump.at("RFC").get ()){ - // Если передан стандарт RFC3164 - case 3164: - // Устанавливаем стандарт RFC3164 - this->_std = std_t::RFC3164; - break; - // Если передан стандарт RFC5424 - case 5424: - // Устанавливаем стандарт RFC5424 - this->_std = std_t::RFC5424; - break; + /** + * Выполняем отлов ошибок + */ + try { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); + // Категория и важность сообщения + uint8_t category = 0, importance = 0; + // Если стандарт сообщения передан + if(dump.contains("RFC") && dump.at("RFC").is_number()){ + // Определяем тип переданного стандарта + switch(dump.at("RFC").get ()){ + // Если передан стандарт RFC3164 + case 3164: + // Устанавливаем стандарт RFC3164 + this->_std = std_t::RFC3164; + break; + // Если передан стандарт RFC5424 + case 5424: + // Устанавливаем стандарт RFC5424 + this->_std = std_t::RFC5424; + break; + } } - } - // Если дата передана - if(dump.contains("date") && dump.at("date").is_string()) - // Устанавливаем дату сообщения - this->date(dump.at("date").get (), this->_format); - // Если идентификатор процесса передан - if(dump.contains("pid") && dump.at("pid").is_number()) - // Устанавливаем идентификатор процесса - this->_pid = dump.at("pid").get (); - // Если идентификатор сообщения передан - if(dump.contains("mid") && dump.at("mid").is_string()) - // Устанавливаем идентификатор сообщения - this->_mid = dump.at("mid").get (); - // Если сообщение передано - if(dump.contains("message") && dump.at("message").is_string()) - // Устанавливаем сообщение - this->_message = dump.at("message").get (); - // Если хост сообщения передан - if(dump.contains("host") && dump.at("host").is_string()) - // Устанавливаем хост сообщения - this->_host = dump.at("host").get (); - // Если название приложения передано - if(dump.contains("application") && dump.at("application").is_string()) - // Устанавливаем название приложения - this->_app = dump.at("application").get (); - // Если категория сообщения передана - if(dump.contains("category") && dump.at("category").is_number()) - // Устанавливаем категорию сообщения - category = dump.at("category").get (); - // Если важность сообщения передана - if(dump.contains("importance") && dump.at("importance").is_number()) - // Устанавливаем важность сообщения - importance = dump.at("importance").get (); - // Выполняем установку приоритета - this->pri(category, importance); - // Если список структурированных данных передан - if(dump.contains("sd") && dump.at("sd").is_object()){ - // Выполняем очистку списка структурированных данных - this->_sd.clear(); - // Выполняем перебор списка параметров - for(auto & el : dump.at("sd").items()){ - // Если объект структурированных данных передан - if(!el.value().empty() && el.value().is_object()){ - // Выполняем перебор всех параметров - for(auto & item : el.value().items()){ - // Если параметр является строкой - if(!item.value().empty() && item.value().is_string()){ - // Выполняем поиск объекта структурированных данных - auto i = this->_sd.find(el.key()); - // Если объект структурированных данных уже создан - if(i != this->_sd.end()) - // Устанавливаем новые структурированные данные - i->second.emplace(item.key(), item.value().get ()); - // Добавляем новое значение записи - else this->_sd.emplace(el.key(), unordered_map {{item.key(), item.value().get ()}}); + // Если версия сообщения передана + if(dump.contains("version") && dump.at("version").is_number()) + // Устанавливаем версию сообщения + this->_ver = dump.at("version").get (); + // Если дата передана + if(dump.contains("date") && dump.at("date").is_string()) + // Устанавливаем дату сообщения + this->date(dump.at("date").get (), this->_format); + // Если идентификатор процесса передан + if(dump.contains("pid") && dump.at("pid").is_number()) + // Устанавливаем идентификатор процесса + this->_pid = dump.at("pid").get (); + // Если идентификатор сообщения передан + if(dump.contains("mid") && dump.at("mid").is_string()) + // Устанавливаем идентификатор сообщения + this->_mid = dump.at("mid").get (); + // Если сообщение передано + if(dump.contains("message") && dump.at("message").is_string()) + // Устанавливаем сообщение + this->_message = dump.at("message").get (); + // Если хост сообщения передан + if(dump.contains("host") && dump.at("host").is_string()) + // Устанавливаем хост сообщения + this->_host = dump.at("host").get (); + // Если название приложения передано + if(dump.contains("application") && dump.at("application").is_string()) + // Устанавливаем название приложения + this->_app = dump.at("application").get (); + // Если категория сообщения передана + if(dump.contains("category") && dump.at("category").is_number()) + // Устанавливаем категорию сообщения + category = dump.at("category").get (); + // Если важность сообщения передана + if(dump.contains("importance") && dump.at("importance").is_number()) + // Устанавливаем важность сообщения + importance = dump.at("importance").get (); + // Выполняем установку приоритета + this->pri(category, importance); + // Если список структурированных данных передан + if(dump.contains("sd") && dump.at("sd").is_object()){ + // Выполняем очистку списка структурированных данных + this->_sd.clear(); + // Выполняем перебор списка параметров + for(auto & el : dump.at("sd").items()){ + // Если объект структурированных данных передан + if(!el.value().empty() && el.value().is_object()){ + // Выполняем перебор всех параметров + for(auto & item : el.value().items()){ + // Если параметр является числом + if(!item.value().empty() && item.value().is_number()){ + // Временное значение переменной + double intpart = 0; + // Выполняем извлечение числа + const double number = item.value().get (); + // Выполняем поиск объекта структурированных данных + auto i = this->_sd.find(el.key()); + // Если объект структурированных данных уже создан + if(i != this->_sd.end()){ + // Выполняем проверку есть ли дробная часть у числа + if(::modf(number, &intpart) == 0){ + // Если число является положительным + if(number > 0.) + // Устанавливаем новые структурированные данные + i->second.emplace(item.key(), std::to_string(item.value().get ())); + // Если число является отрицательным + else i->second.emplace(item.key(), std::to_string(item.value().get ())); + // Если у числа имеется дробная часть + } else i->second.emplace(item.key(), this->_fmk->noexp(number, true)); + // Если объект структурированных данных ещё не создан + } else { + // Выполняем проверку есть ли дробная часть у числа + if(::modf(number, &intpart) == 0){ + // Если число является положительным + if(number > 0.) + // Добавляем новое значение записи + this->_sd.emplace(el.key(), std::unordered_map {{item.key(), std::to_string(item.value().get ())}}); + // Если число является отрицательным + else this->_sd.emplace(el.key(), std::unordered_map {{item.key(), std::to_string(item.value().get ())}}); + // Если у числа имеется дробная часть + } else this->_sd.emplace(el.key(), std::unordered_map {{item.key(), this->_fmk->noexp(number, true)}}); + } + // Если параметр является булевым значением + } else if(!item.value().empty() && item.value().is_boolean()) { + // Выполняем поиск объекта структурированных данных + auto i = this->_sd.find(el.key()); + // Если объект структурированных данных уже создан + if(i != this->_sd.end()) + // Устанавливаем новые структурированные данные + i->second.emplace(item.key(), item.value().get () ? "true" : "false"); + // Добавляем новое значение записи + else this->_sd.emplace(el.key(), std::unordered_map {{item.key(), item.value().get () ? "true" : "false"}}); + // Если параметр является строкой + } else if(!item.value().empty() && item.value().is_string()) { + // Выполняем поиск объекта структурированных данных + auto i = this->_sd.find(el.key()); + // Если объект структурированных данных уже создан + if(i != this->_sd.end()) + // Устанавливаем новые структурированные данные + i->second.emplace(item.key(), item.value().get ()); + // Добавляем новое значение записи + else this->_sd.emplace(el.key(), std::unordered_map {{item.key(), item.value().get ()}}); + } } } } } + /** + * Если возникает ошибка + */ + } catch(const std::exception & error) { + // Выводим сообщение об ошибке + this->_log->print("SysLog dump: %s", log_t::flag_t::CRITICAL, error.what()); } } } +/** + * mode Метод получения установленного режима парсинга + * @return установленный режим парсинга + */ +anyks::SysLog::mode_t anyks::SysLog::mode() const noexcept { + // Выполняем извлечение установленного режима парсинга + return this->_mode; +} +/** + * mode Метод установки режима парсинга + * @param mode режим парсинга для установки + */ +void anyks::SysLog::mode(const mode_t mode) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); + // Выполняем установку режим парсинга + this->_mode = mode; +} /** * Оператор вывода данные контейнера в качестве строки * @return данные контейнера в качестве строки @@ -1052,6 +1605,8 @@ bool anyks::SysLog::operator == (const syslog_t & syslog) const noexcept { * @return текущий объект */ anyks::SysLog & anyks::SysLog::operator = (const syslog_t & syslog) noexcept { + // Выполняем блокировку потока + const lock_guard lock(this->_mtx); // Устанавливаем список структурированных данных this->_sd = syslog._sd; // Устанавливаем стандарт сообщения SysLog @@ -1090,6 +1645,63 @@ anyks::SysLog & anyks::SysLog::operator = (const string & syslog) noexcept { // Выводим текущий объект return (* this); } +/** + * SysLog Конструктор + * @param fmk объект фреймворка + * @param log объект для работы с логами + */ +anyks::SysLog::SysLog(const fmk_t * fmk, const log_t * log) noexcept : + _std(std_t::AUTO), _ver(0), _pri(0), _mode(mode_t::REGEXP), _app{"-"}, _host{"-"}, + _pid(0), _mid{"-"}, _message{""}, _format{FORMAT}, _timestamp(0), _fmk(fmk), _log(log) { + // Выполняем сборку регулярных выражений для распознавания формат даты (Sat Jan 8 20:07:41 2011) + this->_exp.date1 = this->_reg.build("([a-z]+\\s+)?([a-z]+)\\s(\\d+)\\s+(\\d{1,2}\\:\\d{1,2}\\:\\d{1,2})(?:\\s+(\\d{2,4}))?", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для распознавания формат даты (2024-10-04 13:29:47) + this->_exp.date2 = this->_reg.build("(\\d{2,4}\\-\\d{1,2}\\-\\d{1,2})\\s+(\\d{1,2}\\:\\d{1,2}\\:\\d{1,2})", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для распознавания формат даты (2003-10-11T22:14:15.003Z) + this->_exp.date3 = this->_reg.build("(\\d{2,4}\\-\\d{1,2}\\-\\d{1,2})T(\\d{1,2}\\:\\d{1,2}\\:\\d{1,2})(?:\\.(\\d+)Z)?", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для извлечения сообщений для RFC5424 + this->_exp.mess = this->_reg.build("(\\-|\\[[^\\]]+\\])", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для извлечения параметров сообщений RFC5424 + this->_exp.params = this->_reg.build("\\[([\\w\\@\\-]+)\\s+(.*)\\]", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для извлечения параметров сообщения RFC5424 + this->_exp.items = this->_reg.build("([\\w\\-]+)\\=(?:\\\"([^\\\"]+)\\\"|(\\d+))", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для парсинга всего сообщения RFC3164 + this->_exp.rfc3164 = this->_reg.build("(?:<(\\d+)>)?((?:(?:[a-z]+\\s+)?[a-z]+\\s\\d+\\s+\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}(?:\\s+\\d{2,4})?)|\\d{2,4}\\-\\d{1,2}\\-\\d{1,2}\\s+\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}|\\d{2,4}\\-\\d{1,2}\\-\\d{1,2}T\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}(?:\\.\\d+Z)?)\\s([^\\s]+)\\s+([^\\[]+)(?:\\[(\\d+)\\])?\\:\\s*(.+)", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); + // Выполняем сборку регулярных выражений для парсинга всего сообщения RFC5424 + this->_exp.rfc5424 = this->_reg.build("(?:<(\\d+)>)?(?:(\\d+)\\s+)?((?:(?:[a-z]+\\s+)?[a-z]+\\s\\d+\\s+\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}(?:\\s+\\d{2,4})?)|\\d{2,4}\\-\\d{1,2}\\-\\d{1,2}\\s+\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}|\\d{2,4}\\-\\d{1,2}\\-\\d{1,2}T\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}(?:\\.\\d+Z)?)\\s([^\\s]+)\\s([^\\s]+)\\s+([\\d\\-]+)\\s+([\\w\\-]+)\\s+((?:(?:\\-|\\[[^\\]]+\\])\\s*)+)\\s*(.+)", { + regexp_t::option_t::UTF8, + regexp_t::option_t::UCP, + regexp_t::option_t::CASELESS + }); +} /** * Оператор [>>] чтения из потока SysLog контейнера * @param is поток для чтения