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