Line data Source code
1 :
2 : #include "ErrorHandler/MessageAnalyzer/ma_rule_engine.h"
3 :
4 : #include <cetlib/filepath_maker.h>
5 : #include <fhiclcpp/make_ParameterSet.h>
6 :
7 : using fhicl::ParameterSet;
8 :
9 : using namespace novadaq::errorhandler;
10 :
11 0 : ma_rule_engine::ma_rule_engine(fhicl::ParameterSet const& pset, alarm_fn_t alarm, cond_match_fn_t cond_match)
12 0 : : pset(pset)
13 0 : , cmap()
14 0 : , cnames()
15 0 : , rmap()
16 0 : , rnames()
17 0 : , alarm_fn(alarm)
18 0 : , cond_match_fn(cond_match)
19 0 : , events()
20 0 : , event_worker_t()
21 0 : , EHS(false)
22 : {
23 0 : init_engine();
24 0 : }
25 :
26 0 : void ma_rule_engine::init_engine()
27 : {
28 : // Error Handling Supervisor -- EHS
29 0 : EHS = pset.get<bool>("EHS", false);
30 :
31 0 : ParameterSet conds = pset.get<ParameterSet>("conditions", fhicl::ParameterSet());
32 0 : ParameterSet rules = pset.get<ParameterSet>("rules", fhicl::ParameterSet());
33 :
34 0 : cnames = conds.get_pset_names();
35 0 : rnames = rules.get_pset_names();
36 :
37 : // go through all conditions
38 0 : for (size_t i = 0; i < cnames.size(); ++i)
39 : {
40 0 : ParameterSet nulp;
41 :
42 0 : ParameterSet cond = conds.get<ParameterSet>(cnames[i]);
43 0 : ParameterSet rate = cond.get<ParameterSet>("rate", nulp);
44 0 : ParameterSet gran = cond.get<ParameterSet>("granularity", nulp);
45 :
46 : // decide whether "at_least" or "at_most"
47 0 : int occur{0}, occur_at_most{0}, occur_at_least{0};
48 0 : bool at_most = rate.get_if_present<int>("occur_at_most", occur_at_most);
49 0 : bool at_least = rate.get_if_present<int>("occur_at_least", occur_at_least);
50 :
51 : // compatible with the previous "occurence" keyword
52 0 : if (!at_least) at_least = rate.get_if_present<int>("occurence", occur_at_least);
53 :
54 0 : if (at_most && at_least)
55 : {
56 : throw std::runtime_error(
57 : "rule_engine::init_engine() cannot have both 'occur_at_least' "
58 0 : "and 'occur_at_most' in the rate entry, in condition " +
59 0 : cnames[i]);
60 : }
61 0 : else if (!at_most && !at_least)
62 : {
63 0 : occur = 1;
64 0 : at_least = true;
65 : }
66 : else
67 : {
68 0 : occur = at_least ? occur_at_least : occur_at_most;
69 : }
70 :
71 : // construct the condition object
72 0 : ma_condition c(cond.get<std::string>("description", std::string()), cond.get<std::string>("severity"), cond.get<std::vector<std::string>>("source"),
73 0 : cond.get<std::vector<std::string>>("category", std::vector<std::string>(1, "*")), cond.get<std::string>("regex"), cond.get<std::string>("test", std::string()),
74 0 : cond.get<bool>("persistent", true), occur, at_least, rate.get<int>("timespan", 4372596) // a random long time
75 : ,
76 0 : gran.get<bool>("per_source", false), gran.get<bool>("per_target", false), gran.get<unsigned int>("target_group", 1), events);
77 :
78 : // push the condition to the container, and parse the test function
79 0 : cond_map_t::iterator it = cmap.insert(std::make_pair(cnames[i], c)).first;
80 :
81 : // init after the condition has been inserted into the map
82 0 : it->second.init();
83 0 : }
84 :
85 : // go through all rules
86 0 : for (size_t i = 0; i < rnames.size(); ++i)
87 : {
88 0 : ParameterSet nulp;
89 :
90 0 : ParameterSet rule = rules.get<ParameterSet>(rnames[i]);
91 :
92 : // construct the rule object
93 0 : ma_rule r(rnames[i], rule.get<std::string>("description", std::string()), rule.get<bool>("repeat_alarm", false), rule.get<int>("holdoff", 0));
94 :
95 : // push the rule to the container
96 0 : rule_map_t::iterator it = rmap.insert(std::make_pair(rnames[i], r)).first;
97 :
98 : // parse the condition expression and alarm message
99 : // this is done in a two-step method (init the object, push into container
100 : // then parse) because the parse process involves updating the conditions
101 : // notification list which needs the pointer to the ma_rule object. There-
102 : // fore we push the ma_rule object into the container first, then do the
103 : // parse
104 0 : it->second.parse(rule.get<std::string>("expression"), rule.get<std::string>("message"), rule.get<ParameterSet>("action", nulp), &cmap);
105 0 : }
106 :
107 : // for all conditions sort their notification lists
108 0 : cond_map_t::iterator it = cmap.begin();
109 0 : for (; it != cmap.end(); ++it) it->second.sort_notify_lists();
110 :
111 : // timing event worker thread
112 0 : event_worker_t = boost::thread(&ma_rule_engine::event_worker, this);
113 0 : }
114 :
115 0 : void ma_rule_engine::event_worker()
116 : {
117 : while (true)
118 : {
119 : // get current second
120 0 : time_t now = time(0);
121 :
122 : // loop for all past due events, and execute them
123 : {
124 : // scoped lock
125 0 : boost::mutex::scoped_lock lock(events.lock);
126 :
127 0 : conds_t status;
128 0 : event_queue_t& eq = events.event_queue();
129 :
130 0 : while (!eq.empty() && eq.top().timestamp() < now)
131 : {
132 0 : ma_timing_event const& e = eq.top();
133 0 : e.condition().event(e.source_idx(), e.target_idx(), e.timestamp(), status);
134 0 : eq.pop();
135 : }
136 :
137 : // build notify list
138 0 : notify_list_t notify_status;
139 0 : merge_notify_list(notify_status, status, STATUS_NOTIFY);
140 :
141 : // rules->evaluate
142 0 : evaluate_rules(notify_status);
143 0 : }
144 :
145 0 : sleep(1);
146 0 : }
147 : }
148 :
149 0 : void ma_rule_engine::feed(qt_mf_msg const& msg)
150 : {
151 : // reaction starters
152 0 : conds_t status;
153 0 : conds_t source;
154 0 : conds_t target;
155 :
156 : // loop through conditions
157 : {
158 0 : cond_map_t::iterator it = cmap.begin();
159 0 : for (; it != cmap.end(); ++it)
160 0 : if (it->second.match(msg, status, source, target))
161 0 : cond_match_fn(it->first); // callback fn for condition match
162 : }
163 :
164 : // notification mechanism
165 :
166 : // merge notification lists from reaction starters
167 0 : notify_list_t notify_status;
168 0 : notify_list_t notify_domain;
169 :
170 0 : merge_notify_list(notify_status, status, STATUS_NOTIFY);
171 0 : merge_notify_list(notify_domain, source, SOURCE_NOTIFY);
172 0 : merge_notify_list(notify_domain, target, TARGET_NOTIFY);
173 :
174 : // update domains
175 0 : evaluate_rules_domain(notify_domain);
176 :
177 : // loop to update status
178 0 : evaluate_rules(notify_status);
179 0 : }
180 :
181 0 : void ma_rule_engine::evaluate_rules_domain(notify_list_t& notify_domain)
182 : {
183 0 : notify_list_t::iterator it = notify_domain.begin();
184 0 : for (; it != notify_domain.end(); ++it)
185 0 : (*it)->evaluate_domain();
186 0 : }
187 :
188 0 : void ma_rule_engine::evaluate_rules(notify_list_t& notify_status)
189 : {
190 0 : notify_list_t::iterator it = notify_status.begin();
191 0 : for (; it != notify_status.end(); ++it)
192 : {
193 0 : if ((*it)->evaluate())
194 : {
195 : // alarm message
196 0 : alarm_fn((*it)->name(), (*it)->get_alarm_message());
197 :
198 : // actions
199 0 : if (EHS)
200 : {
201 0 : int now_reset_rule = (*it)->act();
202 0 : if (now_reset_rule > 0)
203 : {
204 0 : this->reset_rule((*it)->name());
205 0 : alarm_fn((*it)->name(), "reseting this rule!");
206 : }
207 : }
208 : }
209 : }
210 0 : }
211 :
212 0 : void ma_rule_engine::merge_notify_list(notify_list_t& n_list, conds_t const& c_list, notify_t type)
213 : {
214 0 : conds_t::const_iterator it = c_list.begin();
215 0 : for (; it != c_list.end(); ++it)
216 : {
217 0 : notify_list_t notify((*it)->get_notify_list(type));
218 0 : n_list.merge(notify);
219 0 : n_list.unique();
220 0 : }
221 0 : }
222 :
223 : const ma_condition&
224 0 : ma_rule_engine::find_cond_by_name(std::string const& name) const
225 : {
226 0 : cond_map_t::const_iterator it = cmap.find(name);
227 0 : if (it == cmap.end())
228 0 : throw std::runtime_error("rule_engine::find_cond_by_name() name not found");
229 0 : return it->second;
230 : }
231 :
232 : ma_condition&
233 0 : ma_rule_engine::find_cond_by_name(std::string const& name)
234 : {
235 0 : cond_map_t::iterator it = cmap.find(name);
236 0 : if (it == cmap.end())
237 0 : throw std::runtime_error("rule_engine::find_cond_by_name() name not found");
238 0 : return it->second;
239 : }
240 :
241 : const ma_rule&
242 0 : ma_rule_engine::find_rule_by_name(std::string const& name) const
243 : {
244 0 : rule_map_t::const_iterator it = rmap.find(name);
245 0 : if (it == rmap.end())
246 0 : throw std::runtime_error("rule_engine::find_rule_by_name() name not found");
247 0 : return it->second;
248 : }
249 :
250 : ma_rule&
251 0 : ma_rule_engine::find_rule_by_name(std::string const& name)
252 : {
253 0 : rule_map_t::iterator it = rmap.find(name);
254 0 : if (it == rmap.end())
255 0 : throw std::runtime_error("rule_engine::find_rule_by_name() name not found");
256 0 : return it->second;
257 : }
|