artdaq_mfextensions  v1_04_00
OTS_mfPlugin.cc
1 #include "cetlib/PluginTypeDeducer.h"
2 #include "fhiclcpp/ParameterSet.h"
3 
4 #include "cetlib/compiler_macros.h"
5 #include "messagefacility/MessageLogger/MessageLogger.h"
6 #include "messagefacility/MessageService/ELdestination.h"
7 #include "messagefacility/Utilities/ELseverityLevel.h"
8 #include "messagefacility/Utilities/exception.h"
9 
10 // C/C++ includes
11 #include <arpa/inet.h>
12 #include <ifaddrs.h>
13 #include <netdb.h>
14 #include <netinet/in.h>
15 #include <algorithm>
16 #include <fstream>
17 #include <iostream>
18 #include <memory>
20 
21 #define TRACE_NAME "OTS_mfPlugin"
22 #include "trace.h"
23 
24 // Boost includes
25 #include <boost/algorithm/string.hpp>
26 
27 namespace mfplugins {
28 using mf::ELseverityLevel;
29 using mf::ErrorObj;
30 using mf::service::ELdestination;
31 
36 class ELOTS : public ELdestination
37 {
38 public:
42  struct Config
43  {
45  fhicl::TableFragment<ELdestination::Config> elDestConfig;
47  fhicl::Atom<std::string> format_string = fhicl::Atom<std::string>{
48  fhicl::Name{"format_string"}, fhicl::Comment{"Format specifier for printing to console. %% => '%' ... "},
49  "%L:%N:%f [%u] %m"};
51  fhicl::Atom<std::string> filename_delimit =
52  fhicl::Atom<std::string>{fhicl::Name{"filename_delimit"},
53  fhicl::Comment{"Grab path after this. \"/srcs/\" /x/srcs/y/z.cc => y/z.cc"}, "/"};
54  };
56  using Parameters = fhicl::WrappedTable<Config>;
57 
58 public:
63  ELOTS(Parameters const& pset);
64 
70  virtual void fillPrefix(std::ostringstream& o, const ErrorObj& e) override;
71 
77  virtual void fillUsrMsg(std::ostringstream& o, const ErrorObj& e) override;
78 
82  virtual void fillSuffix(std::ostringstream&, const ErrorObj&) override {}
83 
89  virtual void routePayload(const std::ostringstream& o, const ErrorObj& e) override;
90 
91 private:
92  // Other stuff
93  long pid_;
94  std::string hostname_;
95  std::string hostaddr_;
96  std::string app_;
97  std::string format_string_;
98  std::string filename_delimit_;
99 };
100 
101 // END DECLARATION
102 //======================================================================
103 // BEGIN IMPLEMENTATION
104 
105 //======================================================================
106 // ELOTS c'tor
107 //======================================================================
108 
110  : ELdestination(pset().elDestConfig()), pid_(static_cast<long>(getpid())), format_string_(pset().format_string()), filename_delimit_(pset().filename_delimit())
111 {
112  // hostname
113  char hostname_c[1024];
114  hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c : "Unkonwn Host";
115 
116  // host ip address
117  hostent* host = nullptr;
118  host = gethostbyname(hostname_c);
119 
120  if (host != nullptr)
121  {
122  // ip address from hostname if the entry exists in /etc/hosts
123  char* ip = inet_ntoa(*(struct in_addr*)host->h_addr);
124  hostaddr_ = ip;
125  }
126  else
127  {
128  // enumerate all network interfaces
129  struct ifaddrs* ifAddrStruct = nullptr;
130  struct ifaddrs* ifa = nullptr;
131  void* tmpAddrPtr = nullptr;
132 
133  if (getifaddrs(&ifAddrStruct))
134  {
135  // failed to get addr struct
136  hostaddr_ = "127.0.0.1";
137  }
138  else
139  {
140  // iterate through all interfaces
141  for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
142  {
143  if (ifa->ifa_addr->sa_family == AF_INET)
144  {
145  // a valid IPv4 addres
146  tmpAddrPtr = &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
147  char addressBuffer[INET_ADDRSTRLEN];
148  inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
149  hostaddr_ = addressBuffer;
150  }
151 
152  else if (ifa->ifa_addr->sa_family == AF_INET6)
153  {
154  // a valid IPv6 address
155  tmpAddrPtr = &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
156  char addressBuffer[INET6_ADDRSTRLEN];
157  inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
158  hostaddr_ = addressBuffer;
159  }
160 
161  // find first non-local address
162  if (!hostaddr_.empty() && hostaddr_.compare("127.0.0.1") && hostaddr_.compare("::1")) break;
163  }
164 
165  if (hostaddr_.empty()) // failed to find anything
166  hostaddr_ = "127.0.0.1";
167  }
168  }
169 
170  // get process name from '/proc/pid/cmdline'
171  std::stringstream ss;
172  ss << "//proc//" << pid_ << "//cmdline";
173  std::ifstream procfile{ss.str().c_str()};
174 
175  std::string procinfo;
176 
177  if (procfile.is_open())
178  {
179  procfile >> procinfo;
180  procfile.close();
181  }
182 
183  size_t end = procinfo.find('\0');
184  size_t start = procinfo.find_last_of('/', end);
185 
186  app_ = procinfo.substr(start + 1, end - start - 1);
187 }
188 
189 //======================================================================
190 // Message prefix filler ( overriddes ELdestination::fillPrefix )
191 //======================================================================
192 void ELOTS::fillPrefix(std::ostringstream& oss, const ErrorObj& msg)
193 {
194  const auto& xid = msg.xid();
195 
196  auto id = xid.id();
197  auto module = xid.module();
198  auto app = app_;
199  char* cp = &format_string_[0];
200  char sev;
201  bool msg_printed = false;
202  std::string ossstr;
203  // ossstr.reserve(100);
204 
205  for (; *cp; ++cp)
206  {
207  if (*cp != '%')
208  {
209  oss << *cp;
210  continue;
211  }
212  if (*++cp == '\0')
213  { // inc pas '%' and check if end
214  // ending '%' gets printed
215  oss << *cp;
216  break; // done
217  }
218  switch (*cp)
219  {
220  case 'A':
221  oss << app;
222  break; // application
223  case 'a':
224  oss << hostaddr_;
225  break; // host address
226  case 'd':
227  oss << module;
228  break; // module name # Early
229  case 'f': // filename
230  if (filename_delimit_.size() == 0)
231  oss << msg.filename();
232  else if (filename_delimit_.size() == 1)
233  oss << (strrchr(&msg.filename()[0], filename_delimit_[0])
234  ? strrchr(&msg.filename()[0], filename_delimit_[0]) + 1
235  : msg.filename());
236  else
237  oss << (strstr(&msg.filename()[0], &filename_delimit_[0])
238  ? strstr(&msg.filename()[0], &filename_delimit_[0]) + filename_delimit_.size()
239  : msg.filename());
240  break;
241  case 'h':
242  oss << hostname_;
243  break; // host name
244  case 'L':
245  oss << xid.severity().getName();
246  break; // severity
247  case 'm': // message
248  // ossstr.clear(); // incase message is repeated
249  for (auto const& val : msg.items()) ossstr += val; // Print the contents.
250  if (ossstr.size())
251  { // allow/check for "no message"
252  if (ossstr.compare(0, 1, "\n") == 0) ossstr.erase(0, 1); // remove leading "\n" if present
253  if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
254  ossstr.erase(ossstr.size() - 1, 1); // remove trailing "\n" if present
255  oss << ossstr;
256  }
257  msg_printed = true;
258  break;
259  case 'N':
260  oss << id;
261  break; // category
262  case 'P':
263  oss << pid_;
264  break; // processID
265  case 'r':
266  oss << mf::GetIteration();
267  break; // run/iteration/event no #pre-events
268  case 's':
269  sev = xid.severity().getName()[0] | 0x20;
270  oss << sev;
271  break; // severity lower case
272  case 'T':
273  oss << format_.timestamp(msg.timestamp());
274  break; // timestamp
275  case 'u':
276  oss << std::to_string(msg.lineNumber());
277  break; // linenumber
278  case '%':
279  oss << '%';
280  break; // a '%' character
281  default:
282  oss << '%' << *cp;
283  break; // unknown - just print it w/ it's '%'
284  }
285  }
286  if (!msg_printed)
287  {
288  for (auto const& val : msg.items()) ossstr += val; // Print the contents.
289  if (ossstr.compare(0, 1, "\n") == 0) ossstr.erase(0, 1); // remove leading "\n" if present
290  if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
291  ossstr.erase(ossstr.size() - 1, 1); // remove trailing "\n" if present
292  oss << ossstr;
293  }
294 }
295 
296 //======================================================================
297 // Message filler ( overriddes ELdestination::fillUsrMsg )
298 //======================================================================
299 void ELOTS::fillUsrMsg(std::ostringstream& oss __attribute__((__unused__)),
300  const ErrorObj& msg __attribute__((__unused__)))
301 {
302  return; // UsrMsg filled above
303 }
304 
305 //======================================================================
306 // Message router ( overriddes ELdestination::routePayload )
307 //======================================================================
308 void ELOTS::routePayload(const std::ostringstream& oss, const ErrorObj&) { std::cout << oss.str() << std::endl; }
309 } // end namespace mfplugins
310 //======================================================================
311 //
312 // makePlugin function
313 //
314 //======================================================================
315 
316 #ifndef EXTERN_C_FUNC_DECLARE_START
317 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
318 #endif
319 
320 EXTERN_C_FUNC_DECLARE_START auto makePlugin(const std::string&, const fhicl::ParameterSet& pset)
321 {
322  return std::make_unique<mfplugins::ELOTS>(pset);
323 }
324 } // namespace mfplugins
325 
326 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Configuration Parameters for ELOTS.
Definition: OTS_mfPlugin.cc:42
fhicl::Atom< std::string > filename_delimit
filename_delimit (Default: &quot;/&quot;): Grab path after this. &quot;/srcs/&quot; /x/srcs/y/z.cc =&gt; y/z...
Definition: OTS_mfPlugin.cc:51
virtual void fillUsrMsg(std::ostringstream &o, const ErrorObj &e) override
Fill the &quot;User Message&quot; portion of the message.
fhicl::TableFragment< ELdestination::Config > elDestConfig
ELDestination common config parameters.
Definition: OTS_mfPlugin.cc:45
virtual void routePayload(const std::ostringstream &o, const ErrorObj &e) override
Serialize a MessageFacility message to the output.
fhicl::Atom< std::string > format_string
format_string (Default: &quot;%L:%N:%f [%u] %m&quot;): Format specifier for printing to console. %% =&gt; &#39;&#39; ...
Definition: OTS_mfPlugin.cc:47
Message Facility OTS Console Destination Formats messages into Ryan&#39;s favorite format for OTS ...
Definition: OTS_mfPlugin.cc:36
virtual void fillPrefix(std::ostringstream &o, const ErrorObj &e) override
Fill the &quot;Prefix&quot; portion of the message.
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation.
Definition: OTS_mfPlugin.cc:56
virtual void fillSuffix(std::ostringstream &, const ErrorObj &) override
Fill the &quot;Suffix&quot; portion of the message (Unused)
Definition: OTS_mfPlugin.cc:82
ELOTS(Parameters const &pset)
ELOTS Constructor