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"
10 # include "messagefacility/MessageService/MessageDrop.h"
12 #include "messagefacility/Utilities/exception.h"
19 #include <arpa/inet.h>
22 #include <netinet/in.h>
26 #include <boost/asio.hpp>
27 #include <boost/algorithm/string.hpp>
31 using mf::service::ELdestination;
32 using mf::ELseverityLevel;
34 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
35 using mf::service::ELcontextSupplier;
37 using boost::asio::ip::udp;
43 class ELUDP :
public ELdestination
45 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
48 fhicl::TableFragment<ELdestination::Config> elDestConfig;
49 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 };
50 fhicl::Atom<int> error_report{ fhicl::Name{
"error_report_backoff_factor" },fhicl::Comment{
"Print an error message every N errors" },100 };
51 fhicl::Atom<std::string> host{ fhicl::Name{
"host" },fhicl::Comment{
"Address to send messages to" },
"227.128.12.27" };
52 fhicl::Atom<int> port{ fhicl::Name{
"port" },fhicl::Comment{
"Port to send messages to" },5140 };
54 using Parameters = fhicl::WrappedTable<Config>;
57 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
58 ELUDP(
const fhicl::ParameterSet& pset);
60 ELUDP(Parameters
const& pset);
63 virtual void fillPrefix(std::ostringstream&,
const ErrorObj&
64 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
65 ,
const ELcontextSupplier&
69 virtual void fillUsrMsg(std::ostringstream&,
const ErrorObj&)
override;
71 virtual void fillSuffix(std::ostringstream&,
const ErrorObj&)
override {}
73 virtual void routePayload(
const std::ostringstream&,
const ErrorObj&
74 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
75 ,
const ELcontextSupplier&
80 void reconnect_(
bool quiet =
false);
83 int error_report_backoff_factor_;
89 boost::asio::io_service io_service_;
91 udp::endpoint remote_endpoint_;
92 int consecutive_success_count_;
94 int next_error_report_;
99 std::string hostname_;
100 std::string hostaddr_;
113 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
114 ELUDP::ELUDP(
const fhicl::ParameterSet& pset)
115 : ELdestination(pset)
116 , error_report_backoff_factor_(pset.get<int>(
"error_report_backoff_factor", 100))
117 , error_max_(pset.get<int>(
"error_turnoff_threshold", 0))
118 , host_(pset.get<std::string>(
"host",
"227.128.12.27"))
119 , port_(pset.get<int>(
"port", 5140))
122 : ELdestination(pset().elDestConfig())
123 , error_report_backoff_factor_(pset().error_report())
124 , error_max_(pset().error_max())
125 , host_(pset().host())
126 , port_(pset().port())
129 , socket_(io_service_)
131 , consecutive_success_count_(0)
133 , next_error_report_(1)
135 , pid_(static_cast<long>(getpid()))
140 char hostname_c[1024];
141 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c :
"Unkonwn Host";
144 hostent* host =
nullptr;
145 host = gethostbyname(hostname_c);
150 char* ip = inet_ntoa(*(
struct in_addr *)host->h_addr);
156 struct ifaddrs* ifAddrStruct =
nullptr;
157 struct ifaddrs* ifa =
nullptr;
158 void* tmpAddrPtr =
nullptr;
160 if (getifaddrs(&ifAddrStruct))
163 hostaddr_ =
"127.0.0.1";
168 for (ifa = ifAddrStruct; ifa !=
nullptr; ifa = ifa->ifa_next)
170 if (ifa->ifa_addr->sa_family == AF_INET)
173 tmpAddrPtr = &((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
174 char addressBuffer[INET_ADDRSTRLEN];
175 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
176 hostaddr_ = addressBuffer;
179 else if (ifa->ifa_addr->sa_family == AF_INET6)
182 tmpAddrPtr = &((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
183 char addressBuffer[INET6_ADDRSTRLEN];
184 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
185 hostaddr_ = addressBuffer;
189 if (!hostaddr_.empty()
190 && hostaddr_.compare(
"127.0.0.1")
191 && hostaddr_.compare(
"::1"))
195 if (hostaddr_.empty())
196 hostaddr_ =
"127.0.0.1";
203 std::ostringstream pid_ostr;
204 pid_ostr <<
"/proc/" << pid_ <<
"/exe";
205 exe = realpath(pid_ostr.str().c_str(), NULL);
207 size_t end = exe.find(
'\0');
208 size_t start = exe.find_last_of(
'/', end);
210 app_ = exe.substr(start + 1, end - start - 1);
213 std::stringstream ss;
214 ss <<
"//proc//" << pid_ <<
"//cmdline";
215 std::ifstream procfile{ ss.str().c_str() };
217 std::string procinfo;
219 if (procfile.is_open())
221 procfile >> procinfo;
225 size_t end = procinfo.find(
'\0');
226 size_t start = procinfo.find_last_of(
'/', end);
228 app_ = procinfo.substr(start + 1, end - start - 1);
232 void ELUDP::reconnect_(
bool quiet)
234 boost::system::error_code ec;
235 socket_.open(udp::v4());
236 socket_.set_option(boost::asio::socket_base::reuse_address(
true), ec);
239 std::cerr <<
"An error occurred setting reuse_address to true: "
240 << ec.message() << std::endl;
243 if (boost::iequals(host_,
"Broadcast") || host_ ==
"255.255.255.255")
245 socket_.set_option(boost::asio::socket_base::broadcast(
true), ec);
246 remote_endpoint_ = udp::endpoint(boost::asio::ip::address_v4::broadcast(), port_);
250 udp::resolver resolver(io_service_);
251 udp::resolver::query query(udp::v4(), host_, std::to_string(port_));
252 remote_endpoint_ = *resolver.resolve(query);
255 socket_.connect(remote_endpoint_, ec);
260 std::cerr <<
"An Error occurred in connect(): " << ec.message() << std::endl
261 <<
" endpoint = " << remote_endpoint_ << std::endl;
274 void ELUDP::fillPrefix(std::ostringstream& oss,
const ErrorObj& msg
275 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
276 , ELcontextSupplier
const&
280 const auto& xid = msg.xid();
282 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
284 auto module = xid.module();
288 auto app = xid.application;
289 auto process = xid.process;
290 auto module = xid.module;
292 std::replace(
id.begin(),
id.end(),
'|',
'!');
293 std::replace(app.begin(), app.end(),
'|',
'!');
294 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
295 std::replace(process.begin(), process.end(),
'|',
'!');
297 std::replace(module.begin(), module.end(),
'|',
'!');
299 oss << format.timestamp(msg.timestamp()) <<
"|";
300 oss << std::to_string(++seqNum_) <<
"|";
301 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
302 oss << hostname_ <<
"|";
303 oss << hostaddr_ <<
"|";
304 oss << xid.severity().getName() <<
"|";
306 oss << xid.hostname <<
"|";
307 oss << xid.hostaddr <<
"|";
308 oss << xid.severity.getName() <<
"|";
312 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
314 oss << mf::MessageDrop::instance()->iteration <<
"|";
316 oss << process <<
"|";
317 oss << xid.pid <<
"|";
318 oss << mf::MessageDrop::instance()->runEvent <<
"|";
320 oss << module <<
"|";
326 void ELUDP::fillUsrMsg(std::ostringstream& oss,
const ErrorObj& msg)
328 std::ostringstream tmposs;
329 ELdestination::fillUsrMsg(tmposs, msg);
332 const std::string& usrMsg = !tmposs.str().compare(0, 1,
"\n") ? tmposs.str().erase(0, 1) : tmposs.str();
340 void ELUDP::routePayload(
const std::ostringstream& oss
341 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
342 ,
const ErrorObj& msg, ELcontextSupplier
const&
348 if (error_count_ < error_max_ || error_max_ == 0)
350 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
353 auto pid = msg.xid().pid;
356 auto string =
"UDPMFMESSAGE" + std::to_string(pid) +
"|" + oss.str();
358 auto message = boost::asio::buffer(
string);
362 socket_.send_to(message, remote_endpoint_);
363 ++consecutive_success_count_;
364 if (consecutive_success_count_ >= 5)
367 next_error_report_ = 1;
371 catch (boost::system::system_error& err)
373 consecutive_success_count_ = 0;
375 if (error_count_ == next_error_report_)
377 std::cerr <<
"An exception occurred when trying to send message " << std::to_string(seqNum_) <<
" to "
378 << remote_endpoint_ << std::endl
379 <<
" message = " << oss.str() << std::endl
380 <<
" exception = " << err.what() << std::endl;
381 next_error_report_ *= error_report_backoff_factor_;
404 auto makePlugin(
const std::string&,
405 const fhicl::ParameterSet& pset)
407 return std::make_unique<mfplugins::ELUDP>(pset);
411 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Message Facility UDP Streamer Destination Formats messages into a delimited string and sends via UDP ...