LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
ELdestination.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
4 #include "cetlib/PluginTypeDeducer.h"
6 #include "fhiclcpp/types/Atom.h"
9 #include "fhiclcpp/types/Table.h"
14 
15 #include <bitset>
16 #include <cstddef>
17 #include <cstdio>
18 #include <cstring>
19 #include <fstream>
20 #include <functional>
21 #include <iomanip>
22 #include <ios>
23 #include <iostream>
24 #include <limits>
25 #include <map>
26 #include <ostream>
27 #include <sstream>
28 #include <string>
29 
30 #include <sys/time.h>
31 #include <time.h>
32 
33 using namespace std;
34 using namespace std::string_literals;
35 
37  "ELdestination"s;
38 
39 namespace mf {
40  namespace service {
41 
42  ELdestination::Category::Config::~Config() {}
43 
44  ELdestination::Category::Config::Config()
45  : limit{fhicl::Name{"limit"}, -1}
46  , reportEvery{fhicl::Name{"reportEvery"}, -1}
47  , timespan{fhicl::Name{"timespan"}, -1}
48  {}
49 
51  : limit{fhicl::Name{"limit"}, pset.get<int>("limit", -1)}
52  , reportEvery{fhicl::Name{"reportEvery"},
53  pset.get<int>("reportEvery", -1)}
54  , timespan{fhicl::Name{"timespan"}, pset.get<int>("timespan", -1)}
55  {}
56 
57  std::string
59  {
60  return R"(The 'limit' parameter is an integer after which the logger will start
61 to ignore messages of this category. Beyond the specified limit, an
62 occasional further message will appear, based on an exponential
63 fall-off. For example, if the limit is set to 5, and 100 messages of
64 this category are issued, then the destination containing this
65 configuration will log messages numbered 1, 2, 3, 4, 5, 10, 15, 25,
66 45, and 85. A limit of zero disables reporting any messages.)";
67  }
68 
69  std::string
71  {
72  return R"(The 'reportEvery' parameter is an integer n which logs only every nth
73 message. If the value is zero or less, then the report-every feature
74 is disabled.)";
75  }
76 
77  std::string
79  {
80  return R"(The 'timespan' parameter is an integer representing seconds. When a
81 limit is set, one can also specify that if no occurrences for that
82 particular category of messages have been seen in a period of time
83 (the timespan), then the count toward that limit is to be reset. For
84 example, if one wish to suppress most of the thousands of warnings of
85 some category expected at startup, but would like to know if another
86 one happens after a gap of ten minutes, one can set the timespan value
87 to 600. A value of zero or less disables the timespan functionality.)";
88  }
89 
91 
93 
95 
97  : limit_{}, reportEvery_{}, timespan_{}
98  {}
99 
101 
103  : previousTimestamp_{}
104  , msgCount_{}
105  , skippedMsgCount_{}
106  , limit_{}
107  , reportEvery_{}
108  , timespan_{}
109  {}
110 
112 
114  : timestamp{fhicl::Name("timestamp"),
116  "The 'timestamp' parameter represents a format that can be "
117  "interpreted\n"
118  "by strftime. Allowed values include:\n\n"
119  " - \"none\" (suppress timestamp printing)\n"
120  " - \"default\" (format string shown below)\n"
121  " - \"default_ms\" (use millisecond precision)\n"
122  " - any user-specified format interpretable by strftime"),
123  "%d-%b-%Y %H:%M:%S %Z"}
124  , noLineBreaks{fhicl::Name("noLineBreaks"), false}
125  , lineLength{fhicl::Name{"lineLength"},
126  fhicl::Comment{"The following parameter is allowed only if "
127  "'noLineBreaks' has been set to 'false'."},
128  [this] { return !noLineBreaks(); },
129  80ull}
130  , wantModule{fhicl::Name("wantModule"), true}
131  , wantSubroutine{fhicl::Name("wantSubroutine"), true}
132  , wantText{fhicl::Name("wantText"), true}
133  , wantSomeContext{fhicl::Name("wantSomeContext"), true}
134  , wantSerial{fhicl::Name("wantSerial"), false}
135  , wantFullContext{fhicl::Name("wantFullContext"), false}
136  , wantTimeSeparate{fhicl::Name("wantTimeSeparate"), false}
137  , wantEpilogueSeparate{fhicl::Name("wantEpilogueSeparate"), false}
138  {}
139 
141 
143  : timeMethod_{0}, timeFmt_{}
144  {
145  auto const& value = config.timestamp();
146  bool const use_timestamp = (value != "none"s);
147  flags.set(TIMESTAMP, use_timestamp);
148  if (!use_timestamp) {
149  timeMethod_ = 0;
150  } else if (value == "default"s) {
151  timeMethod_ = 1;
152  timeFmt_ = "%d-%b-%Y %H:%M:%S %Z"s;
153  } else if (value == "default_ms"s) {
154  timeMethod_ = 2;
155  timeFmt_ = "%d-%b-%Y %H:%M:%S.%%03u %Z"s;
156  } else {
157  timeMethod_ = 1;
158  timeFmt_ = value;
159  }
160  lineLength = config.noLineBreaks() ? 32000ull : config.lineLength();
161  flags.set(NO_LINE_BREAKS, config.noLineBreaks());
162  flags.set(MODULE, config.wantModule());
163  flags.set(SUBROUTINE, config.wantSubroutine());
164  flags.set(TEXT, config.wantText());
165  flags.set(SOME_CONTEXT, config.wantSomeContext());
166  flags.set(SERIAL, config.wantSerial());
167  flags.set(FULL_CONTEXT, config.wantFullContext());
168  flags.set(TIME_SEPARATE, config.wantTimeSeparate());
169  flags.set(EPILOGUE_SEPARATE, config.wantEpilogueSeparate());
170  }
171 
172  bool
174  {
175  return flags.test(FLAG);
176  }
177 
178  string
180  {
181  size_t constexpr SIZE{144};
182  string ret;
183  if (timeMethod_ == 0) {
184  return ret;
185  }
186  struct tm timebuf;
187  char ts[SIZE];
188  if (timeMethod_ == 1) {
189  strftime(
190  ts, sizeof(ts), timeFmt_.data(), localtime_r(&t.tv_sec, &timebuf));
191  ret = ts;
192  return ret;
193  }
194  char tmpts[SIZE];
195  strftime(tmpts,
196  sizeof(tmpts),
197  timeFmt_.data(),
198  localtime_r(&t.tv_sec, &timebuf));
199  snprintf(ts, sizeof(ts), tmpts, static_cast<unsigned>(t.tv_usec / 1000));
200  ret = ts;
201  return ret;
202  }
203 
205 
207  : n_{}
208  , aggregateN_{}
209  , ignoredFlag_{false}
210  , context1_{}
211  , context2_{}
212  , contextLast_{}
213  {}
214 
215  void
216  ELdestination::StatsCount::add(string const& context, bool const reactedTo)
217  {
218  if (reactedTo) {
219  ++n_;
220  }
221  ++aggregateN_;
222  ((n_ == 1) ? context1_ : (n_ == 2) ? context2_ : contextLast_) =
223  string(context, 0, 16);
224  if (!reactedTo) {
225  ignoredFlag_ = true;
226  }
227  }
228 
230 
232  : reset{fhicl::Name("reset"),
233  fhicl::Comment("Used for statistics destinations"),
234  false}
235  , resetStatistics{fhicl::Name("resetStatistics"), false}
236  {}
237 
239 
241  : dest_type{fhicl::Name{"type"}}
242  , threshold{fhicl::Name{"threshold"},
244  "The 'threshold' parameter specifies the lowest severity "
245  "level of\n"
246  "messages that will be logged to the destination"},
247  "INFO"}
248  , format{fhicl::Name{"format"}}
249  , categories{fhicl::Name{"categories"},
251  R"(The 'categories' parameter (if provided) is a FHiCL table that
252 configures the behavior of logging to this destination for the specified
253 category. For example, if the following appears in C++ source code:
254 
255  mf::LogInfo{"Tracking"} << my_track.diagnostics();
256 
257 the category is 'Tracking', and its behavior can be specified via:
258 
259  categories: {
260  Tracking: {
261  limit: -1 # default
262  reportEvery: -1 # default
263  timespan: -1 # default
264  }
265  }
266 
267 Within the 'categories' table, it is permitted to specify a 'default'
268 category, which becomes the configuration for all message categories
269 that are not explicitly listed.
270 
271 Note the categories listed only customize the behavior of messages
272 that are logged specifically to this destination. Messages that are
273 routed to other destinations are not be affected.
274 
275 Category parameters
276 ===================
277 
279  "\n\n" + Category::Config::reportEvery_comment() + "\n\n" +
281  , outputStatistics{fhicl::Name{"outputStatistics"}, false}
282  , msgStatistics{}
283  {}
284 
286  : threshold_{pset.threshold()}
287  , format_{pset.format()}
289  , defaultReportEvery_{-1}
291  , categoryParams_{}
292  , xidLimiters_{}
293  , statsMap_{}
294  , outputStatistics_{pset.outputStatistics()}
295  , updatedStats_{false}
296  , reset_{pset.msgStatistics().reset() ||
297  pset.msgStatistics().resetStatistics()}
298  , charsOnLine_{}
299  {
300  vector<string> configuration_errors;
301  // Grab this destination's category configurations.
302  fhicl::ParameterSet cats_pset{};
303  pset.categories.get_if_present<fhicl::ParameterSet>(cats_pset);
304  // Grab the list of categories, removing the default category
305  // since it is handled specially.
306  auto const default_category_name = "default"s;
307  auto categories = cats_pset.get_pset_names();
308  auto erase_from =
309  remove_if(begin(categories), end(categories), [](auto const& category) {
310  return category == "default"s;
311  });
312  categories.erase(erase_from, categories.cend());
313  // Setup the default configuration for categories--this involves
314  // resetting the limits table according to the user-specified
315  // default configuration.
316  auto const& default_pset =
317  cats_pset.get<fhicl::ParameterSet>("default"s, {});
318  try {
319  fhicl::WrappedTable<Category::Config> default_params{default_pset};
320  defaultLimit_ = (default_params().limit() < 0) ?
321  numeric_limits<decltype(defaultLimit_)>::max() :
322  default_params().limit();
323  defaultReportEvery_ = default_params().reportEvery();
324  defaultTimespan_ = (default_params().timespan() < 0) ?
325  numeric_limits<decltype(defaultTimespan_)>::max() :
326  default_params().timespan();
327  }
328  catch (fhicl::detail::validationException const& e) {
329  string msg{"Category: "s + detail::bold_fontify("default"s) + "\n\n"s};
330  msg += e.what();
331  configuration_errors.push_back(move(msg));
332  }
333  // Now establish this destination's limit/reportEvery/timespan for
334  // each category, using the values of the possibly-specified
335  // default configuration when a given category is missing the
336  // fields.
337  for (auto const& category : categories) {
338  fhicl::Table<Category::Config> category_params{fhicl::Name{category},
339  default_pset};
340  try {
341  category_params.validate_ParameterSet(
342  cats_pset.get<fhicl::ParameterSet>(category));
343  }
344  catch (fhicl::detail::validationException const& e) {
345  string msg{"Category: " + detail::bold_fontify(category) + "\n\n"};
346  msg += e.what();
347  configuration_errors.push_back(move(msg));
348  }
349  // limits_.setCategoryParams(category, category_params().limit(),
350  // category_params().reportEvery(), category_params().timespan());
351  // setCategoryParams(string const& category, int limit, int reportEvery,
352  // int timespan)
353  {
354  if (category_params().limit() < 0) {
355  categoryParams_[category].limit_ = numeric_limits<int>::max();
356  } else {
357  categoryParams_[category].limit_ = category_params().limit();
358  }
359  categoryParams_[category].reportEvery_ =
360  category_params().reportEvery();
361  if (category_params().timespan() < 0) {
362  categoryParams_[category].timespan_ = numeric_limits<int>::max();
363  } else {
364  categoryParams_[category].timespan_ = category_params().timespan();
365  }
366  }
367  }
368  if (!configuration_errors.empty()) {
369  string msg{"The following categories were misconfigured:\n\n"};
370  for (auto const& error : configuration_errors) {
371  msg += error;
372  }
374  }
375  }
376 
377  string
379  {
380  if (c.substr(0, 4) != "Run:") {
381  return c;
382  }
383  istringstream is(c);
384  string runWord;
385  int run;
386  is >> runWord >> run;
387  if (!is) {
388  return c;
389  }
390  if (runWord != "Run:") {
391  return c;
392  }
393  string eventWord;
394  int event;
395  is >> eventWord >> event;
396  if (!is) {
397  return c;
398  }
399  if (eventWord != "Event:") {
400  return c;
401  }
402  ostringstream os;
403  os << run << "/" << event;
404  return os.str();
405  }
406 
407  void
409  string const& s,
410  bool const nl,
411  bool const preambleMode)
412  {
413  string indent(6, ' ');
414  if (s.empty()) {
415  if (nl) {
416  os << '\n';
417  charsOnLine_ = 0UL;
418  }
419  return;
420  }
421  if (!preambleMode) {
422  os << s;
423  return;
424  }
425  char const first = s[0];
426  char const second = (s.length() < 2) ? '\0' : s[1];
427  char const last = (s.length() < 2) ? '\0' : s[s.length() - 1];
428  char const last2 = (s.length() < 3) ? '\0' : s[s.length() - 2];
429  // checking -2 because the very last char is sometimes a ' '
430  // inserted by ErrorLog::operator<<
431  // Accounts for newline @ the beginning of the string
432  if (first == '\n' || (charsOnLine_ + s.length()) > format_.lineLength) {
433  charsOnLine_ = 0UL;
434  if (second != ' ') {
435  os << ' ';
436  ++charsOnLine_;
437  }
438  if (first == '\n') {
439  os << s.substr(1);
440  } else {
441  os << s;
442  }
443  } else {
444  os << s;
445  }
446  if ((last == '\n') || (last2 == '\n')) {
447  os << indent;
448  if (last != ' ') {
449  os << ' ';
450  }
451  charsOnLine_ = indent.length() + 1UL;
452  }
453  if (nl) {
454  os << '\n';
455  charsOnLine_ = 0UL;
456  } else {
457  charsOnLine_ += s.length();
458  }
459  }
460 
461  void
462  ELdestination::fillPrefix(ostringstream& oss, ErrorObj const& msg)
463  {
464  if (msg.is_verbatim()) {
465  return;
466  }
467  auto const& xid = msg.xid();
468  charsOnLine_ = 0UL;
469  emitToken(oss, "%MSG"s, false, true);
470  emitToken(oss, xid.severity().getSymbol(), false, true);
471  emitToken(oss, " ", false, true);
472  emitToken(oss, xid.id(), false, true);
473  emitToken(oss, msg.idOverflow(), false, true);
474  emitToken(oss, ": ", false, true);
475  if (format_.want(SERIAL)) {
476  ostringstream s;
477  s << msg.serial();
478  emitToken(oss, "[serial #" + s.str() + "] ", false, true);
479  }
480  bool needAspace = true;
482  if (xid.module().length() + xid.subroutine().length() > 0) {
483  emitToken(oss, "\n", false, true);
484  needAspace = false;
485  } else if (format_.want(TIMESTAMP) && !format_.want(TIME_SEPARATE)) {
486  emitToken(oss, "\n", false, true);
487  needAspace = false;
488  }
489  }
490  if (format_.want(MODULE) && (xid.module().length() > 0)) {
491  if (needAspace) {
492  emitToken(oss, " ", false, true);
493  needAspace = false;
494  }
495  emitToken(oss, xid.module() + " ", false, true);
496  }
497  if (format_.want(SUBROUTINE) && (xid.subroutine().length() > 0)) {
498  if (needAspace) {
499  emitToken(oss, " ", false, true);
500  needAspace = false;
501  }
502  emitToken(oss, xid.subroutine() + "() ", false, true);
503  }
504  if (format_.want(TIMESTAMP)) {
505  if (format_.want(TIME_SEPARATE)) {
506  emitToken(oss, "\n", false, true);
507  needAspace = false;
508  }
509  if (needAspace) {
510  emitToken(oss, " ", false, true);
511  needAspace = false;
512  }
513  emitToken(oss, format_.timestamp(msg.timestamp()) + " ", false, true);
514  }
515  if (format_.want(SOME_CONTEXT)) {
516  if (needAspace) {
517  emitToken(oss, " ", false, true);
518  needAspace = false;
519  }
520  emitToken(oss, msg.context(), false, true);
521  }
522  }
523 
524  void
525  ELdestination::fillUsrMsg(ostringstream& oss, ErrorObj const& msg)
526  {
527  if (!format_.want(TEXT)) {
528  return;
529  }
530  // Determine if file and line should be included
531  if (!msg.is_verbatim()) {
532  if (!msg.filename().empty()) {
533  emitToken(oss, " "s);
534  emitToken(oss, msg.filename());
535  emitToken(oss, ":"s);
536  emitToken(oss, to_string(msg.lineNumber()));
537  }
538  // Check for user-requested line breaks
539  if (format_.want(NO_LINE_BREAKS)) {
540  emitToken(oss, " ==> ");
541  } else {
542  emitToken(oss, "", true);
543  }
544  }
545  // Print the contents.
546  for (auto const& val : msg.items()) {
547  emitToken(oss, val);
548  }
549  }
550 
551  void
552  ELdestination::fillSuffix(ostringstream& oss, ErrorObj const& msg)
553  {
554  if (!msg.is_verbatim() && !format_.want(NO_LINE_BREAKS)) {
555  emitToken(oss, "\n%MSG");
556  }
557  oss << '\n';
558  }
559 
560  void
561  ELdestination::routePayload(ostringstream const&, ErrorObj const&)
562  {}
563 
564  void
566  {
567  if (msg.xid().severity() < threshold_) {
568  if (outputStatistics_) {
569  statsMap_[msg.xid()].add(summarizeContext(msg.context()), false);
570  updatedStats_ = true;
571  }
572  return;
573  }
574  if (skipMsg(msg.xid())) {
575  if (outputStatistics_) {
576  statsMap_[msg.xid()].add(summarizeContext(msg.context()), false);
577  updatedStats_ = true;
578  }
579  return;
580  }
581  msg.setReactedTo(true);
582  ostringstream payload;
583  fillPrefix(payload, msg);
584  fillUsrMsg(payload, msg);
585  fillSuffix(payload, msg);
586  routePayload(payload, msg);
587  if (outputStatistics_) {
588  statsMap_[msg.xid()].add(summarizeContext(msg.context()), true);
589  updatedStats_ = true;
590  }
591  }
592 
593  string
595  {
596  ostringstream s;
597  int n{};
598  // ----- Summary part I:
599  //
600  bool ftnote{false};
601  struct part3 {
602  long n{}, t{};
604  for (auto const& pr : statsMap_) {
605  auto const& xid = pr.first;
606  auto const& count = pr.second;
607  auto const& cat = xid.id();
608  // ----- Emit new part I header, if needed:
609  //
610  if (n == 0) {
611  s << "\n";
612  s << " type category sev module subroutine "
613  " count total\n"
614  << " ---- -------------------- -- ---------------- "
615  "---------------- ----- -----\n";
616  }
617  // ----- Emit detailed message information:
618  //
619  s
620  // Type
621  << right << setw(5) << ++n
622  << ' '
623  // Category
624  << left << setw(20) << cat.substr(0, 20)
625  << ' '
626  // Severity
627  << left << setw(2) << xid.severity().getSymbol()
628  << ' '
629  // Module
630  << left << setw(16) << xid.module().substr(0, 16)
631  << ' '
632  // Subroutine
633  << left << setw(16)
634  << xid.subroutine().substr(0, 16)
635  // Count
636  << right << setw(7) << count.n_ << left << setw(1)
637  << (count.ignoredFlag_ ? '*' : ' ')
638  // Total Count
639  << right << setw(8) << count.aggregateN_ << '\n';
640  ftnote = ftnote || count.ignoredFlag_;
641  // ----- Obtain information for Part III, below:
642  //
643  p3[xid.severity().getLevel()].n += count.n_;
644  p3[xid.severity().getLevel()].t += count.aggregateN_;
645  }
646  // ----- Provide footnote to part I, if needed:
647  //
648  if (ftnote) {
649  s << "\n* Some occurrences of this message were suppressed in all "
650  "logs, due to limits.\n";
651  }
652  // ----- Summary part II:
653  //
654  n = 0;
655  for (auto const& pr : statsMap_) {
656  auto const& xid = pr.first;
657  auto const& count = pr.second;
658  string const& cat = xid.id();
659  if (n == 0) {
660  s << '\n'
661  << " type category Examples: run/evt run/evt "
662  "run/evt\n"
663  << " ---- -------------------- ---------------- ---------------- "
664  "----------------\n";
665  }
666  s
667  // Type
668  << right << setw(5) << ++n
669  << ' '
670  // Category
671  << left << setw(20) << cat
672  << ' '
673  // Context1
674  << left << setw(16) << count.context1_.c_str()
675  << ' '
676  // Context2
677  << left << setw(16) << count.context2_.c_str()
678  << ' '
679  // ContextLast
680  << count.contextLast_ << '\n';
681  }
682  // ----- Summary part III:
683  //
684  s << '\n'
685  << "Severity # Occurrences Total Occurrences\n"
686  << "-------- ------------- -----------------\n";
687  for (int k = 0; k < ELseverityLevel::nLevels; ++k) {
688  if (p3[k].n != 0 || p3[k].t != 0) {
689  s
690  // Severity
691  << left << setw(8)
692  << ELseverityLevel{ELseverityLevel::ELsev_(k)}.getName().c_str()
693  // Occurrences
694  << right << setw(17)
695  << p3[k].n
696  // Total Occurrences
697  << right << setw(20) << p3[k].t << '\n';
698  }
699  }
700  return s.str();
701  }
702 
703  // Called only by MessageLoggerScribe::summarize()
704  // Called only by MessageLogger::LogStatistics()
705  void
707  {
709  ostringstream payload;
710  payload << "\n=============================================\n\n"
711  << "MessageLogger Summary\n"
712  << formSummary();
713  routePayload(payload, ErrorObj{ELzeroSeverity, "No ostream"s});
714  }
715  updatedStats_ = false;
716  if (reset_) {
718  resetLimiters();
719  }
720  }
721 
722  void
724  {}
725 
726  // Used only by MessageLoggerScribe to disable
727  // cerr_early once startup is complete.
728  void
730  {
731  threshold_ = sv;
732  }
733 
734  void
736  {
737  ErrorObj msg{ELwarning, "ELdestination"s};
738  msg << "Call to unimplemented flush()!";
739  log(msg);
740  }
741 
742  // A return value of true tells the destination
743  // to not log this message.
744  // Called by ELdestination log().
745  bool
747  {
748  auto xl_iter = xidLimiters_.find(xid);
749  if (xl_iter == xidLimiters_.end()) {
750  // Need to create and initialize a limiter for this xid.
751  int limit{defaultLimit_};
752  int reportEvery{defaultReportEvery_};
753  int timespan{defaultTimespan_};
754  // Does the category of this xid have explicit limits?
755  auto cp_iter = categoryParams_.find(xid.id());
756  if (cp_iter != categoryParams_.end()) {
757  // Category limits found, use them.
758  auto const& cp = cp_iter->second;
759  limit = (cp.limit_ < 0) ? defaultLimit_ : cp.limit_;
760  reportEvery =
761  (cp.reportEvery_ < 0) ? defaultReportEvery_ : cp.reportEvery_;
762  timespan = (cp.timespan_ < 0) ? defaultTimespan_ : cp.timespan_;
763  }
764  XidLimiter& limiter = xidLimiters_[xid];
765  limiter.previousTimestamp_ = time(0);
766  limiter.msgCount_ = 0;
767  limiter.skippedMsgCount_ =
768  reportEvery -
769  1; // So that the FIRST of the prescaled messages emerges
770  limiter.limit_ = limit;
771  limiter.reportEvery_ = reportEvery;
772  limiter.timespan_ = timespan;
773  xl_iter = xidLimiters_.find(xid);
774  }
775  XidLimiter& limiter = xl_iter->second;
776  time_t now = time(0);
777  // Has it been so long that we should restart counting toward the limit?
778  if ((limiter.timespan_ >= 0) &&
779  (difftime(now, limiter.previousTimestamp_) >= limiter.timespan_)) {
780  limiter.msgCount_ = 0;
781  if (limiter.reportEvery_ > 0) {
782  // So this message will be reacted to
783  limiter.skippedMsgCount_ = limiter.reportEvery_ - 1;
784  } else {
785  limiter.skippedMsgCount_ = 0;
786  }
787  }
788  limiter.previousTimestamp_ = now;
789  ++limiter.msgCount_;
790  ++limiter.skippedMsgCount_;
791  if (limiter.skippedMsgCount_ < limiter.reportEvery_) {
792  // Skip message.
793  return true;
794  }
795  if (limiter.limit_ == 0) {
796  // Zero limit - never react to this
797  // Skip message.
798  return true;
799  }
800  if ((limiter.limit_ < 0) || (limiter.msgCount_ <= limiter.limit_)) {
801  limiter.skippedMsgCount_ = 0;
802  // Accept message.
803  return false;
804  }
805  // Now we are over the limit - have we exceeded limit by 2^N * limit?
806  long diff = limiter.msgCount_ - limiter.limit_;
807  long r = diff / limiter.limit_;
808  if (r * limiter.limit_ != diff) {
809  // Not a multiple of limit - don't react
810  // Skip message.
811  return true;
812  }
813  if (r == 1) {
814  // Exactly twice limit - react
815  limiter.skippedMsgCount_ = 0;
816  // Accept message.
817  return false;
818  }
819  while (r > 1) {
820  if ((r & 1) != 0) {
821  // Not 2**msgCount_ times limit - don't react
822  // Skip message.
823  return true;
824  }
825  r >>= 1;
826  }
827  // If you never get an odd number till one, r is 2**msgCount_ so react
828  limiter.skippedMsgCount_ = 0;
829  // Accept message.
830  return false;
831  }
832 
833  void
835  {
836  statsMap_.clear();
837  }
838 
839  void
841  {
842  xidLimiters_.clear();
843  }
844 
845  } // namespace service
846 } // namespace mf
int lineNumber() const
Definition: ErrorObj.cc:126
fhicl::Table< MsgFormatSettings::Config > format
Float_t s
Definition: plot.C:23
ELseverityLevel severity() const
Definition: ELextendedID.cc:33
virtual void fillUsrMsg(std::ostringstream &, mf::ErrorObj const &msg)
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
bool skipMsg(ELextendedID const &)
timeval timestamp() const
Definition: ErrorObj.cc:73
fhicl::TableFragment< MsgStatistics::Config > msgStatistics
void add(std::string const &context, bool reactedTo)
void emitToken(std::ostream &os, std::string const &s, bool nl=false, bool preambleMode=false)
STL namespace.
fhicl::OptionalDelegatedParameter categories
virtual void fillSuffix(std::ostringstream &, mf::ErrorObj const &msg)
std::map< std::string const, CategoryParams > categoryParams_
virtual void log(mf::ErrorObj &)
std::list< std::string > const & items() const
Definition: ErrorObj.cc:79
std::string bold_fontify(std::string const &s)
Definition: bold_fontify.h:9
std::string const & context() const
Definition: ErrorObj.cc:98
bool is_verbatim() const
Definition: ErrorObj.cc:91
fhicl::Atom< std::string > threshold
fhicl::Atom< unsigned long long > lineLength
std::string const & idOverflow() const
Definition: ErrorObj.cc:67
Int_t max
Definition: plot.C:27
std::map< ELextendedID const, StatsCount > statsMap_
std::string summarizeContext(std::string const &)
ELslProxy< ELzeroSeverityGen > constexpr ELzeroSeverity
ELextendedID const & xid() const
Definition: ErrorObj.cc:61
ELslProxy< ELwarningGen > constexpr ELwarning
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
std::string indent(std::size_t const i)
std::string const & filename() const
Definition: ErrorObj.cc:120
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
ELdestination(Config const &)
ELseverityLevel threshold_
std::string const & id() const
Definition: ELextendedID.cc:27
int serial() const
Definition: ErrorObj.cc:55
fhicl::Atom< bool > outputStatistics
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
char const * what() const noexcept override
std::string value(boost::any const &)
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
virtual void fillPrefix(std::ostringstream &, mf::ErrorObj const &msg)
virtual void setReactedTo(bool)
Definition: ErrorObj.cc:177
MsgFormatSettings format_
Char_t n[5]
void setThreshold(ELseverityLevel sv)
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
std::map< ELextendedID const, XidLimiter > xidLimiters_
Float_t e
Definition: plot.C:34
std::string nl(std::size_t i=1)
virtual void routePayload(std::ostringstream const &, mf::ErrorObj const &msg)
Event finding and building.