artdaq_mfextensions  v1_03_00
Friendly_mfPlugin.cc
1 #include "cetlib/PluginTypeDeducer.h"
2 #include "cetlib/ostream_handle.h"
3 #include "fhiclcpp/ParameterSet.h"
4 
5 #include "messagefacility/MessageService/ELdestination.h"
6 #include "messagefacility/MessageService/ELostreamOutput.h"
7 #include "messagefacility/Utilities/ELseverityLevel.h"
8 #if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
9 # include "messagefacility/MessageService/ELcontextSupplier.h"
10 # include "messagefacility/MessageLogger/MessageDrop.h"
11 #endif
12 #include "messagefacility/Utilities/exception.h"
13 #include "cetlib/compiler_macros.h"
14 
15 // C/C++ includes
16 #include <iostream>
17 #include <memory>
18 #include <algorithm>
19 
20 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
21 #define format_ format
22 #endif
23 
24 namespace mfplugins
25 {
26  using namespace mf::service;
27  using mf::ELseverityLevel;
28  using mf::ErrorObj;
29 
33  class ELFriendly : public ELostreamOutput
34  {
35 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
36  struct Config
37  {
38  fhicl::TableFragment<ELostreamOutput::Config> elOstrConfig;
39  fhicl::Atom<std::string> delimiter{ fhicl::Name{ "field_delimiter" },fhicl::Comment{ "String to print between each message field" }," " };
40  };
41  using Parameters = fhicl::WrappedTable<Config>;
42 #endif
43  public:
44 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
45  ELFriendly(const fhicl::ParameterSet& pset);
46 #else
47  ELFriendly(Parameters const& pset);
48 #endif
49 
50 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
51  virtual void fillPrefix(std::ostringstream&, const ErrorObj&) override;
52 # else
53  virtual void fillPrefix(std::ostringstream&, const ErrorObj&, const ELcontextSupplier&) override;
54 # endif
55  virtual void fillUsrMsg(std::ostringstream&, const ErrorObj&) override;
56  virtual void fillSuffix(std::ostringstream&, const ErrorObj&) override;
57 
58  private:
59  std::string delimeter_;
60  };
61 
62  // END DECLARATION
63  //======================================================================
64  // BEGIN IMPLEMENTATION
65 
66 
67  //======================================================================
68  // ELFriendly c'tor
69  //======================================================================
70 
71 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
72  ELFriendly::ELFriendly(const fhicl::ParameterSet& pset)
73  : ELostreamOutput(pset, cet::ostream_handle{ std::cout }, false)
74  , delimeter_(pset.get<std::string>("field_delimeter", " "))
75 #else
76  ELFriendly::ELFriendly(Parameters const& pset)
77  : ELostreamOutput(pset().elOstrConfig(), cet::ostream_handle{ std::cout }, false)
78  , delimeter_(pset().delimiter())
79 #endif
80  {}
81 
82  //======================================================================
83  // Message prefix filler ( overriddes ELdestination::fillPrefix )
84  //======================================================================
85 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
86  void ELFriendly::fillPrefix(std::ostringstream& oss, const ErrorObj& msg)
87 # else
88  void ELFriendly::fillPrefix(std::ostringstream& oss, const ErrorObj& msg, ELcontextSupplier const& contextSupplier)
89 # endif
90  {
91  //if (msg.is_verbatim()) return;
92 
93  // Output the prologue:
94  //
95 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
96  format_.preambleMode = true;
97 #endif
98 
99  auto const& xid = msg.xid();
100 
101 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
102  auto id = xid.id();
103  auto app = xid.application();
104  auto module = xid.module();
105  auto subroutine = xid.subroutine();
106 # else
107  auto id = xid.id;
108  auto app = xid.application;
109  auto process = xid.process;
110  auto module = xid.module;
111  auto subroutine = xid.subroutine;
112  std::replace(process.begin(), process.end(), ' ', '-');
113 # define emitToken emit
114 # endif
115  std::replace(id.begin(), id.end(), ' ', '-');
116  std::replace(app.begin(), app.end(), ' ', '-');
117  std::replace(module.begin(), module.end(), ' ', '-');
118  std::replace(subroutine.begin(), subroutine.end(), ' ', '-');
119 
120  emitToken(oss, "%MSG");
121 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
122  emitToken(oss, xid.severity().getSymbol());
123 # else
124  emit(oss, xid.severity.getSymbol());
125 # endif
126  emitToken(oss, delimeter_);
127  emitToken(oss, id);
128  emitToken(oss, msg.idOverflow());
129  emitToken(oss, ":");
130  emitToken(oss, delimeter_);
131 
132  // Output serial number of message:
133  //
134  if (format_.want(SERIAL)) {
135  std::ostringstream s;
136  s << msg.serial();
137  emitToken(oss, "[serial #" + s.str() + "]");
138  emitToken(oss, delimeter_);
139  }
140 
141  // Provide further identification:
142  //
143  bool needAspace = true;
144  if (format_.want(EPILOGUE_SEPARATE)) {
145  if (module.length() + subroutine.length() > 0) {
146  emitToken(oss, "\n");
147  needAspace = false;
148  }
149  else if (format_.want(TIMESTAMP) && !format_.want(TIME_SEPARATE)) {
150  emitToken(oss, "\n");
151  needAspace = false;
152  }
153  }
154  if (format_.want(MODULE) && (module.length() > 0)) {
155  if (needAspace) {
156  emitToken(oss, delimeter_);
157  needAspace = false;
158  }
159  emitToken(oss, module + " ");
160  }
161  if (format_.want(SUBROUTINE) && (subroutine.length() > 0)) {
162  if (needAspace) {
163  emitToken(oss, delimeter_);
164  needAspace = false;
165  }
166  emitToken(oss, subroutine + "()");
167  emitToken(oss, delimeter_);
168  }
169 
170  // Provide time stamp:
171  //
172  if (format_.want(TIMESTAMP)) {
173  if (format_.want(TIME_SEPARATE)) {
174  emitToken(oss, "\n");
175  needAspace = false;
176  }
177  if (needAspace) {
178  emitToken(oss, delimeter_);
179  needAspace = false;
180  }
181  emitToken(oss, format_.timestamp(msg.timestamp()));
182  emitToken(oss, delimeter_);
183  }
184 
185  // Provide the context information:
186  //
187  if (format_.want(SOME_CONTEXT)) {
188  if (needAspace) {
189  emitToken(oss, delimeter_);
190  needAspace = false;
191  }
192 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
193  emitToken(oss, msg.context());
194 # else
195  if (format_.want(FULL_CONTEXT)) {
196  emit(oss, contextSupplier.fullContext());
197  }
198  else {
199  emit(oss, contextSupplier.context());
200  }
201 # endif
202  }
203 
204  }
205 
206 
207  //=============================================================================
208  void ELFriendly::fillUsrMsg(std::ostringstream& oss, ErrorObj const& msg)
209  {
210  if (!format_.want(TEXT)) return;
211 
212 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
213  format_.preambleMode = false;
214 #endif
215  auto const usrMsgStart = std::next(msg.items().cbegin(), 4);
216  auto it = msg.items().cbegin();
217 
218  // Determine if file and line should be included
219  if (true || !msg.is_verbatim()) {
220 
221  // The first four items are { " ", "<FILENAME>", ":", "<LINE>" }
222  while (it != usrMsgStart) {
223  if (!it->compare(" ") && !std::next(it)->compare("--")) {
224  // Do not emit if " --:0" is the match
225  std::advance(it,4);
226  }
227  else {
228  // Emit if <FILENAME> and <LINE> are meaningful
229  emitToken(oss, *it++);
230  }
231  }
232 
233  // Check for user-requested line breaks
234  if (format_.want(NO_LINE_BREAKS)) emitToken(oss, " ==> ");
235  else emitToken(oss, "", true);
236  }
237 
238  // For verbatim (and user-supplied) messages, just print the contents
239  auto const end = msg.items().cend();
240  for (; it != end; ++it) {
241  emitToken(oss, *it);
242  }
243 
244  }
245 
246 
247  //=============================================================================
248  void ELFriendly::fillSuffix(std::ostringstream& oss, ErrorObj const& msg)
249  {
250  if ((true || !msg.is_verbatim()) && !format_.want(NO_LINE_BREAKS)) {
251  emitToken(oss,"\n%MSG");
252  }
253  oss << '\n';
254  }
255 
256 
257 
258 } // end namespace mfplugins
259 
260 //======================================================================
261 //
262 // makePlugin function
263 //
264 //======================================================================
265 
266 #ifndef EXTERN_C_FUNC_DECLARE_START
267 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
268 #endif
269 
270 EXTERN_C_FUNC_DECLARE_START
271  auto makePlugin(const std::string&,
272  const fhicl::ParameterSet& pset)
273  {
274  return std::make_unique<mfplugins::ELFriendly>(pset);
275  }
276 }
277 
278 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Parser-Friendly Message Facility destination plugin