From f59082d2289b3d8c98fe755fae6b4b5432bcf18e Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 12:48:40 +0200 Subject: [PATCH 01/15] Introduce Logger#object_filter --- lib/base/logger.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ lib/base/logger.hpp | 1 + lib/base/logger.ti | 7 +++++++ 3 files changed, 49 insertions(+) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 38a2c6721b4..b7158fb14e2 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -74,6 +74,47 @@ void Logger::Stop(bool runtimeRemoved) ObjectImpl::Stop(runtimeRemoved); } +void Logger::ValidateObjectFilter(const Lazy& lvalue, const ValidationUtils& utils) +{ + ObjectImpl::ValidateObjectFilter(lvalue, utils); + + auto filter (lvalue()); + + if (filter) { + ObjectLock lock (filter); + + for (auto& kv : filter) { + auto type (Type::GetByName(kv.first)); + + if (!type) { + BOOST_THROW_EXCEPTION( + ValidationError(this, {"object_filter"}, "No such type: '" + kv.first + "'") + ); + } + + if (!dynamic_cast(type.get())) { + BOOST_THROW_EXCEPTION( + ValidationError(this, {"object_filter"}, "Not a config object type: '" + kv.first + "'") + ); + } + + Array::Ptr objects = kv.second; + + if (objects) { + ObjectLock lock (objects); + + for (auto& object : objects) { + if (object.GetType() != ValueString) { + BOOST_THROW_EXCEPTION( + ValidationError(this, {"object_filter", kv.first}, "Must be an array of strings.") + ); + } + } + } + } + } +} + std::set Logger::GetLoggers() { std::unique_lock lock(m_Mutex); diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index 10e0872ae68..1c0215cc74e 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -92,6 +92,7 @@ class Logger : public ObjectImpl protected: void Start(bool runtimeCreated) override; void Stop(bool runtimeRemoved) override; + void ValidateObjectFilter(const Lazy& lvalue, const ValidationUtils& utils) override; private: static void UpdateMinLogSeverity(); diff --git a/lib/base/logger.ti b/lib/base/logger.ti index 44226cee41a..88544ea39ee 100644 --- a/lib/base/logger.ti +++ b/lib/base/logger.ti @@ -12,6 +12,13 @@ abstract class Logger : ConfigObject [config, virtual] String severity { default {{{ return "information"; }}} }; + [config] Dictionary::Ptr object_filter; +}; + +validator Logger { + Dictionary object_filter { + Array "*"; + }; }; } From 9693663e2769002be5eaf1b8a7d160f5033a423c Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 18:26:44 +0200 Subject: [PATCH 02/15] Logger#{OnAllConfigLoaded,SetObjectFilter}(): warn on missing objects for --- lib/base/logger.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/base/logger.hpp | 6 ++++++ lib/base/logger.ti | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index b7158fb14e2..042d01a3f05 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -62,6 +62,19 @@ void Logger::Start(bool runtimeCreated) UpdateMinLogSeverity(); } +void Logger::SetObjectFilter(const Dictionary::Ptr& value, bool suppress_events, const Value& cookie) +{ + ObjectImpl::SetObjectFilter(value, suppress_events, cookie); + CheckObjectFilter(); +} + +void Logger::OnAllConfigLoaded() +{ + ObjectImpl::OnAllConfigLoaded(); + m_CalledOnAllConfigLoaded.store(true); + CheckObjectFilter(); +} + void Logger::Stop(bool runtimeRemoved) { { @@ -284,6 +297,38 @@ void Logger::UpdateMinLogSeverity() m_MinLogSeverity.store(result); } +void Logger::CheckObjectFilter() +{ + if (!m_CalledOnAllConfigLoaded.load()) { + return; + } + + auto filter (GetObjectFilter()); + + if (!filter) { + return; + } + + ObjectLock lock (filter); + + for (auto& kv : filter) { + auto type (Type::GetByName(kv.first)); + auto ctype (dynamic_cast(type.get())); + Array::Ptr objects = kv.second; + + if (ctype && objects) { + ObjectLock lock (objects); + + for (String object : objects) { + if (!ctype->GetObject(object)) { + Log(LogWarning, GetReflectionType()->GetName()) + << "Missing " << kv.first << " '" << object << "' in object filter of '" << GetName() << "'."; + } + } + } + } +} + Log::Log(LogSeverity severity, String facility, const String& message) : Log(severity, std::move(facility)) { diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index 1c0215cc74e..cdb4e39c13a 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -88,6 +88,8 @@ class Logger : public ObjectImpl void SetSeverity(const String& value, bool suppress_events = false, const Value& cookie = Empty) override; void ValidateSeverity(const Lazy& lvalue, const ValidationUtils& utils) final; + void SetObjectFilter(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty) override; + void OnAllConfigLoaded() override; protected: void Start(bool runtimeCreated) override; @@ -97,6 +99,8 @@ class Logger : public ObjectImpl private: static void UpdateMinLogSeverity(); + void CheckObjectFilter(); + static std::mutex m_Mutex; static std::set m_Loggers; static bool m_ConsoleLogEnabled; @@ -105,6 +109,8 @@ class Logger : public ObjectImpl static LogSeverity m_ConsoleLogSeverity; static std::mutex m_UpdateMinLogSeverityMutex; static Atomic m_MinLogSeverity; + + Atomic m_CalledOnAllConfigLoaded {false}; }; class Log diff --git a/lib/base/logger.ti b/lib/base/logger.ti index 88544ea39ee..7a788d3c8c4 100644 --- a/lib/base/logger.ti +++ b/lib/base/logger.ti @@ -12,7 +12,7 @@ abstract class Logger : ConfigObject [config, virtual] String severity { default {{{ return "information"; }}} }; - [config] Dictionary::Ptr object_filter; + [config, set_virtual] Dictionary::Ptr object_filter; }; validator Logger { From 27413d531348cd7a571bc69d6eba0afde0d7fd37 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 18:41:41 +0200 Subject: [PATCH 03/15] Cache actual Logger#object_filter objects in Logger#m_ObjectFilterCache --- lib/base/logger.cpp | 44 ++++++++++++++++++++++++++++++-------------- lib/base/logger.hpp | 4 +++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 042d01a3f05..d8f4900c264 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -65,14 +65,14 @@ void Logger::Start(bool runtimeCreated) void Logger::SetObjectFilter(const Dictionary::Ptr& value, bool suppress_events, const Value& cookie) { ObjectImpl::SetObjectFilter(value, suppress_events, cookie); - CheckObjectFilter(); + UpdateCheckObjectFilterCache(); } void Logger::OnAllConfigLoaded() { ObjectImpl::OnAllConfigLoaded(); m_CalledOnAllConfigLoaded.store(true); - CheckObjectFilter(); + UpdateCheckObjectFilterCache(); } void Logger::Stop(bool runtimeRemoved) @@ -297,7 +297,7 @@ void Logger::UpdateMinLogSeverity() m_MinLogSeverity.store(result); } -void Logger::CheckObjectFilter() +void Logger::UpdateCheckObjectFilterCache() { if (!m_CalledOnAllConfigLoaded.load()) { return; @@ -306,27 +306,43 @@ void Logger::CheckObjectFilter() auto filter (GetObjectFilter()); if (!filter) { + ObjectLock lock (this); + m_ObjectFilterCache.clear(); return; } - ObjectLock lock (filter); + std::vector allObjects; - for (auto& kv : filter) { - auto type (Type::GetByName(kv.first)); - auto ctype (dynamic_cast(type.get())); - Array::Ptr objects = kv.second; + { + ObjectLock lock (filter); + + for (auto& kv : filter) { + auto type (Type::GetByName(kv.first)); + auto ctype (dynamic_cast(type.get())); + Array::Ptr objects = kv.second; - if (ctype && objects) { - ObjectLock lock (objects); + if (ctype && objects) { + ObjectLock lock (objects); + + for (String name : objects) { + auto object (ctype->GetObject(name)); - for (String object : objects) { - if (!ctype->GetObject(object)) { - Log(LogWarning, GetReflectionType()->GetName()) - << "Missing " << kv.first << " '" << object << "' in object filter of '" << GetName() << "'."; + if (object) { + allObjects.emplace_back(object.get()); + } else { + Log(LogWarning, GetReflectionType()->GetName()) + << "Missing " << kv.first << " '" << name << "' in name filter of '" << GetName() << "'."; + } } } } } + + std::sort(allObjects.begin(), allObjects.end()); + + ObjectLock lock (this); + + m_ObjectFilterCache.swap(allObjects); } Log::Log(LogSeverity severity, String facility, const String& message) diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index cdb4e39c13a..5d140380c10 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -8,6 +8,7 @@ #include "base/logger-ti.hpp" #include #include +#include namespace icinga { @@ -99,7 +100,7 @@ class Logger : public ObjectImpl private: static void UpdateMinLogSeverity(); - void CheckObjectFilter(); + void UpdateCheckObjectFilterCache(); static std::mutex m_Mutex; static std::set m_Loggers; @@ -111,6 +112,7 @@ class Logger : public ObjectImpl static Atomic m_MinLogSeverity; Atomic m_CalledOnAllConfigLoaded {false}; + std::vector m_ObjectFilterCache; }; class Log From 7914d8e2f5e9e2459547b68f1341d1cff7ab24a8 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 17:31:15 +0200 Subject: [PATCH 04/15] Introduce ObjectImpl#GetParentsAffectingLogging() --- tools/mkclass/class_lexer.ll | 1 + tools/mkclass/classcompiler.cpp | 81 +++++++++++++++++++++++++++++++++ tools/mkclass/classcompiler.hpp | 1 + 3 files changed, 83 insertions(+) diff --git a/tools/mkclass/class_lexer.ll b/tools/mkclass/class_lexer.ll index 217ca492cb0..06a1291fc2b 100644 --- a/tools/mkclass/class_lexer.ll +++ b/tools/mkclass/class_lexer.ll @@ -135,6 +135,7 @@ deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; } get_virtual { yylval->num = FAGetVirtual; return T_FIELD_ATTRIBUTE; } set_virtual { yylval->num = FASetVirtual; return T_FIELD_ATTRIBUTE; } signal_with_old_value { yylval->num = FASignalWithOldValue; return T_FIELD_ATTRIBUTE; } +parent_affecting_logging { yylval->num = FAParentAffectingLogging; return T_FIELD_ATTRIBUTE; } virtual { yylval->num = FAGetVirtual | FASetVirtual; return T_FIELD_ATTRIBUTE; } navigation { return T_NAVIGATION; } validator { return T_VALIDATOR; } diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index 3a49576b87d..3c019cedce8 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -1078,6 +1078,87 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) << field.GetFriendlyName() << "ChangedWithOldValue;" << std::endl << std::endl; } } + + /* override ConfigObject#GetParentsAffectingLogging() */ + + bool overrideGetParentsAffectingLogging = klass.Name == "ConfigObject"; + + if (!overrideGetParentsAffectingLogging) { + for (auto& field : klass.Fields) { + if (field.Attributes & FAParentAffectingLogging && (field.Type.IsName || field.Attributes & FANavigation)) { + overrideGetParentsAffectingLogging = true; + break; + } + } + } + + if (overrideGetParentsAffectingLogging) { + m_Header << "protected:" << std::endl << "\t"; + + if (klass.Name == "ConfigObject") { + m_Header << "virtual void GetParentsAffectingLogging(std::vector>& output) const;"; + } else { + m_Header << "void GetParentsAffectingLogging(std::vector& output) const override;"; + } + + m_Header << std::endl; + + m_Impl << "void ObjectImpl<" << klass.Name + << ">::GetParentsAffectingLogging(std::vector& output) const" << std::endl + << "{" << std::endl; + + std::set types; + + for (auto& field : klass.Fields) { + if (field.Attributes & FAParentAffectingLogging && field.Type.IsName && types.emplace(field.Type.TypeName).second) { + m_Impl << "\t" << "static const auto type" << field.Type.TypeName + << " (Type::GetByName(\"" << field.Type.TypeName << "\"));" << std::endl + << "\t" << "static const auto configType" << field.Type.TypeName + << " (dynamic_cast(type" << field.Type.TypeName << ".get()));" << std::endl; + } + } + + if (klass.Name != "ConfigObject") { + m_Impl << std::endl << "\t" << klass.Parent << "::GetParentsAffectingLogging(output);" << std::endl; + } + + for (auto& field : klass.Fields) { + if (field.Attributes & FAParentAffectingLogging && (field.Type.IsName || field.Attributes & FANavigation)) { + m_Impl << std::endl << "\t"; + + if (field.Type.IsName) { + if (field.Type.ArrayRank) { + m_Impl << "auto names" << field.GetFriendlyName() + << " (Get" << field.GetFriendlyName() << "());" << std::endl << std::endl + << "\t" << "if (names" << field.GetFriendlyName() << ") {" << std::endl + << "\t\t" << "ObjectLock lock (names" << field.GetFriendlyName() << ");" << std::endl << std::endl + << "\t\t" << "for (auto& name : names" << field.GetFriendlyName() << ") {" << std::endl + << "\t\t\t" << "auto object (configType" << field.Type.TypeName << "->GetObject(name));" << std::endl << std::endl + << "\t\t\t" << "if (object) {" << std::endl + << "\t\t\t\t" << "output.emplace_back(std::move(object));" << std::endl + << "\t\t\t" << "}" << std::endl + << "\t\t" << "}"; + } else { + m_Impl << "auto object" << field.GetFriendlyName() + << " (configType" << field.Type.TypeName << "->GetObject(Get" + << field.GetFriendlyName() << "()));" << std::endl << std::endl + << "\t" << "if (object" << field.GetFriendlyName() << ") {" << std::endl + << "\t\t" << "output.emplace_back(std::move(object" << field.GetFriendlyName() << "));"; + } + } else { + m_Impl << "auto object" << field.GetFriendlyName() + << " (static_pointer_cast(Navigate" + << field.GetFriendlyName() << "()));" << std::endl << std::endl + << "\t" << "if (object" << field.GetFriendlyName() << ") {" << std::endl + << "\t\t" << "output.emplace_back(std::move(object" << field.GetFriendlyName() << "));"; + } + + m_Impl << std::endl << "\t" << "}" << std::endl; + } + } + + m_Impl << "}" << std::endl << std::endl; + } } if (klass.Name == "ConfigObject") diff --git a/tools/mkclass/classcompiler.hpp b/tools/mkclass/classcompiler.hpp index 0bd789dd313..8befea0b137 100644 --- a/tools/mkclass/classcompiler.hpp +++ b/tools/mkclass/classcompiler.hpp @@ -62,6 +62,7 @@ enum FieldAttribute FASetVirtual = 16384, FAActivationPriority = 32768, FASignalWithOldValue = 65536, + FAParentAffectingLogging = 131072, }; struct FieldType From a3f8d8402748b116f20262fdd377f50c94792411 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 17:59:34 +0200 Subject: [PATCH 05/15] Disallow Downtime#config_owner modification This attribute is used only by ScheduledDowntime anyway and is a relation declarator such as host_name, service_name. --- lib/icinga/downtime.ti | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/icinga/downtime.ti b/lib/icinga/downtime.ti index 21e97313eae..b8885b30c73 100644 --- a/lib/icinga/downtime.ti +++ b/lib/icinga/downtime.ti @@ -72,7 +72,7 @@ class Downtime : ConfigObject < DowntimeNameComposer [no_storage] bool was_cancelled { get {{{ return GetRemoveTime() > 0; }}} }; - [config] String config_owner; + [config, no_user_modify] String config_owner; [config] String config_owner_hash; [config] String authoritative_zone; From 53f881ba1680b406308b82dd9dceb902d4b89427 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 18:31:21 +0200 Subject: [PATCH 06/15] Forbid Zone#endpoints modification The cluster tree can't be runtime-altered anyway. --- lib/remote/zone.ti | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/remote/zone.ti b/lib/remote/zone.ti index 25f6a642dc2..e06d92d3bdc 100644 --- a/lib/remote/zone.ti +++ b/lib/remote/zone.ti @@ -15,7 +15,7 @@ class Zone : ConfigObject }}} }; - [config] array(name(Endpoint)) endpoints (EndpointsRaw); + [config, no_user_modify] array(name(Endpoint)) endpoints (EndpointsRaw); [config] bool global; [no_user_modify, no_storage] array(Value) all_parents { get; From 1ce044c6047254297296943b18db46a58aa1924d Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 18:41:51 +0200 Subject: [PATCH 07/15] parent_affecting_logging: a zone affects everything in it --- lib/base/configobject.ti | 2 +- lib/remote/endpoint.cpp | 6 ++++++ lib/remote/endpoint.hpp | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/base/configobject.ti b/lib/base/configobject.ti index ea67dfa7ba8..177a6f3c00b 100644 --- a/lib/base/configobject.ti +++ b/lib/base/configobject.ti @@ -66,7 +66,7 @@ abstract class ConfigObject : ConfigObjectBase < ConfigType return shortName; }}} }; - [config, no_user_modify] name(Zone) zone (ZoneName); + [config, no_user_modify, parent_affecting_logging] name(Zone) zone (ZoneName); [config, no_user_modify] String package; [config, get_protected, no_user_modify] Array::Ptr templates; [config, no_storage, no_user_modify] Dictionary::Ptr source_location { diff --git a/lib/remote/endpoint.cpp b/lib/remote/endpoint.cpp index e534fc17840..714606ccad7 100644 --- a/lib/remote/endpoint.cpp +++ b/lib/remote/endpoint.cpp @@ -26,6 +26,12 @@ void Endpoint::OnAllConfigLoaded() "' does not belong to a zone.", GetDebugInfo())); } +void Endpoint::GetParentsAffectingLogging(std::vector& output) const +{ + ObjectImpl::GetParentsAffectingLogging(output); + output.emplace_back(GetZone()); +} + void Endpoint::SetCachedZone(const Zone::Ptr& zone) { if (m_Zone) diff --git a/lib/remote/endpoint.hpp b/lib/remote/endpoint.hpp index d641c2c6b8f..2e121d2fb99 100644 --- a/lib/remote/endpoint.hpp +++ b/lib/remote/endpoint.hpp @@ -51,6 +51,7 @@ class Endpoint final : public ObjectImpl protected: void OnAllConfigLoaded() override; + void GetParentsAffectingLogging(std::vector& output) const override; private: mutable std::mutex m_ClientsLock; From 06ea999ba8476179627a3f3ba70766f8cbba05c0 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 18:46:46 +0200 Subject: [PATCH 08/15] parent_affecting_logging: a group affects everything in it --- lib/icinga/host.ti | 2 +- lib/icinga/hostgroup.ti | 2 +- lib/icinga/service.ti | 2 +- lib/icinga/servicegroup.ti | 2 +- lib/icinga/user.ti | 2 +- lib/icinga/usergroup.ti | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/icinga/host.ti b/lib/icinga/host.ti index f6624e30764..f674220fdd3 100644 --- a/lib/icinga/host.ti +++ b/lib/icinga/host.ti @@ -15,7 +15,7 @@ class Host : Checkable load_after Endpoint; load_after Zone; - [config, no_user_modify, required, signal_with_old_value] array(name(HostGroup)) groups { + [config, no_user_modify, required, signal_with_old_value, parent_affecting_logging] array(name(HostGroup)) groups { default {{{ return new Array(); }}} }; diff --git a/lib/icinga/hostgroup.ti b/lib/icinga/hostgroup.ti index b679344aabd..600240e8500 100644 --- a/lib/icinga/hostgroup.ti +++ b/lib/icinga/hostgroup.ti @@ -19,7 +19,7 @@ class HostGroup : CustomVarObject }}} }; - [config, no_user_modify] array(name(HostGroup)) groups; + [config, no_user_modify, parent_affecting_logging] array(name(HostGroup)) groups; [config] String notes; [config] String notes_url; [config] String action_url; diff --git a/lib/icinga/service.ti b/lib/icinga/service.ti index 12c2d8c66c9..4be5b4c70a3 100644 --- a/lib/icinga/service.ti +++ b/lib/icinga/service.ti @@ -27,7 +27,7 @@ class Service : Checkable < ServiceNameComposer load_after Host; load_after Zone; - [config, no_user_modify, required, signal_with_old_value] array(name(ServiceGroup)) groups { + [config, no_user_modify, required, signal_with_old_value, parent_affecting_logging] array(name(ServiceGroup)) groups { default {{{ return new Array(); }}} }; diff --git a/lib/icinga/servicegroup.ti b/lib/icinga/servicegroup.ti index 7daf9d419b3..edc1d35b700 100644 --- a/lib/icinga/servicegroup.ti +++ b/lib/icinga/servicegroup.ti @@ -19,7 +19,7 @@ class ServiceGroup : CustomVarObject }}} }; - [config, no_user_modify] array(name(ServiceGroup)) groups; + [config, no_user_modify, parent_affecting_logging] array(name(ServiceGroup)) groups; [config] String notes; [config] String notes_url; [config] String action_url; diff --git a/lib/icinga/user.ti b/lib/icinga/user.ti index 8b8c43a14d4..a89765bc7b0 100644 --- a/lib/icinga/user.ti +++ b/lib/icinga/user.ti @@ -20,7 +20,7 @@ class User : CustomVarObject return displayName; }}} }; - [config, no_user_modify, required, signal_with_old_value] array(name(UserGroup)) groups { + [config, no_user_modify, required, signal_with_old_value, parent_affecting_logging] array(name(UserGroup)) groups { default {{{ return new Array(); }}} }; [config, navigation] name(TimePeriod) period (PeriodRaw) { diff --git a/lib/icinga/usergroup.ti b/lib/icinga/usergroup.ti index e955c5e5ed1..8605cd74e4f 100644 --- a/lib/icinga/usergroup.ti +++ b/lib/icinga/usergroup.ti @@ -19,7 +19,7 @@ class UserGroup : CustomVarObject }}} }; - [config, no_user_modify] array(name(UserGroup)) groups; + [config, no_user_modify, parent_affecting_logging] array(name(UserGroup)) groups; }; } From 67fb214acddd8cbd6b81e4388f5db494b527c86f Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 18:52:16 +0200 Subject: [PATCH 09/15] parent_affecting_logging: a config object affects everything applied to it See the currently supported apply rules. --- lib/icinga/dependency.ti | 4 ++-- lib/icinga/notification.ti | 4 ++-- lib/icinga/scheduleddowntime.ti | 4 ++-- lib/icinga/service.ti | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/icinga/dependency.ti b/lib/icinga/dependency.ti index 41de7ba23cf..08d97fa7d90 100644 --- a/lib/icinga/dependency.ti +++ b/lib/icinga/dependency.ti @@ -23,13 +23,13 @@ class Dependency : CustomVarObject < DependencyNameComposer load_after Host; load_after Service; - [config, no_user_modify, required, navigation(child_host)] name(Host) child_host_name { + [config, no_user_modify, required, navigation(child_host), parent_affecting_logging] name(Host) child_host_name { navigate {{{ return Host::GetByName(GetChildHostName()); }}} }; - [config, no_user_modify, navigation(child_service)] String child_service_name { + [config, no_user_modify, navigation(child_service), parent_affecting_logging] String child_service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetChildHostName(), oldValue); diff --git a/lib/icinga/notification.ti b/lib/icinga/notification.ti index 48536075748..40bafd34f4f 100644 --- a/lib/icinga/notification.ti +++ b/lib/icinga/notification.ti @@ -43,12 +43,12 @@ class Notification : CustomVarObject < NotificationNameComposer [no_user_view, no_user_modify] int type_filter_real (TypeFilter); [config] array(Value) states; [no_user_view, no_user_modify] int state_filter_real (StateFilter); - [config, no_user_modify, protected, required, navigation(host)] name(Host) host_name { + [config, no_user_modify, protected, required, navigation(host), parent_affecting_logging] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; - [config, protected, no_user_modify, navigation(service)] String service_name { + [config, protected, no_user_modify, navigation(service), parent_affecting_logging] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); diff --git a/lib/icinga/scheduleddowntime.ti b/lib/icinga/scheduleddowntime.ti index 1653f27e74d..e70992d2d03 100644 --- a/lib/icinga/scheduleddowntime.ti +++ b/lib/icinga/scheduleddowntime.ti @@ -26,12 +26,12 @@ class ScheduledDowntime : CustomVarObject < ScheduledDowntimeNameComposer load_after Host; load_after Service; - [config, protected, no_user_modify, required, navigation(host)] name(Host) host_name { + [config, protected, no_user_modify, required, navigation(host), parent_affecting_logging] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; - [config, protected, no_user_modify, navigation(service)] String service_name { + [config, protected, no_user_modify, navigation(service), parent_affecting_logging] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); diff --git a/lib/icinga/service.ti b/lib/icinga/service.ti index 4be5b4c70a3..ea9989e0cde 100644 --- a/lib/icinga/service.ti +++ b/lib/icinga/service.ti @@ -40,7 +40,7 @@ class Service : Checkable < ServiceNameComposer return displayName; }}} }; - [config, no_user_modify, required] name(Host) host_name; + [config, no_user_modify, required, parent_affecting_logging] name(Host) host_name; [no_storage, navigation] Host::Ptr host { get; navigate {{{ From d98bb316ed6d64e9da21f5e6335ba84a747f14e7 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Aug 2023 18:57:51 +0200 Subject: [PATCH 10/15] parent_affecting_logging: a config object affects everything functionally depending on it --- lib/icinga/comment.ti | 4 ++-- lib/icinga/dependency.ti | 4 ++-- lib/icinga/downtime.cpp | 11 +++++++++++ lib/icinga/downtime.hpp | 1 + lib/icinga/downtime.ti | 4 ++-- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/icinga/comment.ti b/lib/icinga/comment.ti index b8ad6f7f252..74c2a24cef1 100644 --- a/lib/icinga/comment.ti +++ b/lib/icinga/comment.ti @@ -34,12 +34,12 @@ class Comment : ConfigObject < CommentNameComposer load_after Host; load_after Service; - [config, no_user_modify, protected, required, navigation(host)] name(Host) host_name { + [config, no_user_modify, protected, required, navigation(host), parent_affecting_logging] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; - [config, no_user_modify, protected, navigation(service)] String service_name { + [config, no_user_modify, protected, navigation(service), parent_affecting_logging] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); diff --git a/lib/icinga/dependency.ti b/lib/icinga/dependency.ti index 08d97fa7d90..7cba87d5b9e 100644 --- a/lib/icinga/dependency.ti +++ b/lib/icinga/dependency.ti @@ -50,13 +50,13 @@ class Dependency : CustomVarObject < DependencyNameComposer }}} }; - [config, no_user_modify, required, navigation(parent_host)] name(Host) parent_host_name { + [config, no_user_modify, required, navigation(parent_host), parent_affecting_logging] name(Host) parent_host_name { navigate {{{ return Host::GetByName(GetParentHostName()); }}} }; - [config, no_user_modify, navigation(parent_service)] String parent_service_name { + [config, no_user_modify, navigation(parent_service), parent_affecting_logging] String parent_service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetParentHostName(), oldValue); diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index 2178953f3d1..e8a619c85fc 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -161,6 +161,17 @@ void Downtime::Stop(bool runtimeRemoved) ObjectImpl::Stop(runtimeRemoved); } +void Downtime::GetParentsAffectingLogging(std::vector& output) const +{ + ObjectImpl::GetParentsAffectingLogging(output); + + auto object (ConfigObject::GetObject(GetConfigOwner())); + + if (object) { + output.emplace_back(std::move(object)); + } +} + void Downtime::Pause() { if (m_CleanupTimer) { diff --git a/lib/icinga/downtime.hpp b/lib/icinga/downtime.hpp index 15aa0af5d3d..fc2bbf2ba30 100644 --- a/lib/icinga/downtime.hpp +++ b/lib/icinga/downtime.hpp @@ -71,6 +71,7 @@ class Downtime final : public ObjectImpl protected: void Start(bool runtimeCreated) override; void Stop(bool runtimeRemoved) override; + void GetParentsAffectingLogging(std::vector& output) const override; void Pause() override; void Resume() override; diff --git a/lib/icinga/downtime.ti b/lib/icinga/downtime.ti index b8885b30c73..1e8690ab122 100644 --- a/lib/icinga/downtime.ti +++ b/lib/icinga/downtime.ti @@ -25,12 +25,12 @@ class Downtime : ConfigObject < DowntimeNameComposer load_after Host; load_after Service; - [config, no_user_modify, required, navigation(host)] name(Host) host_name { + [config, no_user_modify, required, navigation(host), parent_affecting_logging] name(Host) host_name { navigate {{{ return Host::GetByName(GetHostName()); }}} }; - [config, no_user_modify, navigation(service)] String service_name { + [config, no_user_modify, navigation(service), parent_affecting_logging] String service_name { track {{{ if (!oldValue.IsEmpty()) { Service::Ptr service = Service::GetByNamePair(GetHostName(), oldValue); From 2a14803897ab3eef9f53c28cd19d0c17c1020d02 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 15 Aug 2023 11:17:40 +0200 Subject: [PATCH 11/15] ConfigObject#OnAllConfigLoaded(): build m_AllParentsAffectingLogging cache recursively from ConfigObject#GetParentsAffectingLogging(). --- lib/base/configobject.cpp | 12 ++++++++++++ lib/base/configobject.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index 4317771d1f8..fee6e43743c 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -419,6 +419,18 @@ void ConfigObject::OnAllConfigLoaded() if (!zoneName.IsEmpty()) m_Zone = ctype->GetObject(zoneName); + + std::vector toDo {this}; + + do { + auto current (toDo.back()); + + toDo.pop_back(); + + if (m_AllParentsAffectingLogging.emplace(current.get()).second) { + current->GetParentsAffectingLogging(toDo); + } + } while (!toDo.empty()); } void ConfigObject::CreateChildObjects(const Type::Ptr& childType) diff --git a/lib/base/configobject.hpp b/lib/base/configobject.hpp index 5596363703c..a091c0a3a8c 100644 --- a/lib/base/configobject.hpp +++ b/lib/base/configobject.hpp @@ -9,6 +9,7 @@ #include "base/type.hpp" #include "base/dictionary.hpp" #include +#include namespace icinga { @@ -81,6 +82,7 @@ class ConfigObject : public ObjectImpl private: ConfigObject::Ptr m_Zone; + std::set m_AllParentsAffectingLogging; static void RestoreObject(const String& message, int attributeTypes); }; From eb1261ec8e9b2cd69b0123bc3bbb46ca44acc8dd Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 13:07:37 +0200 Subject: [PATCH 12/15] Merge Log#Log() methods --- lib/base/logger.cpp | 8 ++------ lib/base/logger.hpp | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index d8f4900c264..8cf7a930974 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -346,17 +346,13 @@ void Logger::UpdateCheckObjectFilterCache() } Log::Log(LogSeverity severity, String facility, const String& message) - : Log(severity, std::move(facility)) + : m_Severity(severity), m_Facility(std::move(facility)), m_IsNoOp(severity < Logger::GetMinLogSeverity()) { - if (!m_IsNoOp) { + if (!m_IsNoOp && !message.IsEmpty()) { m_Buffer << message; } } -Log::Log(LogSeverity severity, String facility) - : m_Severity(severity), m_Facility(std::move(facility)), m_IsNoOp(severity < Logger::GetMinLogSeverity()) -{ } - /** * Writes the message to the application's log. */ diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index 5d140380c10..c38e44477b4 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -122,9 +122,7 @@ class Log Log(const Log& other) = delete; Log& operator=(const Log& rhs) = delete; - Log(LogSeverity severity, String facility, const String& message); - Log(LogSeverity severity, String facility); - + Log(LogSeverity severity, String facility, const String& message = String()); ~Log(); template From 73e9b524278ccf95a91216142bba27a1aba1cbf2 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 13:32:14 +0200 Subject: [PATCH 13/15] Log#Log(): require passing one involved object --- lib/base/logger.cpp | 5 +++-- lib/base/logger.hpp | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 8cf7a930974..0777b78cd6f 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -345,8 +345,9 @@ void Logger::UpdateCheckObjectFilterCache() m_ObjectFilterCache.swap(allObjects); } -Log::Log(LogSeverity severity, String facility, const String& message) - : m_Severity(severity), m_Facility(std::move(facility)), m_IsNoOp(severity < Logger::GetMinLogSeverity()) +Log::Log(LogSeverity severity, String facility, const ConfigObject::Ptr& involved, const String& message) + : m_Severity(severity), m_Facility(std::move(facility)), + m_Involved(involved), m_IsNoOp(severity < Logger::GetMinLogSeverity()) { if (!m_IsNoOp && !message.IsEmpty()) { m_Buffer << message; diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index c38e44477b4..fec06dcb668 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -5,6 +5,7 @@ #include "base/atomic.hpp" #include "base/i2-base.hpp" +#include "base/configobject.hpp" #include "base/logger-ti.hpp" #include #include @@ -122,7 +123,7 @@ class Log Log(const Log& other) = delete; Log& operator=(const Log& rhs) = delete; - Log(LogSeverity severity, String facility, const String& message = String()); + Log(LogSeverity severity, String facility, const ConfigObject::Ptr& involved, const String& message = String()); ~Log(); template @@ -137,6 +138,7 @@ class Log private: LogSeverity m_Severity; String m_Facility; + ConfigObject::Ptr m_Involved; std::ostringstream m_Buffer; bool m_IsNoOp; }; From 0cecad622fd4fde27592707080758f0375ca0715 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 11 Aug 2023 13:34:04 +0200 Subject: [PATCH 14/15] [TODO: REVERT] Repair GHA for now --- lib/base/logger.cpp | 5 ++--- lib/base/logger.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 0777b78cd6f..8cf7a930974 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -345,9 +345,8 @@ void Logger::UpdateCheckObjectFilterCache() m_ObjectFilterCache.swap(allObjects); } -Log::Log(LogSeverity severity, String facility, const ConfigObject::Ptr& involved, const String& message) - : m_Severity(severity), m_Facility(std::move(facility)), - m_Involved(involved), m_IsNoOp(severity < Logger::GetMinLogSeverity()) +Log::Log(LogSeverity severity, String facility, const String& message) + : m_Severity(severity), m_Facility(std::move(facility)), m_IsNoOp(severity < Logger::GetMinLogSeverity()) { if (!m_IsNoOp && !message.IsEmpty()) { m_Buffer << message; diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index fec06dcb668..d005bd22f36 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -123,7 +123,7 @@ class Log Log(const Log& other) = delete; Log& operator=(const Log& rhs) = delete; - Log(LogSeverity severity, String facility, const ConfigObject::Ptr& involved, const String& message = String()); + Log(LogSeverity severity, String facility, const String& message = String()); ~Log(); template From 8c3bfd0f50968e3fd32aeb162dc0aa943eb3a121 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 15 Aug 2023 11:53:25 +0200 Subject: [PATCH 15/15] Log#~Log(): skip messages based on Logger#m_ObjectFilterCache & ConfigObject#m_AllParentsAffectingLogging If Logger#object_filter is set, but doesn't intersect with ConfigObject#m_AllParentsAffectingLogging, drop the message. --- lib/base/configobject.cpp | 14 +++++++++++++- lib/base/configobject.hpp | 8 +++++++- lib/base/logger.cpp | 30 +++++++++++++++++++++++++++--- lib/base/logger.hpp | 5 +++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index fee6e43743c..337d4dedae9 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -427,10 +427,22 @@ void ConfigObject::OnAllConfigLoaded() toDo.pop_back(); - if (m_AllParentsAffectingLogging.emplace(current.get()).second) { + if (m_AllParentsAffectingLogging.Data.emplace(current.get()).second) { current->GetParentsAffectingLogging(toDo); } } while (!toDo.empty()); + + m_AllParentsAffectingLogging.Frozen.store(true); +} + +const std::set& ConfigObject::GetAllParentsAffectingLogging() const +{ + if (m_AllParentsAffectingLogging.Frozen.load(std::memory_order_relaxed)) { + return m_AllParentsAffectingLogging.Data; + } + + static const std::set fallback; + return fallback; } void ConfigObject::CreateChildObjects(const Type::Ptr& childType) diff --git a/lib/base/configobject.hpp b/lib/base/configobject.hpp index a091c0a3a8c..bc68a0a3b92 100644 --- a/lib/base/configobject.hpp +++ b/lib/base/configobject.hpp @@ -4,6 +4,7 @@ #define CONFIGOBJECT_H #include "base/i2-base.hpp" +#include "base/atomic.hpp" #include "base/configobject-ti.hpp" #include "base/object.hpp" #include "base/type.hpp" @@ -61,6 +62,7 @@ class ConfigObject : public ObjectImpl virtual void OnStateLoaded(); Dictionary::Ptr GetSourceLocation() const override; + const std::set& GetAllParentsAffectingLogging() const; template static intrusive_ptr GetObject(const String& name) @@ -82,7 +84,11 @@ class ConfigObject : public ObjectImpl private: ConfigObject::Ptr m_Zone; - std::set m_AllParentsAffectingLogging; + + struct { + std::set Data; + Atomic Frozen {false}; + } m_AllParentsAffectingLogging; static void RestoreObject(const String& message, int attributeTypes); }; diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 8cf7a930974..9cfa010e1e4 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -14,7 +14,9 @@ #endif /* _WIN32 */ #include #include +#include #include +#include using namespace icinga; @@ -387,11 +389,33 @@ Log::~Log() for (const Logger::Ptr& logger : Logger::GetLoggers()) { ObjectLock llock(logger); - if (!logger->IsActive()) + if (!logger->IsActive()) { continue; + } + + if (entry.Severity < logger->GetMinSeverity()) { + continue; + } + + auto filter (logger->GetObjectFilter()); + + if (logger->GetObjectFilter()) { + if (!m_Involved) { + continue; + } + + auto& allowed (logger->GetObjectFilterCache()); + auto& indirect (m_Involved->GetAllParentsAffectingLogging()); + std::vector intersection; + + std::set_intersection(allowed.begin(), allowed.end(), indirect.begin(), indirect.end(), std::back_inserter(intersection)); + + if (intersection.empty()) { + continue; + } + } - if (entry.Severity >= logger->GetMinSeverity()) - logger->ProcessLogEntry(entry); + logger->ProcessLogEntry(entry); #ifdef I2_DEBUG /* I2_DEBUG */ /* Always flush, don't depend on the timer. Enable this for development sprints on Linux/macOS only. Windows crashes. */ diff --git a/lib/base/logger.hpp b/lib/base/logger.hpp index d005bd22f36..027817164cc 100644 --- a/lib/base/logger.hpp +++ b/lib/base/logger.hpp @@ -93,6 +93,11 @@ class Logger : public ObjectImpl void SetObjectFilter(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty) override; void OnAllConfigLoaded() override; + inline const std::vector& GetObjectFilterCache() const + { + return m_ObjectFilterCache; + } + protected: void Start(bool runtimeCreated) override; void Stop(bool runtimeRemoved) override;