Mismatching apply rules and parent objects: give time by rule and per object

This commit is contained in:
Alexander A. Klimov 2022-11-14 17:21:15 +01:00
parent 2e38e24a31
commit 3ef0917dd9
17 changed files with 241 additions and 148 deletions

View File

@ -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. */
}

View File

@ -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();

View File

@ -2,6 +2,7 @@
#include "config/applyrule.hpp"
#include "base/logger.hpp"
#include <algorithm>
#include <set>
#include <unordered_set>
@ -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<double, seconds::period>(steady_clock::duration(m_MonotonicTicks.load())).count();
return duration<double, seconds::period>(steady_clock::duration(ticks)).count();
}
double TimeSpentOnApplyMismatches::GetTotal()
{
std::chrono::steady_clock::rep total = 0;
{
boost::shared_lock<boost::shared_mutex> lock (m_Mutex);
for (auto& kv : m_ByRule) {
total += kv.second.MonotonicTicks.load();
}
}
return MonotonicTicksToSeconds(total);
}
std::vector<TimeSpentOnApplyMismatches::BadRule> TimeSpentOnApplyMismatches::GetWorstRules()
{
std::vector<BadRule> worstRules;
{
boost::shared_lock<boost::shared_mutex> 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;
}

View File

@ -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 <atomic>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <chrono>
#include <cstdint>
#include <map>
#include <unordered_map>
#include <utility>
#include <vector>
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<BadRule> GetWorstRules();
private:
Atomic<std::chrono::steady_clock::rep> m_MonotonicTicks {0};
struct PerRule
{
std::atomic<uint_fast32_t> ParentObjects;
std::atomic<std::chrono::steady_clock::rep> MonotonicTicks;
};
boost::shared_mutex m_Mutex;
std::map<ApplyRule::Ptr, PerRule> 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<boost::shared_mutex> lock (m_TimeSpentOnMismatches.m_Mutex);
auto perRule (mtbr.find(m_Rule));
if (perRule != mtbr.end()) {
total = &perRule->second;
}
}
if (!total) {
boost::unique_lock<boost::shared_mutex> 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;
};

View File

@ -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<ConfigItem::Ptr>& newItems,
TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches
TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches
)
{
typedef std::pair<ConfigItem::Ptr, bool> ItemPair;
@ -598,14 +598,14 @@ bool ConfigItem::CommitNewItems(
auto items (itemsByType.find(loadDep));
if (items != itemsByType.end()) {
upq.ParallelFor(items->second, [&type, &notified_items, &totalTimeSpentOnApplyMismatches](const ItemPair& ip) {
upq.ParallelFor(items->second, [&type, &notified_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<Type::Ptr, int> ItemCountMap;
ItemCountMap itemCounts;

View File

@ -101,7 +101,7 @@ private:
static bool CommitNewItems(
const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems,
TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches
TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches
);
};

View File

@ -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<Array>()) {
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<Dictionary>()) {
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();
}
}

View File

@ -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<Array::Ptr>& lvalue, const ValidationUtils& utils) override;
static void EvaluateApplyRules(const intrusive_ptr<Host>& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Host>& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
/* Note: Only use them for unit test mocks. Prefer OnConfigLoaded(). */
void SetParent(intrusive_ptr<Checkable> 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
);
};

View File

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

View File

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

View File

@ -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<Array>()) {
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<Dictionary>()) {
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();
}
}

View File

@ -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<Array::Ptr>& lvalue, const ValidationUtils& utils) override;
void ValidateTimes(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils) override;
static void EvaluateApplyRules(const intrusive_ptr<Host>& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Host>& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
static const std::map<String, int>& GetStateFilterMap();
static const std::map<String, int>& GetTypeFilterMap();
@ -121,8 +122,8 @@ private:
static bool EvaluateApplyRuleInstance(const intrusive_ptr<Checkable>& checkable, const String& name, ScriptFrame& frame, const ApplyRule& rule, bool skipFilter);
static bool EvaluateApplyRule(
const intrusive_ptr<Checkable>& checkable, const ApplyRule& rule,
TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches, bool skipFilter = false
const intrusive_ptr<Checkable>& checkable, const ApplyRule::Ptr& rule,
TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches, bool skipFilter = false
);
static std::map<String, int> m_StateFilterMap;

View File

@ -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<Array>()) {
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<Dictionary>()) {
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();
}
}

View File

@ -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>& host, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TotalTimeSpentOnApplyMismatches& totalTimeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Host>& host, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
static void EvaluateApplyRules(const intrusive_ptr<Service>& service, TimeSpentOnApplyMismatches& timeSpentOnApplyMismatches);
static bool AllConfigIsLoaded();
void ValidateRanges(const Lazy<Dictionary::Ptr>& 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
);
};

View File

@ -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<Array>()) {
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<Dictionary>()) {
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();
}
}

View File

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

View File

@ -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<void (const Service::Ptr&, const CheckResult::Ptr&, const MessageOrigin::Ptr&)> 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
);
};