artdaq_mfextensions  v1_03_06
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  public:
41  struct Config {
43  fhicl::TableFragment<ELdestination::Config> elDestConfig;
45  fhicl::Atom<std::string> format_string = fhicl::Atom<std::string>{
46  fhicl::Name{"format_string"}, fhicl::Comment{"Format specifier for printing to console. %% => '%' ... "},
47  "%L:%N:%f [%u] %m"};
49  fhicl::Atom<std::string> filename_delimit =
50  fhicl::Atom<std::string>{fhicl::Name{"filename_delimit"},
51  fhicl::Comment{"Grab path after this. \"/srcs/\" /x/srcs/y/z.cc => y/z.cc"}, "/"};
52  };
54  using Parameters = fhicl::WrappedTable<Config>;
55 
56  public:
61  ELOTS(Parameters const& pset);
62 
68  virtual void fillPrefix(std::ostringstream& o, const ErrorObj& e) override;
69 
75  virtual void fillUsrMsg(std::ostringstream& o, const ErrorObj& e) override;
76 
80  virtual void fillSuffix(std::ostringstream&, const ErrorObj&) override {}
81 
87  virtual void routePayload(const std::ostringstream& o, const ErrorObj& e) override;
88 
89  private:
90  // Other stuff
91  long pid_;
92  std::string hostname_;
93  std::string hostaddr_;
94  std::string app_;
95  std::string format_string_;
96  std::string filename_delimit_;
97 };
98 
99 // END DECLARATION
100 //======================================================================
101 // BEGIN IMPLEMENTATION
102 
103 //======================================================================
104 // ELOTS c'tor
105 //======================================================================
106 
108  : ELdestination(pset().elDestConfig()),
109  pid_(static_cast<long>(getpid())),
110  format_string_(pset().format_string()),
111  filename_delimit_(pset().filename_delimit()) {
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  // ip address from hostname if the entry exists in /etc/hosts
122  char* ip = inet_ntoa(*(struct in_addr*)host->h_addr);
123  hostaddr_ = ip;
124  } else {
125  // enumerate all network interfaces
126  struct ifaddrs* ifAddrStruct = nullptr;
127  struct ifaddrs* ifa = nullptr;
128  void* tmpAddrPtr = nullptr;
129 
130  if (getifaddrs(&ifAddrStruct)) {
131  // failed to get addr struct
132  hostaddr_ = "127.0.0.1";
133  } else {
134  // iterate through all interfaces
135  for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) {
136  if (ifa->ifa_addr->sa_family == AF_INET) {
137  // a valid IPv4 addres
138  tmpAddrPtr = &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
139  char addressBuffer[INET_ADDRSTRLEN];
140  inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
141  hostaddr_ = addressBuffer;
142  }
143 
144  else if (ifa->ifa_addr->sa_family == AF_INET6) {
145  // a valid IPv6 address
146  tmpAddrPtr = &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
147  char addressBuffer[INET6_ADDRSTRLEN];
148  inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
149  hostaddr_ = addressBuffer;
150  }
151 
152  // find first non-local address
153  if (!hostaddr_.empty() && hostaddr_.compare("127.0.0.1") && hostaddr_.compare("::1")) break;
154  }
155 
156  if (hostaddr_.empty()) // failed to find anything
157  hostaddr_ = "127.0.0.1";
158  }
159  }
160 
161  // get process name from '/proc/pid/cmdline'
162  std::stringstream ss;
163  ss << "//proc//" << pid_ << "//cmdline";
164  std::ifstream procfile{ss.str().c_str()};
165 
166  std::string procinfo;
167 
168  if (procfile.is_open()) {
169  procfile >> procinfo;
170  procfile.close();
171  }
172 
173  size_t end = procinfo.find('\0');
174  size_t start = procinfo.find_last_of('/', end);
175 
176  app_ = procinfo.substr(start + 1, end - start - 1);
177 }
178 
179 //======================================================================
180 // Message prefix filler ( overriddes ELdestination::fillPrefix )
181 //======================================================================
182 void ELOTS::fillPrefix(std::ostringstream& oss, const ErrorObj& msg) {
183  const auto& xid = msg.xid();
184 
185  auto id = xid.id();
186  auto module = xid.module();
187  auto app = app_;
188  char* cp = &format_string_[0];
189  char sev;
190  bool msg_printed = false;
191  std::string ossstr;
192  // ossstr.reserve(100);
193 
194  for (; *cp; ++cp) {
195  if (*cp != '%') {
196  oss << *cp;
197  continue;
198  }
199  if (*++cp == '\0') { // inc pas '%' and check if end
200  // ending '%' gets printed
201  oss << *cp;
202  break; // done
203  }
204  switch (*cp) {
205  case 'A':
206  oss << app;
207  break; // application
208  case 'a':
209  oss << hostaddr_;
210  break; // host address
211  case 'd':
212  oss << module;
213  break; // module name # Early
214  case 'f': // filename
215  if (filename_delimit_.size() == 0)
216  oss << msg.filename();
217  else if (filename_delimit_.size() == 1)
218  oss << (strrchr(&msg.filename()[0], filename_delimit_[0])
219  ? strrchr(&msg.filename()[0], filename_delimit_[0]) + 1
220  : msg.filename());
221  else
222  oss << (strstr(&msg.filename()[0], &filename_delimit_[0])
223  ? strstr(&msg.filename()[0], &filename_delimit_[0]) + filename_delimit_.size()
224  : msg.filename());
225  break;
226  case 'h':
227  oss << hostname_;
228  break; // host name
229  case 'L':
230  oss << xid.severity().getName();
231  break; // severity
232  case 'm': // message
233  // ossstr.clear(); // incase message is repeated
234  for (auto const& val : msg.items()) ossstr += val; // Print the contents.
235  if (ossstr.size()) { // allow/check for "no message"
236  if (ossstr.compare(0, 1, "\n") == 0) ossstr.erase(0, 1); // remove leading "\n" if present
237  if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
238  ossstr.erase(ossstr.size() - 1, 1); // remove trailing "\n" if present
239  oss << ossstr;
240  }
241  msg_printed = true;
242  break;
243  case 'N':
244  oss << id;
245  break; // category
246  case 'P':
247  oss << pid_;
248  break; // processID
249  case 'r':
250  oss << mf::GetIteration();
251  break; // run/iteration/event no #pre-events
252  case 's':
253  sev = xid.severity().getName()[0] | 0x20;
254  oss << sev;
255  break; // severity lower case
256  case 'T':
257  oss << format_.timestamp(msg.timestamp());
258  break; // timestamp
259  case 'u':
260  oss << std::to_string(msg.lineNumber());
261  break; // linenumber
262  case '%':
263  oss << '%';
264  break; // a '%' character
265  default:
266  oss << '%' << *cp;
267  break; // unknown - just print it w/ it's '%'
268  }
269  }
270  if (!msg_printed) {
271  for (auto const& val : msg.items()) ossstr += val; // Print the contents.
272  if (ossstr.compare(0, 1, "\n") == 0) ossstr.erase(0, 1); // remove leading "\n" if present
273  if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
274  ossstr.erase(ossstr.size() - 1, 1); // remove trailing "\n" if present
275  oss << ossstr;
276  }
277 }
278 
279 //======================================================================
280 // Message filler ( overriddes ELdestination::fillUsrMsg )
281 //======================================================================
282 void ELOTS::fillUsrMsg(std::ostringstream& oss __attribute__((__unused__)),
283  const ErrorObj& msg __attribute__((__unused__))) {
284  return; // UsrMsg filled above
285 }
286 
287 //======================================================================
288 // Message router ( overriddes ELdestination::routePayload )
289 //======================================================================
290 void ELOTS::routePayload(const std::ostringstream& oss, const ErrorObj&) { std::cout << oss.str() << std::endl; }
291 } // end namespace mfplugins
292 //======================================================================
293 //
294 // makePlugin function
295 //
296 //======================================================================
297 
298 #ifndef EXTERN_C_FUNC_DECLARE_START
299 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
300 #endif
301 
302 EXTERN_C_FUNC_DECLARE_START auto makePlugin(const std::string&, const fhicl::ParameterSet& pset) {
303  return std::make_unique<mfplugins::ELOTS>(pset);
304 }
305 } // namespace mfplugins
306 
307 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Configuration Parameters for ELOTS.
Definition: OTS_mfPlugin.cc:41
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:49
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:43
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:45
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:54
virtual void fillSuffix(std::ostringstream &, const ErrorObj &) override
Fill the &quot;Suffix&quot; portion of the message (Unused)
Definition: OTS_mfPlugin.cc:80
ELOTS(Parameters const &pset)
ELOTS Constructor