artdaq_mfextensions  v1_05_00
Friendly_mfPlugin.cc
1 #include "cetlib/PluginTypeDeducer.h"
2 #include "cetlib/ostream_handle.h"
3 #include "fhiclcpp/ParameterSet.h"
4 
5 #include "cetlib/compiler_macros.h"
6 #include "messagefacility/MessageService/ELdestination.h"
7 #include "messagefacility/MessageService/ELostreamOutput.h"
8 #include "messagefacility/Utilities/ELseverityLevel.h"
9 #include "messagefacility/Utilities/exception.h"
10 
11 // C/C++ includes
12 #include <algorithm>
13 #include <iostream>
14 #include <memory>
15 
16 namespace mfplugins {
17 using namespace mf::service;
18 using mf::ErrorObj;
19 
23 class ELFriendly : public ELostreamOutput
24 {
25 public:
29  struct Config
30  {
32  fhicl::TableFragment<ELostreamOutput::Config> elOstrConfig;
34  fhicl::Atom<std::string> delimiter = fhicl::Atom<std::string>{
35  fhicl::Name{"field_delimiter"}, fhicl::Comment{"String to print between each message field"}, " "};
36  };
38  using Parameters = fhicl::WrappedTable<Config>;
39 
40 public:
45  explicit ELFriendly(Parameters const& pset);
46 
52  void fillPrefix(std::ostringstream& o, const ErrorObj& msg) override;
58  void fillUsrMsg(std::ostringstream& o, const ErrorObj& msg) override;
64  void fillSuffix(std::ostringstream& o, const ErrorObj& msg) override;
65 
66 private:
67  std::string delimeter_;
68 };
69 
70 // END DECLARATION
71 //======================================================================
72 // BEGIN IMPLEMENTATION
73 
74 //======================================================================
75 // ELFriendly c'tor
76 //======================================================================
77 
79  : ELostreamOutput(pset().elOstrConfig(), cet::ostream_handle{std::cout}, false), delimeter_(pset().delimiter()) {}
80 
81 //======================================================================
82 // Message prefix filler ( overriddes ELdestination::fillPrefix )
83 //======================================================================
84 void ELFriendly::fillPrefix(std::ostringstream& oss, const ErrorObj& msg)
85 {
86  // if (msg.is_verbatim()) return;
87 
88  // Output the prologue:
89  //
90 
91  auto const& xid = msg.xid();
92 
93  auto id = xid.id();
94  auto app = xid.application();
95  auto module = xid.module();
96  auto subroutine = xid.subroutine();
97  std::replace(id.begin(), id.end(), ' ', '-');
98  std::replace(app.begin(), app.end(), ' ', '-');
99  std::replace(module.begin(), module.end(), ' ', '-');
100  std::replace(subroutine.begin(), subroutine.end(), ' ', '-');
101 
102  emitToken(oss, "%MSG");
103  emitToken(oss, xid.severity().getSymbol());
104  emitToken(oss, delimeter_);
105  emitToken(oss, id);
106  emitToken(oss, msg.idOverflow());
107  emitToken(oss, ":");
108  emitToken(oss, delimeter_);
109 
110  // Output serial number of message:
111  //
112  if (format_.want(SERIAL))
113  {
114  std::ostringstream s;
115  s << msg.serial();
116  emitToken(oss, "[serial #" + s.str() + "]");
117  emitToken(oss, delimeter_);
118  }
119 
120  // Provide further identification:
121  //
122  bool needAspace = true;
123  if (format_.want(EPILOGUE_SEPARATE))
124  {
125  if (module.length() + subroutine.length() > 0)
126  {
127  emitToken(oss, "\n");
128  needAspace = false;
129  }
130  else if (format_.want(TIMESTAMP) && !format_.want(TIME_SEPARATE))
131  {
132  emitToken(oss, "\n");
133  needAspace = false;
134  }
135  }
136  if (format_.want(MODULE) && (module.length() > 0))
137  {
138  if (needAspace)
139  {
140  emitToken(oss, delimeter_);
141  needAspace = false;
142  }
143  emitToken(oss, module + " ");
144  }
145  if (format_.want(SUBROUTINE) && (subroutine.length() > 0))
146  {
147  if (needAspace)
148  {
149  emitToken(oss, delimeter_);
150  needAspace = false;
151  }
152  emitToken(oss, subroutine + "()");
153  emitToken(oss, delimeter_);
154  }
155 
156  // Provide time stamp:
157  //
158  if (format_.want(TIMESTAMP))
159  {
160  if (format_.want(TIME_SEPARATE))
161  {
162  emitToken(oss, "\n");
163  needAspace = false;
164  }
165  if (needAspace)
166  {
167  emitToken(oss, delimeter_);
168  needAspace = false;
169  }
170  emitToken(oss, format_.timestamp(msg.timestamp()));
171  emitToken(oss, delimeter_);
172  }
173 
174  // Provide the context information:
175  //
176  if (format_.want(SOME_CONTEXT))
177  {
178  if (needAspace)
179  {
180  emitToken(oss, delimeter_);
181  // needAspace = false; // Uncomment this line if more fields are added in the future
182  }
183  emitToken(oss, msg.context());
184  }
185 }
186 
187 //=============================================================================
188 void ELFriendly::fillUsrMsg(std::ostringstream& oss, ErrorObj const& msg)
189 {
190  if (!format_.want(TEXT))
191  {
192  return;
193  }
194 
195  auto const usrMsgStart = std::next(msg.items().cbegin(), 4);
196  auto it = msg.items().cbegin();
197 
198  // Determine if file and line should be included
199 
200  // The first four items are { " ", "<FILENAME>", ":", "<LINE>" }
201  while (it != usrMsgStart)
202  {
203  if ((*it == " ") && (*std::next(it) == "--"))
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))
217  {
218  emitToken(oss, " ==> ");
219  }
220  else
221  {
222  emitToken(oss, "", true);
223  }
224 
225  // For verbatim (and user-supplied) messages, just print the contents
226  auto const end = msg.items().cend();
227  for (; it != end; ++it)
228  {
229  emitToken(oss, *it);
230  }
231 }
232 
233 //=============================================================================
234 void ELFriendly::fillSuffix(std::ostringstream& oss, ErrorObj const& /*msg*/)
235 {
236  if (!format_.want(NO_LINE_BREAKS))
237  {
238  emitToken(oss, "\n%MSG");
239  }
240  oss << '\n';
241 }
242 
243 } // end namespace mfplugins
244 
245 //======================================================================
246 //
247 // makePlugin function
248 //
249 //======================================================================
250 
251 #ifndef EXTERN_C_FUNC_DECLARE_START
252 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
253 #endif
254 
255 EXTERN_C_FUNC_DECLARE_START
256 auto makePlugin(const std::string& /*unused*/, 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
void fillUsrMsg(std::ostringstream &o, const ErrorObj &msg) override
Fill the &quot;User Message&quot; portion of the message.
ELFriendly(Parameters const &pset)
ELFriendly Constructor
void fillPrefix(std::ostringstream &o, const ErrorObj &msg) override
Fill the &quot;Prefix&quot; portion of the message.
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation.
fhicl::TableFragment< ELostreamOutput::Config > elOstrConfig
Configuration parameters for ELostreamOutput.
Configuration Parameters for ELFriendly.
void fillSuffix(std::ostringstream &o, const ErrorObj &msg) override
Fill the &quot;Suffix&quot; portion of the message.