From 3ef0917dd9b069301931716ab1d3a70dc479f26b Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 14 Nov 2022 17:21:15 +0100 Subject: [PATCH] Mismatching apply rules and parent objects: give time by rule and per object --- lib/base/configobject.cpp | 2 +- lib/base/configobject.hpp | 4 +- lib/config/applyrule.cpp | 41 ++++++++++++++- lib/config/applyrule.hpp | 72 ++++++++++++++++++++------ lib/config/configitem.cpp | 26 +++++++--- lib/config/configitem.hpp | 2 +- lib/icinga/dependency-apply.cpp | 46 ++++++++-------- lib/icinga/dependency.hpp | 9 ++-- lib/icinga/host.cpp | 10 ++-- lib/icinga/host.hpp | 2 +- lib/icinga/notification-apply.cpp | 48 ++++++++--------- lib/icinga/notification.hpp | 9 ++-- lib/icinga/scheduleddowntime-apply.cpp | 48 ++++++++--------- lib/icinga/scheduleddowntime.hpp | 9 ++-- lib/icinga/service-apply.cpp | 44 ++++++++-------- lib/icinga/service.cpp | 8 +-- lib/icinga/service.hpp | 9 ++-- 17 files changed, 241 insertions(+), 148 deletions(-) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index 6f5973570..b2c0b05d5 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -421,7 +421,7 @@ void ConfigObject::OnAllConfigLoaded() m_Zone = ctype->GetObject(zoneName); } -void ConfigObject::CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void ConfigObject::CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { /* Nothing to do here. */ } diff --git a/lib/base/configobject.hpp b/lib/base/configobject.hpp index 59628de4f..6a5e5b7d8 100644 --- a/lib/base/configobject.hpp +++ b/lib/base/configobject.hpp @@ -14,7 +14,7 @@ namespace icinga { class ConfigType; -class TotalTimeSpentOnApplyMismatches; +class TimeSpentOnApplyMismatches; /** * A dynamic object that can be instantiated from the configuration file. @@ -56,7 +56,7 @@ public: virtual void Resume(); virtual void OnConfigLoaded(); - virtual void CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); + virtual void CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); virtual void OnAllConfigLoaded(); virtual void OnStateLoaded(); diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index 2693b6fcc..fe16782ae 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -2,6 +2,7 @@ #include "config/applyrule.hpp" #include "base/logger.hpp" +#include #include #include @@ -198,9 +199,45 @@ void ApplyRule::CheckMatches(const ApplyRule::Ptr& rule, Type* sourceType, bool } } -double TotalTimeSpentOnApplyMismatches::AsSeconds() const +static double MonotonicTicksToSeconds(std::chrono::steady_clock::rep ticks) { using namespace std::chrono; - return duration(steady_clock::duration(m_MonotonicTicks.load())).count(); + return duration(steady_clock::duration(ticks)).count(); +} + +double TimeSpentOnApplyMismatches::GetTotal() +{ + std::chrono::steady_clock::rep total = 0; + + { + boost::shared_lock lock (m_Mutex); + + for (auto& kv : m_ByRule) { + total += kv.second.MonotonicTicks.load(); + } + } + + return MonotonicTicksToSeconds(total); +} + +std::vector TimeSpentOnApplyMismatches::GetWorstRules() +{ + std::vector worstRules; + + { + boost::shared_lock lock (m_Mutex); + + for (auto& kv : m_ByRule) { + worstRules.push_back({ + kv.first, kv.second.ParentObjects.load(),MonotonicTicksToSeconds(kv.second.MonotonicTicks.load()) + }); + } + } + + std::sort(worstRules.begin(), worstRules.end(), [](const BadRule& lhs, const BadRule& rhs) { + return lhs.SpentTime / lhs.ParentObjects > rhs.SpentTime / rhs.ParentObjects; + }); + + return worstRules; } diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index 4b4d8f515..d8efa3d15 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -5,12 +5,18 @@ #include "config/i2-config.hpp" #include "config/expression.hpp" -#include "base/atomic.hpp" #include "base/debuginfo.hpp" #include "base/shared-object.hpp" #include "base/type.hpp" +#include +#include +#include #include +#include +#include #include +#include +#include namespace icinga { @@ -114,29 +120,45 @@ private: class BenchmarkApplyRuleEvaluation; -class TotalTimeSpentOnApplyMismatches +class TimeSpentOnApplyMismatches { friend BenchmarkApplyRuleEvaluation; public: - TotalTimeSpentOnApplyMismatches() = default; - TotalTimeSpentOnApplyMismatches(const TotalTimeSpentOnApplyMismatches&) = delete; - TotalTimeSpentOnApplyMismatches(TotalTimeSpentOnApplyMismatches&&) = delete; - TotalTimeSpentOnApplyMismatches& operator=(const TotalTimeSpentOnApplyMismatches&) = delete; - TotalTimeSpentOnApplyMismatches& operator=(TotalTimeSpentOnApplyMismatches&&) = delete; + struct BadRule + { + ApplyRule::Ptr Rule; + uint_fast32_t ParentObjects; + double SpentTime; + }; - double AsSeconds() const; + TimeSpentOnApplyMismatches() = default; + TimeSpentOnApplyMismatches(const TimeSpentOnApplyMismatches&) = delete; + TimeSpentOnApplyMismatches(TimeSpentOnApplyMismatches&&) = delete; + TimeSpentOnApplyMismatches& operator=(const TimeSpentOnApplyMismatches&) = delete; + TimeSpentOnApplyMismatches& operator=(TimeSpentOnApplyMismatches&&) = delete; + + double GetTotal(); + std::vector GetWorstRules(); private: - Atomic m_MonotonicTicks {0}; + struct PerRule + { + std::atomic ParentObjects; + std::atomic MonotonicTicks; + }; + + boost::shared_mutex m_Mutex; + std::map m_ByRule; }; class BenchmarkApplyRuleEvaluation { public: - inline BenchmarkApplyRuleEvaluation(TotalTimeSpentOnApplyMismatches& totalTimeSpentOnMismatches, const bool& ruleMatched) - : m_TotalTimeSpentOnMismatches(totalTimeSpentOnMismatches), - m_RuleMatched(ruleMatched), m_Start(std::chrono::steady_clock::now()) + inline BenchmarkApplyRuleEvaluation(TimeSpentOnApplyMismatches& timeSpentOnMismatches, + const ApplyRule::Ptr& rule, const bool& ruleMatched) + : m_TimeSpentOnMismatches(timeSpentOnMismatches), m_Rule(rule), + m_RuleMatched(ruleMatched), m_Start(std::chrono::steady_clock::now()) { } BenchmarkApplyRuleEvaluation(const BenchmarkApplyRuleEvaluation&) = delete; @@ -147,14 +169,32 @@ public: inline ~BenchmarkApplyRuleEvaluation() { if (!m_RuleMatched) { - m_TotalTimeSpentOnMismatches.m_MonotonicTicks.fetch_add( - (std::chrono::steady_clock::now() - m_Start).count() - ); + auto diff (std::chrono::steady_clock::now() - m_Start); + TimeSpentOnApplyMismatches::PerRule* total = nullptr; + auto& mtbr (m_TimeSpentOnMismatches.m_ByRule); + + { + boost::shared_lock lock (m_TimeSpentOnMismatches.m_Mutex); + auto perRule (mtbr.find(m_Rule)); + + if (perRule != mtbr.end()) { + total = &perRule->second; + } + } + + if (!total) { + boost::unique_lock lock (m_TimeSpentOnMismatches.m_Mutex); + total = &mtbr[m_Rule]; + } + + total->ParentObjects.fetch_add(1); + total->MonotonicTicks.fetch_add(diff.count()); } } private: - TotalTimeSpentOnApplyMismatches& m_TotalTimeSpentOnMismatches; + TimeSpentOnApplyMismatches& m_TimeSpentOnMismatches; + const ApplyRule::Ptr& m_Rule; const bool& m_RuleMatched; std::chrono::steady_clock::time_point m_Start; }; diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index b4d44e975..a15e4fcf4 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -387,7 +387,7 @@ ConfigItem::Ptr ConfigItem::GetByTypeAndName(const Type::Ptr& type, const String bool ConfigItem::CommitNewItems( const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches ) { typedef std::pair ItemPair; @@ -598,14 +598,14 @@ bool ConfigItem::CommitNewItems( auto items (itemsByType.find(loadDep)); if (items != itemsByType.end()) { - upq.ParallelFor(items->second, [&type, ¬ified_items, &totalTimeSpentOnApplyMismatches](const ItemPair& ip) { + upq.ParallelFor(items->second, [&type, ¬ified_items, &timeSpentOnApplyMismatches](const ItemPair& ip) { const ConfigItem::Ptr& item = ip.first; if (!item->m_Object) return; ActivationScope ascope(item->m_ActivationContext); - item->m_Object->CreateChildObjects(type, totalTimeSpentOnApplyMismatches); + item->m_Object->CreateChildObjects(type, timeSpentOnApplyMismatches); notified_items++; }); } @@ -623,7 +623,7 @@ bool ConfigItem::CommitNewItems( return false; // Make sure to activate any additionally generated items - if (!CommitNewItems(context, upq, newItems, totalTimeSpentOnApplyMismatches)) + if (!CommitNewItems(context, upq, newItems, timeSpentOnApplyMismatches)) return false; } } @@ -636,9 +636,9 @@ bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& u if (!silent) Log(LogInformation, "ConfigItem", "Committing config item(s)."); - TotalTimeSpentOnApplyMismatches totalTimeSpentOnApplyMismatches; + TimeSpentOnApplyMismatches timeSpentOnApplyMismatches; - if (!CommitNewItems(context, upq, newItems, totalTimeSpentOnApplyMismatches)) { + if (!CommitNewItems(context, upq, newItems, timeSpentOnApplyMismatches)) { upq.ReportExceptions("config"); for (const ConfigItem::Ptr& item : newItems) { @@ -652,11 +652,23 @@ bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& u if (!silent) { Log(LogNotice, "ConfigItem") - << "Spent " << totalTimeSpentOnApplyMismatches.AsSeconds() + << "Spent " << timeSpentOnApplyMismatches.GetTotal() << " seconds on evaluating mismatching apply rules and parent objects." << " (This summary isn't aware of apply rules being evaluated in parallel." << " Therefore consider dividing the number by amount of CPU cores according to htop.)"; + if (LogDebug >= Logger::GetMinLogSeverity()) { + for (auto& perRule: timeSpentOnApplyMismatches.GetWorstRules()) { + std::ostringstream oss; + ShowCodeLocation(oss, perRule.Rule->GetDebugInfo()); + + Log(LogDebug, "ConfigItem") + << "Spent " << (perRule.SpentTime * 1000 / perRule.ParentObjects) + << "ms on evaluating apply rule per mismatching parent object (total: " + << (perRule.SpentTime * 1000) << "ms): " << oss.str(); + } + } + /* log stats for external parsers */ typedef std::map ItemCountMap; ItemCountMap itemCounts; diff --git a/lib/config/configitem.hpp b/lib/config/configitem.hpp index bdb464165..540cf0146 100644 --- a/lib/config/configitem.hpp +++ b/lib/config/configitem.hpp @@ -101,7 +101,7 @@ private: static bool CommitNewItems( const ActivationContext::Ptr& context, WorkQueue& upq, std::vector& newItems, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches ); }; diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 88a6d56fb..1ed9ea9b1 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -62,12 +62,12 @@ bool Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, cons return true; } -bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule& rule, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter) +bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyRule::Ptr& rule, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter) { bool match = false; - BenchmarkApplyRuleEvaluation bare (totalTimeSpentOnApplyMismatches, match); + BenchmarkApplyRuleEvaluation bare (timeSpentOnApplyMismatches, rule, match); - auto& di (rule.GetDebugInfo()); + auto& di (rule->GetDebugInfo()); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; @@ -75,11 +75,11 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR ScriptFrame frame (false); - if (rule.GetScope() || rule.GetFTerm()) { + if (rule->GetScope() || rule->GetFTerm()) { frame.Locals = new Dictionary(); - if (rule.GetScope()) { - rule.GetScope()->CopyTo(frame.Locals); + if (rule->GetScope()) { + rule->GetScope()->CopyTo(frame.Locals); } checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); @@ -88,80 +88,80 @@ bool Dependency::EvaluateApplyRule(const Checkable::Ptr& checkable, const ApplyR frame.Locals = checkable->GetFrozenLocalsForApply(); } - if (rule.GetFTerm()) { + if (rule->GetFTerm()) { Value vinstances; try { - vinstances = rule.GetFTerm()->Evaluate(frame); + vinstances = rule->GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } if (vinstances.IsObjectType()) { - if (!rule.GetFVVar().IsEmpty()) + if (!rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { - String name = rule.GetName(); + String name = rule->GetName(); - frame.Locals->Set(rule.GetFKVar(), instance, true); + frame.Locals->Set(rule->GetFKVar(), instance, true); name += instance; - if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, name, frame, *rule, skipFilter)) match = true; } } else if (vinstances.IsObjectType()) { - if (rule.GetFVVar().IsEmpty()) + if (rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first, true); - frame.Locals->Set(rule.GetFVVar(), kv.second, true); + frame.Locals->Set(rule->GetFKVar(), kv.first, true); + frame.Locals->Set(rule->GetFVVar(), kv.second, true); - if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, rule->GetName() + kv.first, frame, *rule, skipFilter)) match = true; } } - } else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) { + } else if (EvaluateApplyRuleInstance(checkable, rule->GetName(), frame, *rule, skipFilter)) { match = true; } return match; } -void Dependency::EvaluateApplyRules(const Host::Ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Dependency::EvaluateApplyRules(const Host::Ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(Dependency::TypeInstance, Host::TypeInstance)) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedHostRules(Dependency::TypeInstance, host->GetName())) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } -void Dependency::EvaluateApplyRules(const Service::Ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Dependency::EvaluateApplyRules(const Service::Ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(Dependency::TypeInstance, Service::TypeInstance)) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedServiceRules(Dependency::TypeInstance, service->GetHost()->GetName(), service->GetShortName())) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } diff --git a/lib/icinga/dependency.hpp b/lib/icinga/dependency.hpp index d61ec574e..da4ba09d5 100644 --- a/lib/icinga/dependency.hpp +++ b/lib/icinga/dependency.hpp @@ -3,6 +3,7 @@ #ifndef DEPENDENCY_H #define DEPENDENCY_H +#include "config/applyrule.hpp" #include "icinga/i2-icinga.hpp" #include "icinga/dependency-ti.hpp" @@ -34,8 +35,8 @@ public: void ValidateStates(const Lazy& lvalue, const ValidationUtils& utils) override; - static void EvaluateApplyRules(const intrusive_ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); - static void EvaluateApplyRules(const intrusive_ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); /* Note: Only use them for unit test mocks. Prefer OnConfigLoaded(). */ void SetParent(intrusive_ptr parent); @@ -53,8 +54,8 @@ private: static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule, bool skipFilter); static bool EvaluateApplyRule( - const Checkable::Ptr& checkable, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter = false + const Checkable::Ptr& checkable, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter = false ); }; diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 6199eda61..db7b20d00 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -47,19 +47,19 @@ void Host::OnAllConfigLoaded() } } -void Host::CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Host::CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { if (childType == ScheduledDowntime::TypeInstance) - ScheduledDowntime::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + ScheduledDowntime::EvaluateApplyRules(this, timeSpentOnApplyMismatches); if (childType == Notification::TypeInstance) - Notification::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + Notification::EvaluateApplyRules(this, timeSpentOnApplyMismatches); if (childType == Dependency::TypeInstance) - Dependency::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + Dependency::EvaluateApplyRules(this, timeSpentOnApplyMismatches); if (childType == Service::TypeInstance) - Service::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + Service::EvaluateApplyRules(this, timeSpentOnApplyMismatches); } void Host::Stop(bool runtimeRemoved) diff --git a/lib/icinga/host.hpp b/lib/icinga/host.hpp index efc2ef0c6..013bb6739 100644 --- a/lib/icinga/host.hpp +++ b/lib/icinga/host.hpp @@ -55,7 +55,7 @@ public: protected: void Stop(bool runtimeRemoved) override; - void CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) override; + void CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) override; Dictionary::Ptr MakeLocalsForApply() override; diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index af38e3570..9f423b088 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -62,14 +62,14 @@ bool Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, co } bool Notification::EvaluateApplyRule( - const Checkable::Ptr& checkable, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter + const Checkable::Ptr& checkable, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter ) { bool match = false; - BenchmarkApplyRuleEvaluation bare (totalTimeSpentOnApplyMismatches, match); + BenchmarkApplyRuleEvaluation bare (timeSpentOnApplyMismatches, rule, match); - auto& di (rule.GetDebugInfo()); + auto& di (rule->GetDebugInfo()); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; @@ -77,11 +77,11 @@ bool Notification::EvaluateApplyRule( ScriptFrame frame (false); - if (rule.GetScope() || rule.GetFTerm()) { + if (rule->GetScope() || rule->GetFTerm()) { frame.Locals = new Dictionary(); - if (rule.GetScope()) { - rule.GetScope()->CopyTo(frame.Locals); + if (rule->GetScope()) { + rule->GetScope()->CopyTo(frame.Locals); } checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); @@ -90,81 +90,81 @@ bool Notification::EvaluateApplyRule( frame.Locals = checkable->GetFrozenLocalsForApply(); } - if (rule.GetFTerm()) { + if (rule->GetFTerm()) { Value vinstances; try { - vinstances = rule.GetFTerm()->Evaluate(frame); + vinstances = rule->GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } if (vinstances.IsObjectType()) { - if (!rule.GetFVVar().IsEmpty()) + if (!rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { - String name = rule.GetName(); + String name = rule->GetName(); - frame.Locals->Set(rule.GetFKVar(), instance, true); + frame.Locals->Set(rule->GetFKVar(), instance, true); name += instance; - if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, name, frame, *rule, skipFilter)) match = true; } } else if (vinstances.IsObjectType()) { - if (rule.GetFVVar().IsEmpty()) + if (rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first, true); - frame.Locals->Set(rule.GetFVVar(), kv.second, true); + frame.Locals->Set(rule->GetFKVar(), kv.first, true); + frame.Locals->Set(rule->GetFVVar(), kv.second, true); - if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, rule->GetName() + kv.first, frame, *rule, skipFilter)) match = true; } } - } else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) { + } else if (EvaluateApplyRuleInstance(checkable, rule->GetName(), frame, *rule, skipFilter)) { match = true; } return match; } -void Notification::EvaluateApplyRules(const Host::Ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Notification::EvaluateApplyRules(const Host::Ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(Notification::TypeInstance, Host::TypeInstance)) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedHostRules(Notification::TypeInstance, host->GetName())) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } -void Notification::EvaluateApplyRules(const Service::Ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Notification::EvaluateApplyRules(const Service::Ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(Notification::TypeInstance, Service::TypeInstance)) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedServiceRules(Notification::TypeInstance, service->GetHost()->GetName(), service->GetShortName())) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } diff --git a/lib/icinga/notification.hpp b/lib/icinga/notification.hpp index 7702311af..b76c2570d 100644 --- a/lib/icinga/notification.hpp +++ b/lib/icinga/notification.hpp @@ -3,6 +3,7 @@ #ifndef NOTIFICATION_H #define NOTIFICATION_H +#include "config/applyrule.hpp" #include "icinga/i2-icinga.hpp" #include "icinga/notification-ti.hpp" #include "icinga/checkable-ti.hpp" @@ -99,8 +100,8 @@ public: void ValidateTypes(const Lazy& lvalue, const ValidationUtils& utils) override; void ValidateTimes(const Lazy& lvalue, const ValidationUtils& utils) override; - static void EvaluateApplyRules(const intrusive_ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); - static void EvaluateApplyRules(const intrusive_ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); static const std::map& GetStateFilterMap(); static const std::map& GetTypeFilterMap(); @@ -121,8 +122,8 @@ private: static bool EvaluateApplyRuleInstance(const intrusive_ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule, bool skipFilter); static bool EvaluateApplyRule( - const intrusive_ptr& checkable, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter = false + const intrusive_ptr& checkable, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter = false ); static std::map m_StateFilterMap; diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 5f4c07d60..0ac8cf8bb 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -61,14 +61,14 @@ bool ScheduledDowntime::EvaluateApplyRuleInstance(const Checkable::Ptr& checkabl } bool ScheduledDowntime::EvaluateApplyRule( - const Checkable::Ptr& checkable, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter + const Checkable::Ptr& checkable, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter ) { bool match = false; - BenchmarkApplyRuleEvaluation bare (totalTimeSpentOnApplyMismatches, match); + BenchmarkApplyRuleEvaluation bare (timeSpentOnApplyMismatches, rule, match); - auto& di (rule.GetDebugInfo()); + auto& di (rule->GetDebugInfo()); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; @@ -76,11 +76,11 @@ bool ScheduledDowntime::EvaluateApplyRule( ScriptFrame frame (false); - if (rule.GetScope() || rule.GetFTerm()) { + if (rule->GetScope() || rule->GetFTerm()) { frame.Locals = new Dictionary(); - if (rule.GetScope()) { - rule.GetScope()->CopyTo(frame.Locals); + if (rule->GetScope()) { + rule->GetScope()->CopyTo(frame.Locals); } checkable->GetFrozenLocalsForApply()->CopyTo(frame.Locals); @@ -89,80 +89,80 @@ bool ScheduledDowntime::EvaluateApplyRule( frame.Locals = checkable->GetFrozenLocalsForApply(); } - if (rule.GetFTerm()) { + if (rule->GetFTerm()) { Value vinstances; try { - vinstances = rule.GetFTerm()->Evaluate(frame); + vinstances = rule->GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } if (vinstances.IsObjectType()) { - if (!rule.GetFVVar().IsEmpty()) + if (!rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { - String name = rule.GetName(); + String name = rule->GetName(); - frame.Locals->Set(rule.GetFKVar(), instance, true); + frame.Locals->Set(rule->GetFKVar(), instance, true); name += instance; - if (EvaluateApplyRuleInstance(checkable, name, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, name, frame, *rule, skipFilter)) match = true; } } else if (vinstances.IsObjectType()) { - if (rule.GetFVVar().IsEmpty()) + if (rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first, true); - frame.Locals->Set(rule.GetFVVar(), kv.second, true); + frame.Locals->Set(rule->GetFKVar(), kv.first, true); + frame.Locals->Set(rule->GetFVVar(), kv.second, true); - if (EvaluateApplyRuleInstance(checkable, rule.GetName() + kv.first, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(checkable, rule->GetName() + kv.first, frame, *rule, skipFilter)) match = true; } } - } else if (EvaluateApplyRuleInstance(checkable, rule.GetName(), frame, rule, skipFilter)) { + } else if (EvaluateApplyRuleInstance(checkable, rule->GetName(), frame, *rule, skipFilter)) { match = true; } return match; } -void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void ScheduledDowntime::EvaluateApplyRules(const Host::Ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(ScheduledDowntime::TypeInstance, Host::TypeInstance)) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedHostRules(ScheduledDowntime::TypeInstance, host->GetName())) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } -void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void ScheduledDowntime::EvaluateApplyRules(const Service::Ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for service '" + service->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(ScheduledDowntime::TypeInstance, Service::TypeInstance)) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedServiceRules(ScheduledDowntime::TypeInstance, service->GetHost()->GetName(), service->GetShortName())) { - if (EvaluateApplyRule(service, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(service, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } diff --git a/lib/icinga/scheduleddowntime.hpp b/lib/icinga/scheduleddowntime.hpp index d86a45b54..f3551994a 100644 --- a/lib/icinga/scheduleddowntime.hpp +++ b/lib/icinga/scheduleddowntime.hpp @@ -3,6 +3,7 @@ #ifndef SCHEDULEDDOWNTIME_H #define SCHEDULEDDOWNTIME_H +#include "config/applyrule.hpp" #include "icinga/i2-icinga.hpp" #include "icinga/scheduleddowntime-ti.hpp" #include "icinga/checkable.hpp" @@ -29,8 +30,8 @@ public: Checkable::Ptr GetCheckable() const; - static void EvaluateApplyRules(const intrusive_ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); - static void EvaluateApplyRules(const intrusive_ptr& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); + static void EvaluateApplyRules(const intrusive_ptr& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); static bool AllConfigIsLoaded(); void ValidateRanges(const Lazy& lvalue, const ValidationUtils& utils) override; @@ -54,8 +55,8 @@ private: static bool EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule, bool skipFilter); static bool EvaluateApplyRule( - const Checkable::Ptr& checkable, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter = false + const Checkable::Ptr& checkable, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter = false ); }; diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index ec400e69f..9f6b9530e 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -56,14 +56,14 @@ bool Service::EvaluateApplyRuleInstance(const Host::Ptr& host, const String& nam } bool Service::EvaluateApplyRule( - const Host::Ptr& host, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter + const Host::Ptr& host, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter ) { bool match = false; - BenchmarkApplyRuleEvaluation bare (totalTimeSpentOnApplyMismatches, match); + BenchmarkApplyRuleEvaluation bare (timeSpentOnApplyMismatches, rule, match); - auto& di (rule.GetDebugInfo()); + auto& di (rule->GetDebugInfo()); std::ostringstream msgbuf; msgbuf << "Evaluating 'apply' rule (" << di << ")"; @@ -71,11 +71,11 @@ bool Service::EvaluateApplyRule( ScriptFrame frame (false); - if (rule.GetScope() || rule.GetFTerm()) { + if (rule->GetScope() || rule->GetFTerm()) { frame.Locals = new Dictionary(); - if (rule.GetScope()) { - rule.GetScope()->CopyTo(frame.Locals); + if (rule->GetScope()) { + rule->GetScope()->CopyTo(frame.Locals); } host->GetFrozenLocalsForApply()->CopyTo(frame.Locals); @@ -84,67 +84,67 @@ bool Service::EvaluateApplyRule( frame.Locals = host->GetFrozenLocalsForApply(); } - if (rule.GetFTerm()) { + if (rule->GetFTerm()) { Value vinstances; try { - vinstances = rule.GetFTerm()->Evaluate(frame); + vinstances = rule->GetFTerm()->Evaluate(frame); } catch (const std::exception&) { /* Silently ignore errors here and assume there are no instances. */ return false; } if (vinstances.IsObjectType()) { - if (!rule.GetFVVar().IsEmpty()) + if (!rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Dictionary iterator requires value to be a dictionary.", di)); Array::Ptr arr = vinstances; ObjectLock olock(arr); for (const Value& instance : arr) { - String name = rule.GetName(); + String name = rule->GetName(); - if (!rule.GetFKVar().IsEmpty()) { - frame.Locals->Set(rule.GetFKVar(), instance, true); + if (!rule->GetFKVar().IsEmpty()) { + frame.Locals->Set(rule->GetFKVar(), instance, true); name += instance; } - if (EvaluateApplyRuleInstance(host, name, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(host, name, frame, *rule, skipFilter)) match = true; } } else if (vinstances.IsObjectType()) { - if (rule.GetFVVar().IsEmpty()) + if (rule->GetFVVar().IsEmpty()) BOOST_THROW_EXCEPTION(ScriptError("Array iterator requires value to be an array.", di)); Dictionary::Ptr dict = vinstances; ObjectLock olock (dict); for (auto& kv : dict) { - frame.Locals->Set(rule.GetFKVar(), kv.first, true); - frame.Locals->Set(rule.GetFVVar(), kv.second, true); + frame.Locals->Set(rule->GetFKVar(), kv.first, true); + frame.Locals->Set(rule->GetFVVar(), kv.second, true); - if (EvaluateApplyRuleInstance(host, rule.GetName() + kv.first, frame, rule, skipFilter)) + if (EvaluateApplyRuleInstance(host, rule->GetName() + kv.first, frame, *rule, skipFilter)) match = true; } } - } else if (EvaluateApplyRuleInstance(host, rule.GetName(), frame, rule, skipFilter)) { + } else if (EvaluateApplyRuleInstance(host, rule->GetName(), frame, *rule, skipFilter)) { match = true; } return match; } -void Service::EvaluateApplyRules(const Host::Ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Service::EvaluateApplyRules(const Host::Ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { CONTEXT("Evaluating 'apply' rules for host '" + host->GetName() + "'"); for (auto& rule : ApplyRule::GetRules(Service::TypeInstance, Host::TypeInstance)) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches)) rule->AddMatch(); } for (auto& rule : ApplyRule::GetTargetedHostRules(Service::TypeInstance, host->GetName())) { - if (EvaluateApplyRule(host, *rule, totalTimeSpentOnApplyMismatches, true)) + if (EvaluateApplyRule(host, rule, timeSpentOnApplyMismatches, true)) rule->AddMatch(); } } diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index 42a7fbb91..2b48acdf6 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -74,16 +74,16 @@ void Service::OnAllConfigLoaded() } } -void Service::CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) +void Service::CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) { if (childType == ScheduledDowntime::TypeInstance) - ScheduledDowntime::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + ScheduledDowntime::EvaluateApplyRules(this, timeSpentOnApplyMismatches); if (childType == Notification::TypeInstance) - Notification::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + Notification::EvaluateApplyRules(this, timeSpentOnApplyMismatches); if (childType == Dependency::TypeInstance) - Dependency::EvaluateApplyRules(this, totalTimeSpentOnApplyMismatches); + Dependency::EvaluateApplyRules(this, timeSpentOnApplyMismatches); } Service::Ptr Service::GetByNamePair(const String& hostName, const String& serviceName) diff --git a/lib/icinga/service.hpp b/lib/icinga/service.hpp index 3a18dbf70..9f8ed5915 100644 --- a/lib/icinga/service.hpp +++ b/lib/icinga/service.hpp @@ -3,6 +3,7 @@ #ifndef SERVICE_H #define SERVICE_H +#include "config/applyrule.hpp" #include "icinga/i2-icinga.hpp" #include "icinga/service-ti.hpp" #include "icinga/macroresolver.hpp" @@ -42,14 +43,14 @@ public: static StateType StateTypeFromString(const String& state); static String StateTypeToString(StateType state); - static void EvaluateApplyRules(const Host::Ptr& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches); + static void EvaluateApplyRules(const Host::Ptr& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches); void OnAllConfigLoaded() override; static boost::signals2::signal OnHostProblemChanged; protected: - void CreateChildObjects(const Type::Ptr& childType, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches) override; + void CreateChildObjects(const Type::Ptr& childType, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches) override; Dictionary::Ptr MakeLocalsForApply() override; @@ -59,8 +60,8 @@ private: static bool EvaluateApplyRuleInstance(const Host::Ptr& host, const String& name, ScriptFrame& frame, const ApplyRule& rule, bool skipFilter); static bool EvaluateApplyRule( - const Host::Ptr& host, const ApplyRule& rule, - TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter = false + const Host::Ptr& host, const ApplyRule::Ptr& rule, + TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter = false ); };