diff --git a/agent/CMakeLists.txt b/agent/CMakeLists.txt index 9cc7025cee..a8669eecfa 100644 --- a/agent/CMakeLists.txt +++ b/agent/CMakeLists.txt @@ -145,7 +145,9 @@ set( SRC_WINDOWS ${NATIVE_SRC}/check_uptime.cc ${NATIVE_SRC}/check_drive_size.cc ${NATIVE_SRC}/check_event_log.cc + ${NATIVE_SRC}/check_event_log_container.cc ${NATIVE_SRC}/check_event_log_data.cc + ${NATIVE_SRC}/check_event_log_uniq.cc ${NATIVE_SRC}/check_memory.cc ${NATIVE_SRC}/check_service.cc ${NATIVE_SRC}/windows_util.cc diff --git a/agent/native_windows/inc/com/centreon/agent/check_event_log_container.hh b/agent/native_windows/inc/com/centreon/agent/check_event_log_container.hh new file mode 100644 index 0000000000..a2909dd9ea --- /dev/null +++ b/agent/native_windows/inc/com/centreon/agent/check_event_log_container.hh @@ -0,0 +1,97 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_CHECK_EVENT_LOG_CONTAINER_HH +#define CENTREON_AGENT_CHECK_EVENT_LOG_CONTAINER_HH + +#include "check_event_log_data.hh" + +namespace com::centreon::agent::check_event_log_detail { + +class event_container { + public: + using event_set = boost::multi_index::multi_index_container< + event, + boost::multi_index::indexed_by< + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_CONST_MEM_FUN( + event, + std::chrono::file_clock::time_point, + time)>, + boost::multi_index::ordered_non_unique< + BOOST_MULTI_INDEX_CONST_MEM_FUN(event, e_status, status)>>>; + + private: + duration _scan_range; + + std::wstring _file; + std::unique_ptr _primary_filter; + std::unique_ptr _warning_filter; + std::unique_ptr _critical_filter; + + event_set _events ABSL_GUARDED_BY(_events_m); + unsigned _insertion_cpt ABSL_GUARDED_BY(_events_m); + unsigned _nb_warning ABSL_GUARDED_BY(_events_m); + unsigned _nb_critical ABSL_GUARDED_BY(_events_m); + absl::Mutex _events_m; + + EVT_HANDLE _render_context; + EVT_HANDLE _subscription; + + using provider_metadata = absl::flat_hash_map; + provider_metadata _provider_metadata ABSL_GUARDED_BY(_events_m); + + void* _read_event_buffer ABSL_GUARDED_BY(_events_m); + DWORD _buffer_size ABSL_GUARDED_BY(_events_m); + + bool _need_to_decode_message_content; + LPWSTR _read_message_buffer ABSL_GUARDED_BY(_events_m); + DWORD _message_buffer_size ABSL_GUARDED_BY(_events_m); // size in wchar_t + + std::shared_ptr _logger; + + static DWORD WINAPI _subscription_callback(EVT_SUBSCRIBE_NOTIFY_ACTION action, + PVOID p_context, + EVT_HANDLE h_event); + + void _on_event(EVT_HANDLE event_handle); + + LPWSTR _get_message_string(EVT_HANDLE h_metadata, EVT_HANDLE h_event); + + public: + event_container(const std::string_view& file, + const std::string_view& primary_filter, + const std::string_view& warning_filter, + const std::string_view& critical_filter, + duration scan_range, + const std::shared_ptr& logger); + void start(); + + ~event_container(); + + void lock() { _events_m.Lock(); } + void unlock() { _events_m.Unlock(); } + + const event_set& get_events() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(_events_m) { + return _events; + } +}; + +} // namespace com::centreon::agent::check_event_log_detail + +#endif \ No newline at end of file diff --git a/agent/native_windows/inc/com/centreon/agent/check_event_log_data.hh b/agent/native_windows/inc/com/centreon/agent/check_event_log_data.hh index 21e4413763..88391d9e88 100644 --- a/agent/native_windows/inc/com/centreon/agent/check_event_log_data.hh +++ b/agent/native_windows/inc/com/centreon/agent/check_event_log_data.hh @@ -23,9 +23,6 @@ #include -#include "boost/multi_index/indexed_by.hpp" -#include "boost/multi_index/ordered_index.hpp" -#include "boost/multi_index_container.hpp" #include "check.hh" #include "filter.hh" @@ -169,75 +166,6 @@ class event { std::ostream& operator<<(std::ostream& s, const event& evt); -class event_container { - public: - using event_set = boost::multi_index::multi_index_container< - event, - boost::multi_index::indexed_by< - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_CONST_MEM_FUN( - event, - std::chrono::file_clock::time_point, - time)>, - boost::multi_index::ordered_non_unique< - BOOST_MULTI_INDEX_CONST_MEM_FUN(event, e_status, status)>>>; - - private: - duration _scan_range; - - std::wstring _file; - std::unique_ptr _primary_filter; - std::unique_ptr _warning_filter; - std::unique_ptr _critical_filter; - - event_set _events ABSL_GUARDED_BY(_events_m); - unsigned _insertion_cpt ABSL_GUARDED_BY(_events_m); - unsigned _nb_warning ABSL_GUARDED_BY(_events_m); - unsigned _nb_critical ABSL_GUARDED_BY(_events_m); - absl::Mutex _events_m; - - EVT_HANDLE _render_context; - EVT_HANDLE _subscription; - - using provider_metadata = absl::flat_hash_map; - provider_metadata _provider_metadata ABSL_GUARDED_BY(_events_m); - - void* _read_event_buffer ABSL_GUARDED_BY(_events_m); - DWORD _buffer_size ABSL_GUARDED_BY(_events_m); - - bool _need_to_decode_message_content; - LPWSTR _read_message_buffer ABSL_GUARDED_BY(_events_m); - DWORD _message_buffer_size ABSL_GUARDED_BY(_events_m); // size in wchar_t - - std::shared_ptr _logger; - - static DWORD WINAPI _subscription_callback(EVT_SUBSCRIBE_NOTIFY_ACTION action, - PVOID p_context, - EVT_HANDLE h_event); - - void _on_event(EVT_HANDLE event_handle); - - LPWSTR _get_message_string(EVT_HANDLE h_metadata, EVT_HANDLE h_event); - - public: - event_container(const std::string_view& file, - const std::string_view& primary_filter, - const std::string_view& warning_filter, - const std::string_view& critical_filter, - duration scan_range, - const std::shared_ptr& logger); - void start(); - - ~event_container(); - - void lock() { _events_m.Lock(); } - void unlock() { _events_m.Unlock(); } - - const event_set& get_events() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(_events_m) { - return _events; - } -}; - } // namespace com::centreon::agent::check_event_log_detail #endif diff --git a/agent/native_windows/inc/com/centreon/agent/check_event_log_uniq.hh b/agent/native_windows/inc/com/centreon/agent/check_event_log_uniq.hh new file mode 100644 index 0000000000..6d9d2d18d4 --- /dev/null +++ b/agent/native_windows/inc/com/centreon/agent/check_event_log_uniq.hh @@ -0,0 +1,80 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_CHECK_EVENT_LOG_UNIQ_HH +#define CENTREON_AGENT_CHECK_EVENT_LOG_UNIQ_HH + +#include "check_event_log_data.hh" + +namespace com::centreon::agent::check_event_log_detail { + +class event_comparator { + using field_event_hasher = std::function; + using field_event_compare = std::function; + + std::vector _hash; + std::vector _compare; + + public: + event_comparator(std::string_view fields, + const std::shared_ptr& logger); + + bool operator()(const event* left, const event* right) const; + std::size_t operator()(const event* evt) const; +}; + +class unique_event { + event_comparator _comparator; + + public: + unique_event(const std::string_view& fields, + const std::shared_ptr& logger); + + template + void unique(event_iter begin, + event_iter end, + out_iter&& warning_inserter, + out_iter&& critical_inserter); +}; + +template +void unique_event::unique(event_iter begin, + event_iter end, + out_iter&& warning_inserter, + out_iter&& critical_inserter) { + absl::flat_hash_set warning( + 0, _comparator, _comparator); + absl::flat_hash_set + critical(0, _comparator, _comparator); + + for (; begin != end; ++begin) { + if (begin->status() == e_status::warning) { + if (warning.insert(&*begin).second) { + warning_inserter(*begin); + } + } else { + if (critical.insert(&*begin).second) { + critical_inserter(*begin); + } + } + } +} + +} // namespace com::centreon::agent::check_event_log_detail + +#endif diff --git a/agent/native_windows/src/check_event_log_container.cc b/agent/native_windows/src/check_event_log_container.cc new file mode 100644 index 0000000000..d9b063cc68 --- /dev/null +++ b/agent/native_windows/src/check_event_log_container.cc @@ -0,0 +1,222 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "windows_util.hh" + +#include "check_event_log_container.hh" + +using namespace com::centreon::agent; +using namespace com::centreon::agent::check_event_log_detail; + +event_container::event_container(const std::string_view& file, + const std::string_view& primary_filter, + const std::string_view& warning_filter, + const std::string_view& critical_filter, + duration scan_range, + const std::shared_ptr& logger) + : _scan_range(scan_range), + _file(file.begin(), file.end()), + _insertion_cpt(0), + _nb_warning(0), + _nb_critical(0), + _render_context(nullptr), + _subscription(nullptr), + _read_event_buffer(malloc(4096)), + _buffer_size(4096), + _read_message_buffer(static_cast(malloc(4096 * sizeof(wchar_t)))), + _message_buffer_size(4095), + _logger(logger) { + if (!primary_filter.empty()) { + try { + _primary_filter = std::make_unique(primary_filter, logger); + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR(logger, "fail to parse event filter: {}", e.what()); + throw; + } + } + + if (!warning_filter.empty()) { + try { + _warning_filter = std::make_unique(warning_filter, logger); + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR(logger, "fail to parse warning filter: {}", e.what()); + throw; + } + } + + if (!critical_filter.empty()) { + try { + _critical_filter = + std::make_unique(critical_filter, logger); + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR(logger, "fail to parse critical filter: {}", + e.what()); + throw; + } + } + + _render_context = EvtCreateRenderContext(0, nullptr, EvtRenderContextSystem); + if (!_render_context) { + throw exceptions::msg_fmt("fail to create render context: {}", + get_last_error_as_string()); + } +} + +event_container::~event_container() { + if (_subscription != nullptr) { + EvtClose(_subscription); + } + if (_render_context != nullptr) { + EvtClose(_render_context); + } + free(_read_event_buffer); + free(_read_message_buffer); + + for (auto& to_close : _provider_metadata) { + EvtClose(to_close.second); + } +} + +void event_container::start() { + std::wstring query; + query = std::format( + L"Event/System[TimeCreated[timediff(@SystemTime) <= {}]]", + std::chrono::duration_cast(_scan_range) + .count()); + + _subscription = EvtSubscribe(nullptr, nullptr, _file.c_str(), query.c_str(), + nullptr, this, _subscription_callback, + EvtSubscribeStartAtOldestRecord); + if (_subscription == nullptr) { + throw exceptions::msg_fmt("Failed to subscribe to event log: {}", + get_last_error_as_string()); + } +} + +DWORD WINAPI +event_container::_subscription_callback(EVT_SUBSCRIBE_NOTIFY_ACTION action, + PVOID p_context, + EVT_HANDLE h_event) { + event_container* me = reinterpret_cast(p_context); + if (action == EvtSubscribeActionError) { + SPDLOG_LOGGER_ERROR(me->_logger, "subscription_callback error"); + return ERROR_SUCCESS; + } + me->_on_event(h_event); + return ERROR_SUCCESS; +} + +LPWSTR event_container::_get_message_string(EVT_HANDLE h_metadata, + EVT_HANDLE h_event) { + DWORD buffer_used = 0; + + if (EvtFormatMessage(h_metadata, h_event, 0, 0, nullptr, + EvtFormatMessageEvent, _message_buffer_size, + _read_message_buffer, &buffer_used)) { + _read_message_buffer[_message_buffer_size] = L'\0'; + return _read_message_buffer; + } + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + _read_message_buffer = static_cast( + malloc((buffer_used + 1) * sizeof(wchar_t))); //+1 for \0 + _message_buffer_size = buffer_used; + } + if (EvtFormatMessage(h_metadata, h_event, 0, 0, nullptr, + EvtFormatMessageEvent, _message_buffer_size, + _read_message_buffer, &buffer_used)) { + _read_message_buffer[_message_buffer_size] = L'\0'; + return _read_message_buffer; + } + SPDLOG_LOGGER_ERROR(_logger, "fail to get message"); + return nullptr; +} + +void event_container::_on_event(EVT_HANDLE h_event) { + try { + absl::MutexLock l(&_events_m); + event_data raw_event(_render_context, h_event, &_read_event_buffer, + &_buffer_size); + + if (!_primary_filter->allow(raw_event)) { + return; + } + + e_status event_status = e_status::ok; + if (_critical_filter->allow(raw_event)) { + event_status = e_status::critical; + } else if (_warning_filter->allow(raw_event)) { + event_status = e_status::warning; + } else { + return; + } + + std::string message; + if (_need_to_decode_message_content) { + auto yet_open = _provider_metadata.find(raw_event.get_provider()); + if (yet_open == _provider_metadata.end()) { + EVT_HANDLE new_publisher = EvtOpenPublisherMetadata( + NULL, raw_event.get_provider().data(), NULL, 0, 0); + if (!new_publisher) { + SPDLOG_LOGGER_ERROR(_logger, + "fail to get publisher metadata for provider: {}", + lpwcstr_to_acp(raw_event.get_provider().data())); + } else { + yet_open = _provider_metadata + .emplace(raw_event.get_provider(), new_publisher) + .first; + } + } + if (yet_open != _provider_metadata.end()) { + LPWSTR mess = _get_message_string(yet_open->second, h_event); + if (mess) { + message = lpwcstr_to_acp(mess); + } + } + } + + boost::replace_all(message, "\r\n", " "); + + _events.emplace(raw_event, event_status, std::move(message)); + if (event_status == e_status::warning) { + ++_nb_warning; + } else { + ++_nb_critical; + } + + // every 10 events we + if (!((++_insertion_cpt) % 10)) { + auto peremption = std::chrono::file_clock::now() - _scan_range; + auto& time_index = _events.get<0>(); + while (!_events.empty()) { + auto oldest = time_index.begin(); + if (oldest->time() > peremption) { + break; + } + if (oldest->status() == e_status::warning) { + --_nb_warning; + } else { + --_nb_critical; + } + _events.erase(oldest); + } + } + + } catch (const std::exception& e) { + SPDLOG_LOGGER_ERROR(_logger, "fail to read event: {}", e.what()); + } +} diff --git a/agent/native_windows/src/check_event_log_data.cc b/agent/native_windows/src/check_event_log_data.cc index 46382be00b..4a6189100f 100644 --- a/agent/native_windows/src/check_event_log_data.cc +++ b/agent/native_windows/src/check_event_log_data.cc @@ -16,8 +16,6 @@ * For more information : contact@centreon.com */ -#include -#include "boost/algorithm/string/replace.hpp" #include "windows_util.hh" #include "filter.hh" @@ -407,207 +405,3 @@ std::ostream& operator<<(std::ostream& s, const event& evt) { } } // namespace com::centreon::agent::check_event_log_detail - -/*************************************************************************** - * * - * event_container * - * * - ****************************************************************************/ - -event_container::event_container(const std::string_view& file, - const std::string_view& primary_filter, - const std::string_view& warning_filter, - const std::string_view& critical_filter, - duration scan_range, - const std::shared_ptr& logger) - : _scan_range(scan_range), - _file(file.begin(), file.end()), - _insertion_cpt(0), - _nb_warning(0), - _nb_critial(0), - _render_context(nullptr), - _subscription(nullptr), - _read_event_buffer(malloc(4096)), - _buffer_size(4096), - _read_message_buffer(static_cast(malloc(4096 * sizeof(wchar_t)))), - _message_buffer_size(4095), - _logger(logger) { - if (!primary_filter.empty()) { - try { - _primary_filter = std::make_unique(primary_filter, logger); - } catch (const std::exception& e) { - SPDLOG_LOGGER_ERROR(logger, "fail to parse event filter: {}", e.what()); - throw; - } - } - - if (!warning_filter.empty()) { - try { - _warning_filter = std::make_unique(warning_filter, logger); - } catch (const std::exception& e) { - SPDLOG_LOGGER_ERROR(logger, "fail to parse warning filter: {}", e.what()); - throw; - } - } - - if (!critical_filter.empty()) { - try { - _critical_filter = - std::make_unique(critical_filter, logger); - } catch (const std::exception& e) { - SPDLOG_LOGGER_ERROR(logger, "fail to parse critical filter: {}", - e.what()); - throw; - } - } - - _render_context = EvtCreateRenderContext(0, nullptr, EvtRenderContextSystem); - if (!_render_context) { - throw exceptions::msg_fmt("fail to create render context: {}", - get_last_error_as_string()); - } -} - -event_container::~event_container() { - if (_subscription != nullptr) { - EvtClose(_subscription); - } - if (_render_context != nullptr) { - EvtClose(_render_context); - } - free(_read_event_buffer); - free(_read_message_buffer); - - for (auto& to_close : _provider_metadata) { - EvtClose(to_close.second); - } -} - -void event_container::start() { - std::wstring query; - query = std::format( - L"Event/System[TimeCreated[timediff(@SystemTime) <= {}]]", - std::chrono::duration_cast(_scan_range) - .count()); - - _subscription = EvtSubscribe(nullptr, nullptr, _file.c_str(), query.c_str(), - nullptr, this, _subscription_callback, - EvtSubscribeStartAtOldestRecord); - if (_subscription == nullptr) { - throw exceptions::msg_fmt("Failed to subscribe to event log: {}", - get_last_error_as_string()); - } -} - -DWORD WINAPI -event_container::_subscription_callback(EVT_SUBSCRIBE_NOTIFY_ACTION action, - PVOID p_context, - EVT_HANDLE h_event) { - event_container* me = reinterpret_cast(p_context); - if (action == EvtSubscribeActionError) { - SPDLOG_LOGGER_ERROR(me->_logger, "subscription_callback error"); - return ERROR_SUCCESS; - } - me->_on_event(h_event); - return ERROR_SUCCESS; -} - -LPWSTR event_container::_get_message_string(EVT_HANDLE h_metadata, - EVT_HANDLE h_event) { - DWORD buffer_used = 0; - - if (EvtFormatMessage(h_metadata, h_event, 0, 0, nullptr, - EvtFormatMessageEvent, _message_buffer_size, - _read_message_buffer, &buffer_used)) { - _read_message_buffer[_message_buffer_size] = L'\0'; - return _read_message_buffer; - } - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - _read_message_buffer = static_cast( - malloc((buffer_used + 1) * sizeof(wchar_t))); //+1 for \0 - _message_buffer_size = buffer_used; - } - if (EvtFormatMessage(h_metadata, h_event, 0, 0, nullptr, - EvtFormatMessageEvent, _message_buffer_size, - _read_message_buffer, &buffer_used)) { - _read_message_buffer[_message_buffer_size] = L'\0'; - return _read_message_buffer; - } - SPDLOG_LOGGER_ERROR(_logger, "fail to get message"); - return nullptr; -} - -void event_container::_on_event(EVT_HANDLE h_event) { - try { - absl::MutexLock l(&_events_m); - event_data raw_event(_render_context, h_event, &_read_event_buffer, - &_buffer_size); - - if (!_primary_filter->allow(raw_event)) { - return; - } - - e_status event_status = e_status::ok; - if (_critical_filter->allow(raw_event)) { - event_status = e_status::critical; - } else if (_warning_filter->allow(raw_event)) { - event_status = e_status::warning; - } else { - return; - } - - std::string message; - if (_need_to_decode_message_content) { - auto yet_open = _provider_metadata.find(raw_event.get_provider()); - if (yet_open == _provider_metadata.end()) { - EVT_HANDLE new_publisher = EvtOpenPublisherMetadata( - NULL, raw_event.get_provider().data(), NULL, 0, 0); - if (!new_publisher) { - SPDLOG_LOGGER_ERROR(_logger, - "fail to get publisher metadata for provider: {}", - lpwcstr_to_acp(raw_event.get_provider().data())); - } else { - yet_open = _provider_metadata - .emplace(raw_event.get_provider(), new_publisher) - .first; - } - } - if (yet_open != _provider_metadata.end()) { - LPWSTR mess = _get_message_string(yet_open->second, h_event); - if (mess) { - message = lpwcstr_to_acp(mess); - } - } - } - - boost::replace_all(message, "\r\n", " "); - - _events.emplace(raw_event, event_status, std::move(message)); - if (event_status == e_status::warning) { - ++_nb_warning; - } else { - ++_nb_critical; - } - - // every 10 events we - if (!(++_insertion_cpt) % 10) { - auto peremption = std::chrono::file_clock::now() - _scan_range; - auto& time_index = _events.get<0>(); - while (!_events.empty()) { - auto oldest = time_index.begin(); - if (oldest->time() > peremption) { - break; - } - if (oldest->status() == e_status::warning) { - --_nb_warning; - } else { - --nb_critical; - } - _events.erase(oldest); - } - } - - } catch (const std::exception& e) { - SPDLOG_LOGGER_ERROR(_logger, "fail to read event: {}", e.what()); - } -} diff --git a/agent/native_windows/src/check_event_log_uniq.cc b/agent/native_windows/src/check_event_log_uniq.cc new file mode 100644 index 0000000000..78b5580914 --- /dev/null +++ b/agent/native_windows/src/check_event_log_uniq.cc @@ -0,0 +1,84 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#include "check_event_log_uniq.hh" +#include "re2/re2.h" +#include "spdlog/spdlog.h" + +using namespace com::centreon::agent::check_event_log_detail; + +re2::RE2 field_regex("\\${([^\\${}]+)}"); + +event_comparator::event_comparator( + std::string_view fields, + const std::shared_ptr& logger) { + std::string_view field; + while (RE2::FindAndConsume(&fields, field_regex, &field)) { + if (field == "source" || field == "provider") { + _hash.emplace_back([](const event& evt) -> size_t { + return absl::Hash()(evt.provider()); + }); + _compare.emplace_back([](const event& left, const event& right) -> bool { + return left.provider() == right.provider(); + }); + } else if (field == "id") { + _hash.emplace_back([](const event& evt) -> size_t { return evt.id(); }); + _compare.emplace_back([](const event& left, const event& right) -> bool { + return left.id() == right.id(); + }); + } else if (field == "message" || field == "message") { + _hash.emplace_back([](const event& evt) -> size_t { + return absl::Hash()(evt.message()); + }); + _compare.emplace_back([](const event& left, const event& right) -> bool { + return left.message() == right.message(); + }); + } else if (field == "channel" || field == "channel") { + _hash.emplace_back([](const event& evt) -> size_t { + return absl::Hash()(evt.channel()); + }); + _compare.emplace_back([](const event& left, const event& right) -> bool { + return left.channel() == right.channel(); + }); + } + } + if (_compare.empty()) { + SPDLOG_LOGGER_DEBUG(logger, "no unique sort for output"); + } +} + +bool event_comparator::operator()(const event* left, const event* right) const { + for (const auto& comp : _compare) { + if (!comp(*left, *right)) { + return false; + } + } + return true; +} + +std::size_t event_comparator::operator()(const event* to_hash) const { + std::size_t ret = 0; + for (const auto hash : _hash) { + ret += hash(*to_hash); + } + return ret; +} + +unique_event::unique_event(const std::string_view& fields, + const std::shared_ptr& logger) + : _comparator(fields, logger) {} diff --git a/agent/test/CMakeLists.txt b/agent/test/CMakeLists.txt index 9317039868..fd58a5c778 100644 --- a/agent/test/CMakeLists.txt +++ b/agent/test/CMakeLists.txt @@ -34,6 +34,7 @@ else() set(SRC ${SRC_COMMON} check_event_log_data_test.cc check_event_log_filter_test.cc + check_event_log_uniq_test.cc check_windows_cpu_test.cc check_windows_memory_test.cc check_uptime_test.cc diff --git a/agent/test/check_event_log_data_test.cc b/agent/test/check_event_log_data_test.cc index a212a53e04..3aee416d3f 100644 --- a/agent/test/check_event_log_data_test.cc +++ b/agent/test/check_event_log_data_test.cc @@ -18,7 +18,7 @@ #include -#include "check_event_log_data.hh" +#include "check_event_log_container.hh" using namespace com::centreon::agent; using namespace com::centreon::agent::check_event_log_detail;