1 #include "cetlib/PluginTypeDeducer.h"
2 #include "fhiclcpp/ParameterSet.h"
4 #include "messagefacility/MessageService/ELdestination.h"
5 #include "messagefacility/Utilities/ELseverityLevel.h"
6 #if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
7 # include "messagefacility/MessageService/ELcontextSupplier.h"
8 # include "messagefacility/MessageLogger/MessageDrop.h"
9 #elif MESSAGEFACILITY_HEX_VERSION < 0x20201 // v2_02_01 is s67
10 # include "messagefacility/MessageService/MessageDrop.h"
12 # include "messagefacility/MessageLogger/MessageLogger.h"
14 #include "messagefacility/Utilities/exception.h"
15 #include "cetlib/compiler_macros.h"
22 #include <arpa/inet.h>
25 #include <netinet/in.h>
29 #include <boost/asio.hpp>
30 #include <boost/algorithm/string.hpp>
32 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
33 #define format_ format
38 using mf::service::ELdestination;
39 using mf::ELseverityLevel;
41 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
42 using mf::service::ELcontextSupplier;
44 using boost::asio::ip::udp;
50 class ELUDP :
public ELdestination
52 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
55 fhicl::TableFragment<ELdestination::Config> elDestConfig;
56 fhicl::Atom<int> error_max{ fhicl::Name{
"error_turnoff_threshold" },fhicl::Comment{
"Number of errors before turning off destination (default: 0, don't turn off)" },0 };
57 fhicl::Atom<int> error_report{ fhicl::Name{
"error_report_backoff_factor" },fhicl::Comment{
"Print an error message every N errors" },100 };
58 fhicl::Atom<std::string> host{ fhicl::Name{
"host" },fhicl::Comment{
"Address to send messages to" },
"227.128.12.27" };
59 fhicl::Atom<int> port{ fhicl::Name{
"port" },fhicl::Comment{
"Port to send messages to" },5140 };
61 using Parameters = fhicl::WrappedTable<Config>;
64 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
65 ELUDP(
const fhicl::ParameterSet& pset);
67 ELUDP(Parameters
const& pset);
70 virtual void fillPrefix(std::ostringstream&,
const ErrorObj&
71 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
72 ,
const ELcontextSupplier&
76 virtual void fillUsrMsg(std::ostringstream&,
const ErrorObj&)
override;
78 virtual void fillSuffix(std::ostringstream&,
const ErrorObj&)
override {}
80 virtual void routePayload(
const std::ostringstream&,
const ErrorObj&
81 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
82 ,
const ELcontextSupplier&
87 void reconnect_(
bool quiet =
false);
90 int error_report_backoff_factor_;
96 boost::asio::io_service io_service_;
98 udp::endpoint remote_endpoint_;
99 int consecutive_success_count_;
101 int next_error_report_;
106 std::string hostname_;
107 std::string hostaddr_;
120 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
121 ELUDP::ELUDP(
const fhicl::ParameterSet& pset)
122 : ELdestination(pset)
123 , error_report_backoff_factor_(pset.get<int>(
"error_report_backoff_factor", 100))
124 , error_max_(pset.get<int>(
"error_turnoff_threshold", 0))
125 , host_(pset.get<std::string>(
"host",
"227.128.12.27"))
126 , port_(pset.get<int>(
"port", 5140))
129 : ELdestination(pset().elDestConfig())
130 , error_report_backoff_factor_(pset().error_report())
131 , error_max_(pset().error_max())
132 , host_(pset().host())
133 , port_(pset().port())
136 , socket_(io_service_)
138 , consecutive_success_count_(0)
140 , next_error_report_(1)
142 , pid_(static_cast<long>(getpid()))
147 char hostname_c[1024];
148 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c :
"Unkonwn Host";
151 hostent* host =
nullptr;
152 host = gethostbyname(hostname_c);
157 char* ip = inet_ntoa(*(
struct in_addr *)host->h_addr);
163 struct ifaddrs* ifAddrStruct =
nullptr;
164 struct ifaddrs* ifa =
nullptr;
165 void* tmpAddrPtr =
nullptr;
167 if (getifaddrs(&ifAddrStruct))
170 hostaddr_ =
"127.0.0.1";
175 for (ifa = ifAddrStruct; ifa !=
nullptr; ifa = ifa->ifa_next)
177 if (ifa->ifa_addr->sa_family == AF_INET)
180 tmpAddrPtr = &((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
181 char addressBuffer[INET_ADDRSTRLEN];
182 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
183 hostaddr_ = addressBuffer;
186 else if (ifa->ifa_addr->sa_family == AF_INET6)
189 tmpAddrPtr = &((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
190 char addressBuffer[INET6_ADDRSTRLEN];
191 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
192 hostaddr_ = addressBuffer;
196 if (!hostaddr_.empty()
197 && hostaddr_.compare(
"127.0.0.1")
198 && hostaddr_.compare(
"::1"))
202 if (hostaddr_.empty())
203 hostaddr_ =
"127.0.0.1";
210 std::ostringstream pid_ostr;
211 pid_ostr <<
"/proc/" << pid_ <<
"/exe";
212 exe = realpath(pid_ostr.str().c_str(), NULL);
214 size_t end = exe.find(
'\0');
215 size_t start = exe.find_last_of(
'/', end);
217 app_ = exe.substr(start + 1, end - start - 1);
220 std::stringstream ss;
221 ss <<
"//proc//" << pid_ <<
"//cmdline";
222 std::ifstream procfile{ ss.str().c_str() };
224 std::string procinfo;
226 if (procfile.is_open())
228 procfile >> procinfo;
232 size_t end = procinfo.find(
'\0');
233 size_t start = procinfo.find_last_of(
'/', end);
235 app_ = procinfo.substr(start + 1, end - start - 1);
239 void ELUDP::reconnect_(
bool quiet)
241 boost::system::error_code ec;
242 socket_.open(udp::v4());
243 socket_.set_option(boost::asio::socket_base::reuse_address(
true), ec);
246 std::cerr <<
"An error occurred setting reuse_address to true: "
247 << ec.message() << std::endl;
250 if (boost::iequals(host_,
"Broadcast") || host_ ==
"255.255.255.255")
252 socket_.set_option(boost::asio::socket_base::broadcast(
true), ec);
253 remote_endpoint_ = udp::endpoint(boost::asio::ip::address_v4::broadcast(), port_);
257 udp::resolver resolver(io_service_);
258 udp::resolver::query query(udp::v4(), host_, std::to_string(port_));
259 remote_endpoint_ = *resolver.resolve(query);
262 socket_.connect(remote_endpoint_, ec);
267 std::cerr <<
"An Error occurred in connect(): " << ec.message() << std::endl
268 <<
" endpoint = " << remote_endpoint_ << std::endl;
281 void ELUDP::fillPrefix(std::ostringstream& oss,
const ErrorObj& msg
282 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
283 , ELcontextSupplier
const&
287 const auto& xid = msg.xid();
289 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
291 auto module = xid.module();
295 auto app = xid.application;
296 auto process = xid.process;
297 auto module = xid.module;
299 std::replace(
id.begin(),
id.end(),
'|',
'!');
300 std::replace(app.begin(), app.end(),
'|',
'!');
301 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
302 std::replace(process.begin(), process.end(),
'|',
'!');
304 std::replace(module.begin(), module.end(),
'|',
'!');
306 oss << format_.timestamp(msg.timestamp()) <<
"|";
307 oss << std::to_string(++seqNum_) <<
"|";
308 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
309 oss << hostname_ <<
"|";
310 oss << hostaddr_ <<
"|";
311 oss << xid.severity().getName() <<
"|";
313 oss << xid.hostname <<
"|";
314 oss << xid.hostaddr <<
"|";
315 oss << xid.severity.getName() <<
"|";
319 # if MESSAGEFACILITY_HEX_VERSION >= 0x20201 // an indication of s67
321 oss << mf::GetIteration() <<
"|";
322 # elif MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
324 oss << mf::MessageDrop::instance()->iteration <<
"|";
326 oss << process <<
"|";
327 oss << xid.pid <<
"|";
328 oss << mf::MessageDrop::instance()->runEvent <<
"|";
330 oss << module <<
"|";
331 #if MESSAGEFACILITY_HEX_VERSION >= 0x20201
332 oss << msg.filename() <<
"|" << std::to_string(msg.lineNumber()) <<
"|";
339 void ELUDP::fillUsrMsg(std::ostringstream& oss,
const ErrorObj& msg)
341 std::ostringstream tmposs;
343 for (
auto const& val : msg.items()) {
348 const std::string& usrMsg = !tmposs.str().compare(0, 1,
"\n") ? tmposs.str().erase(0, 1) : tmposs.str();
356 void ELUDP::routePayload(
const std::ostringstream& oss
357 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
358 ,
const ErrorObj& msg, ELcontextSupplier
const&
364 if (error_count_ < error_max_ || error_max_ == 0)
366 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
369 auto pid = msg.xid().pid;
372 auto string =
"UDPMFMESSAGE" + std::to_string(pid) +
"|" + oss.str();
374 auto message = boost::asio::buffer(
string);
378 socket_.send_to(message, remote_endpoint_);
379 ++consecutive_success_count_;
380 if (consecutive_success_count_ >= 5)
383 next_error_report_ = 1;
387 catch (boost::system::system_error& err)
389 consecutive_success_count_ = 0;
391 if (error_count_ == next_error_report_)
393 std::cerr <<
"An exception occurred when trying to send message " << std::to_string(seqNum_) <<
" to "
394 << remote_endpoint_ << std::endl
395 <<
" message = " << oss.str() << std::endl
396 <<
" exception = " << err.what() << std::endl;
397 next_error_report_ *= error_report_backoff_factor_;
418 #ifndef EXTERN_C_FUNC_DECLARE_START
419 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
422 EXTERN_C_FUNC_DECLARE_START
423 auto makePlugin(
const std::string&,
424 const fhicl::ParameterSet& pset)
426 return std::make_unique<mfplugins::ELUDP>(pset);
430 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Message Facility UDP Streamer Destination Formats messages into a delimited string and sends via UDP ...