LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-mfextensions/mfextensions/Destinations - OTS_mfPlugin.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 135 0
Test Date: 2025-09-04 00:45:34 Functions: 0.0 % 7 0

            Line data    Source code
       1              : #include "cetlib/PluginTypeDeducer.h"
       2              : #include "fhiclcpp/ParameterSet.h"
       3              : #include "fhiclcpp/types/ConfigurationTable.h"
       4              : 
       5              : #include "cetlib/compiler_macros.h"
       6              : #include "messagefacility/MessageLogger/MessageLogger.h"
       7              : #include "messagefacility/MessageService/ELdestination.h"
       8              : #include "messagefacility/Utilities/ELseverityLevel.h"
       9              : #include "messagefacility/Utilities/exception.h"
      10              : 
      11              : // C/C++ includes
      12              : #include <arpa/inet.h>
      13              : #include <ifaddrs.h>
      14              : #include <netdb.h>
      15              : #include <netinet/in.h>
      16              : #include <algorithm>
      17              : #include <fstream>
      18              : #include <iostream>
      19              : #include <memory>
      20              : #include "mfextensions/Receivers/detail/TCPConnect.hh"
      21              : 
      22              : #define TRACE_NAME "OTS_mfPlugin"
      23              : #include "trace.h"
      24              : 
      25              : // Boost includes
      26              : #include <boost/algorithm/string.hpp>
      27              : 
      28              : namespace mfplugins {
      29              : using mf::ErrorObj;
      30              : using mf::service::ELdestination;
      31              : 
      32              : /// <summary>
      33              : /// Message Facility OTS Console Destination
      34              : /// Formats messages into Ryan's favorite format for OTS
      35              : /// </summary>
      36              : class ELOTS : public ELdestination
      37              : {
      38              : public:
      39              :         /**
      40              :          * \brief Configuration Parameters for ELOTS
      41              :          */
      42              :         struct Config
      43              :         {
      44              :                 /// ELDestination common config parameters
      45              :                 fhicl::TableFragment<ELdestination::Config> elDestConfig;
      46              :                 /// format_string (Default: "%L:%N:%f [%u] %m"): Format specifier for printing to console. %% => '%' ...
      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"};
      50              :                 /// filename_delimit (Default: "/"): Grab path after this. "/srcs/" /x/srcs/y/z.cc => y/z.cc
      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              :         };
      55              :         /// Used for ParameterSet validation
      56              :         using Parameters = fhicl::WrappedTable<Config>;
      57              : 
      58              : public:
      59              :         /// <summary>
      60              :         /// ELOTS Constructor
      61              :         /// </summary>
      62              :         /// <param name="pset">ParameterSet used to configure ELOTS</param>
      63              :         ELOTS(Parameters const& pset);
      64              : 
      65              :         /**
      66              :          * \brief Fill the "Prefix" portion of the message
      67              :          * \param o Output stringstream
      68              :          * \param msg MessageFacility object containing header information
      69              :          */
      70              :         void fillPrefix(std::ostringstream& o, const ErrorObj& msg) override;
      71              : 
      72              :         /**
      73              :          * \brief Fill the "User Message" portion of the message
      74              :          * \param o Output stringstream
      75              :          * \param msg MessageFacility object containing header information
      76              :          */
      77              :         void fillUsrMsg(std::ostringstream& o, const ErrorObj& msg) override;
      78              : 
      79              :         /**
      80              :          * \brief Fill the "Suffix" portion of the message (Unused)
      81              :          */
      82            0 :         void fillSuffix(std::ostringstream& /*unused*/, const ErrorObj& /*msg*/) override {}
      83              : 
      84              :         /**
      85              :          * \brief Serialize a MessageFacility message to the output
      86              :          * \param o Stringstream object containing message data
      87              :          * \param e MessageFacility object containing header information
      88              :          */
      89              :         void routePayload(const std::ostringstream& o, const ErrorObj& e) override;
      90              : 
      91              : private:
      92              :         // Other stuff
      93              :         int64_t 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              : 
     109            0 : ELOTS::ELOTS(Parameters const& pset)
     110            0 :     : ELdestination(pset().elDestConfig()), pid_(static_cast<int64_t>(getpid())), format_string_(pset().format_string()), filename_delimit_(pset().filename_delimit())
     111              : {
     112              :         // hostname
     113              :         char hostname_c[1024];
     114            0 :         hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c : "Unkonwn Host";
     115              : 
     116              :         // host ip address
     117            0 :         hostent* host = nullptr;
     118            0 :         host = gethostbyname(hostname_c);
     119              : 
     120            0 :         if (host != nullptr)
     121              :         {
     122              :                 // ip address from hostname if the entry exists in /etc/hosts
     123            0 :                 char* ip = inet_ntoa(*reinterpret_cast<struct in_addr*>(host->h_addr));  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic)
     124            0 :                 hostaddr_ = ip;
     125              :         }
     126              :         else
     127              :         {
     128              :                 // enumerate all network interfaces
     129            0 :                 struct ifaddrs* ifAddrStruct = nullptr;
     130            0 :                 struct ifaddrs* ifa = nullptr;
     131            0 :                 void* tmpAddrPtr = nullptr;
     132              : 
     133            0 :                 if (getifaddrs(&ifAddrStruct) != 0)
     134              :                 {
     135              :                         // failed to get addr struct
     136            0 :                         hostaddr_ = "127.0.0.1";
     137              :                 }
     138              :                 else
     139              :                 {
     140              :                         // iterate through all interfaces
     141            0 :                         for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
     142              :                         {
     143            0 :                                 if (ifa->ifa_addr->sa_family == AF_INET)
     144              :                                 {
     145              :                                         // a valid IPv4 addres
     146            0 :                                         tmpAddrPtr = &(reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr))->sin_addr;  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
     147              :                                         char addressBuffer[INET_ADDRSTRLEN];
     148            0 :                                         inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
     149            0 :                                         hostaddr_ = addressBuffer;
     150              :                                 }
     151              : 
     152            0 :                                 else if (ifa->ifa_addr->sa_family == AF_INET6)
     153              :                                 {
     154              :                                         // a valid IPv6 address
     155            0 :                                         tmpAddrPtr = &(reinterpret_cast<struct sockaddr_in6*>(ifa->ifa_addr))->sin6_addr;  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
     156              :                                         char addressBuffer[INET6_ADDRSTRLEN];
     157            0 :                                         inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
     158            0 :                                         hostaddr_ = addressBuffer;
     159              :                                 }
     160              : 
     161              :                                 // find first non-local address
     162            0 :                                 if (!hostaddr_.empty() && (hostaddr_ != "127.0.0.1") && (hostaddr_ != "::1"))
     163              :                                 {
     164            0 :                                         break;
     165              :                                 }
     166              :                         }
     167              : 
     168            0 :                         if (hostaddr_.empty())
     169              :                         {  // failed to find anything
     170            0 :                                 hostaddr_ = "127.0.0.1";
     171              :                         }
     172              :                 }
     173              :         }
     174              : 
     175              :         // get process name from '/proc/pid/cmdline'
     176            0 :         std::stringstream ss;
     177            0 :         ss << "//proc//" << pid_ << "//cmdline";
     178            0 :         std::ifstream procfile{ss.str().c_str()};
     179              : 
     180            0 :         std::string procinfo;
     181              : 
     182            0 :         if (procfile.is_open())
     183              :         {
     184            0 :                 procfile >> procinfo;
     185            0 :                 procfile.close();
     186              :         }
     187              : 
     188            0 :         size_t end = procinfo.find('\0');
     189            0 :         size_t start = procinfo.find_last_of('/', end);
     190              : 
     191            0 :         app_ = procinfo.substr(start + 1, end - start - 1);
     192            0 : }
     193              : 
     194              : //======================================================================
     195              : // Message prefix filler ( overriddes ELdestination::fillPrefix )
     196              : //======================================================================
     197            0 : void ELOTS::fillPrefix(std::ostringstream& oss, const ErrorObj& msg)
     198              : {
     199            0 :         const auto& xid = msg.xid();
     200              : 
     201            0 :         const auto& id = xid.id();
     202            0 :         const auto& module = xid.module();
     203            0 :         auto app = app_;
     204            0 :         char* cp = &format_string_[0];  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     205              :         char sev;
     206            0 :         bool msg_printed = false;
     207            0 :         std::string ossstr;
     208              :         // ossstr.reserve(100);
     209              : 
     210            0 :         for (; *cp != 0; ++cp)  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     211              :         {
     212            0 :                 if (*cp != '%')
     213              :                 {
     214            0 :                         oss << *cp;
     215            0 :                         continue;
     216              :                 }
     217            0 :                 if (*++cp == '\0')  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     218              :                 {                   // inc pas '%' and check if end
     219              :                         // ending '%' gets printed
     220            0 :                         oss << *cp;
     221            0 :                         break;  // done
     222              :                 }
     223            0 :                 switch (*cp)
     224              :                 {
     225            0 :                         case 'A':
     226            0 :                                 oss << app;
     227            0 :                                 break;  // application
     228            0 :                         case 'a':
     229            0 :                                 oss << hostaddr_;
     230            0 :                                 break;  // host address
     231            0 :                         case 'd':
     232            0 :                                 oss << module;
     233            0 :                                 break;  // module name # Early
     234            0 :                         case 'f':   // filename
     235            0 :                                 if (filename_delimit_.empty())
     236              :                                 {
     237            0 :                                         oss << msg.filename();
     238              :                                 }
     239            0 :                                 else if (filename_delimit_.size() == 1)
     240              :                                 {
     241            0 :                                         oss << (strrchr(&msg.filename()[0], filename_delimit_[0]) != nullptr  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     242            0 :                                                     ? strrchr(&msg.filename()[0], filename_delimit_[0]) + 1   // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     243            0 :                                                     : msg.filename());
     244              :                                 }
     245              :                                 else
     246              :                                 {
     247            0 :                                         const char* cp = strstr(&msg.filename()[0], &filename_delimit_[0]);  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     248            0 :                                         if (cp != nullptr)
     249              :                                         {
     250              :                                                 // make sure to remove a part that ends with '/'
     251            0 :                                                 cp += filename_delimit_.size() - 1;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     252            0 :                                                 while (*cp && *cp != '/') ++cp;
     253            0 :                                                 ++cp;  // increment past '/'
     254            0 :                                                 oss << cp;
     255              :                                         }
     256              :                                         else
     257            0 :                                                 oss << msg.filename();
     258              :                                 }
     259            0 :                                 break;
     260            0 :                         case 'h':
     261            0 :                                 oss << hostname_;
     262            0 :                                 break;  // host name
     263            0 :                         case 'L':
     264            0 :                                 oss << xid.severity().getName();
     265            0 :                                 break;  // severity
     266            0 :                         case 'm':   // message
     267              :                                 // ossstr.clear();                                               // incase message is repeated
     268            0 :                                 for (auto const& val : msg.items())
     269              :                                 {
     270            0 :                                         ossstr += val;  // Print the contents.
     271              :                                 }
     272            0 :                                 if (!ossstr.empty())
     273              :                                 {  // allow/check for "no message"
     274            0 :                                         if (ossstr.compare(0, 1, "\n") == 0)
     275              :                                         {
     276            0 :                                                 ossstr.erase(0, 1);  // remove leading "\n" if present
     277              :                                         }
     278            0 :                                         if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
     279              :                                         {
     280            0 :                                                 ossstr.erase(ossstr.size() - 1, 1);  // remove trailing "\n" if present
     281              :                                         }
     282            0 :                                         oss << ossstr;
     283              :                                 }
     284            0 :                                 msg_printed = true;
     285            0 :                                 break;
     286            0 :                         case 'N':
     287            0 :                                 oss << id;
     288            0 :                                 break;  // category
     289            0 :                         case 'P':
     290            0 :                                 oss << pid_;
     291            0 :                                 break;  // processID
     292            0 :                         case 'r':
     293            0 :                                 oss << mf::GetIteration();
     294            0 :                                 break;  // run/iteration/event no #pre-events
     295            0 :                         case 's':
     296            0 :                                 sev = xid.severity().getName()[0] | 0x20;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
     297            0 :                                 oss << sev;
     298            0 :                                 break;  // severity lower case
     299            0 :                         case 'T':
     300            0 :                                 oss << format_.timestamp(msg.timestamp());
     301            0 :                                 break;  // timestamp
     302            0 :                         case 'u':
     303            0 :                                 oss << std::to_string(msg.lineNumber());
     304            0 :                                 break;  // linenumber
     305            0 :                         case '%':
     306            0 :                                 oss << '%';
     307            0 :                                 break;  // a '%' character
     308            0 :                         default:
     309            0 :                                 oss << '%' << *cp;
     310            0 :                                 break;  // unknown - just print it w/ it's '%'
     311              :                 }
     312              :         }
     313            0 :         if (!msg_printed)
     314              :         {
     315            0 :                 for (auto const& val : msg.items())
     316              :                 {
     317            0 :                         ossstr += val;  // Print the contents.
     318              :                 }
     319            0 :                 if (ossstr.compare(0, 1, "\n") == 0)
     320              :                 {
     321            0 :                         ossstr.erase(0, 1);  // remove leading "\n" if present
     322              :                 }
     323            0 :                 if (ossstr.compare(ossstr.size() - 1, 1, "\n") == 0)
     324              :                 {
     325            0 :                         ossstr.erase(ossstr.size() - 1, 1);  // remove trailing "\n" if present
     326              :                 }
     327            0 :                 oss << ossstr;
     328              :         }
     329            0 : }
     330              : 
     331              : //======================================================================
     332              : // Message filler ( overriddes ELdestination::fillUsrMsg )
     333              : //======================================================================
     334            0 : void ELOTS::fillUsrMsg(std::ostringstream& oss __attribute__((__unused__)),
     335              :                        const ErrorObj& msg __attribute__((__unused__)))
     336              : {
     337              :         // UsrMsg filled above
     338            0 : }
     339              : 
     340              : //======================================================================
     341              : // Message router ( overriddes ELdestination::routePayload )
     342              : //======================================================================
     343            0 : void ELOTS::routePayload(const std::ostringstream& oss, const ErrorObj& /*msg*/) { std::cout << oss.str() << std::endl; }
     344              : }  // end namespace mfplugins
     345              : //======================================================================
     346              : //
     347              : // makePlugin function
     348              : //
     349              : //======================================================================
     350              : 
     351              : #ifndef EXTERN_C_FUNC_DECLARE_START
     352              : #define EXTERN_C_FUNC_DECLARE_START extern "C" {
     353              : #endif
     354              : 
     355            0 : EXTERN_C_FUNC_DECLARE_START auto makePlugin(const std::string& /*unused*/, const fhicl::ParameterSet& pset)
     356              : {
     357            0 :         return std::make_unique<mfplugins::ELOTS>(pset);
     358              : }
     359              : }  // namespace mfplugins
     360              : 
     361            0 : DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
        

Generated by: LCOV version 2.0-1