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