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