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
47 ELUDP(
const fhicl::ParameterSet& pset);
49 virtual void fillPrefix(std::ostringstream&,
const ErrorObj&
50 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
51 ,
const ELcontextSupplier&
55 virtual void fillUsrMsg(std::ostringstream&,
const ErrorObj&)
override;
57 virtual void fillSuffix(std::ostringstream&,
const ErrorObj&)
override {}
59 virtual void routePayload(
const std::ostringstream&,
const ErrorObj&
60 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
61 ,
const ELcontextSupplier&
66 void reconnect_(
bool quiet =
false);
68 boost::asio::io_service io_service_;
70 udp::endpoint remote_endpoint_;
71 int consecutive_success_count_;
73 int next_error_report_;
74 int error_report_backoff_factor_;
82 std::string hostname_;
83 std::string hostaddr_;
96 ELUDP::ELUDP(
const fhicl::ParameterSet& pset)
99 , socket_(io_service_)
101 , consecutive_success_count_(0)
103 , next_error_report_(1)
104 , error_report_backoff_factor_(pset.get<int>(
"error_report_backoff_factor", 10))
105 , error_max_(pset.get<int>(
"error_turnoff_threshold", 1))
106 , host_(pset.get<std::string>(
"host",
"227.128.12.27"))
107 , port_(pset.get<int>(
"port", 5140))
109 , pid_(static_cast<long>(getpid()))
114 char hostname_c[1024];
115 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c :
"Unkonwn Host";
118 hostent* host =
nullptr;
119 host = gethostbyname(hostname_c);
124 char* ip = inet_ntoa(*(
struct in_addr *)host->h_addr);
130 struct ifaddrs* ifAddrStruct =
nullptr;
131 struct ifaddrs* ifa =
nullptr;
132 void* tmpAddrPtr =
nullptr;
134 if (getifaddrs(&ifAddrStruct))
137 hostaddr_ =
"127.0.0.1";
142 for (ifa = ifAddrStruct; ifa !=
nullptr; ifa = ifa->ifa_next)
144 if (ifa->ifa_addr->sa_family == AF_INET)
147 tmpAddrPtr = &((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
148 char addressBuffer[INET_ADDRSTRLEN];
149 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
150 hostaddr_ = addressBuffer;
153 else if (ifa->ifa_addr->sa_family == AF_INET6)
156 tmpAddrPtr = &((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
157 char addressBuffer[INET6_ADDRSTRLEN];
158 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
159 hostaddr_ = addressBuffer;
163 if (!hostaddr_.empty()
164 && hostaddr_.compare(
"127.0.0.1")
165 && hostaddr_.compare(
"::1"))
169 if (hostaddr_.empty())
170 hostaddr_ =
"127.0.0.1";
177 std::ostringstream pid_ostr;
178 pid_ostr <<
"/proc/" << pid_ <<
"/exe";
179 exe = realpath(pid_ostr.str().c_str(), NULL);
181 size_t end = exe.find(
'\0');
182 size_t start = exe.find_last_of(
'/', end);
184 app_ = exe.substr(start + 1, end - start - 1);
187 std::stringstream ss;
188 ss <<
"//proc//" << pid_ <<
"//cmdline";
189 std::ifstream procfile{ ss.str().c_str() };
191 std::string procinfo;
193 if (procfile.is_open())
195 procfile >> procinfo;
199 size_t end = procinfo.find(
'\0');
200 size_t start = procinfo.find_last_of(
'/', end);
202 app_ = procinfo.substr(start + 1, end - start - 1);
206 void ELUDP::reconnect_(
bool quiet)
208 boost::system::error_code ec;
209 socket_.open(udp::v4());
210 socket_.set_option(boost::asio::socket_base::reuse_address(
true), ec);
213 std::cerr <<
"An error occurred setting reuse_address to true: "
214 << ec.message() << std::endl;
217 if (boost::iequals(host_,
"Broadcast") || host_ ==
"255.255.255.255")
219 socket_.set_option(boost::asio::socket_base::broadcast(
true), ec);
220 remote_endpoint_ = udp::endpoint(boost::asio::ip::address_v4::broadcast(), port_);
224 udp::resolver resolver(io_service_);
225 udp::resolver::query query(udp::v4(), host_, std::to_string(port_));
226 remote_endpoint_ = *resolver.resolve(query);
229 socket_.connect(remote_endpoint_, ec);
234 std::cerr <<
"An Error occurred in connect(): " << ec.message() << std::endl
235 <<
" endpoint = " << remote_endpoint_ << std::endl;
248 void ELUDP::fillPrefix(std::ostringstream& oss,
const ErrorObj& msg
249 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
250 , ELcontextSupplier
const&
254 const auto& xid = msg.xid();
256 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
258 auto module = xid.module();
262 auto app = xid.application;
263 auto process = xid.process;
264 auto module = xid.module;
266 std::replace(
id.begin(),
id.end(),
'|',
'!');
267 std::replace(app.begin(), app.end(),
'|',
'!');
268 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
269 std::replace(process.begin(), process.end(),
'|',
'!');
271 std::replace(module.begin(), module.end(),
'|',
'!');
273 oss << format.timestamp(msg.timestamp()) <<
"|";
274 oss << std::to_string(++seqNum_) <<
"|";
275 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
276 oss << hostname_ <<
"|";
277 oss << hostaddr_ <<
"|";
278 oss << xid.severity().getName() <<
"|";
280 oss << xid.hostname <<
"|";
281 oss << xid.hostaddr <<
"|";
282 oss << xid.severity.getName() <<
"|";
286 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
288 oss << mf::MessageDrop::instance()->iteration <<
"|";
290 oss << process <<
"|";
291 oss << xid.pid <<
"|";
292 oss << mf::MessageDrop::instance()->runEvent <<
"|";
294 oss << module <<
"|";
300 void ELUDP::fillUsrMsg(std::ostringstream& oss,
const ErrorObj& msg)
302 std::ostringstream tmposs;
303 ELdestination::fillUsrMsg(tmposs, msg);
306 const std::string& usrMsg = !tmposs.str().compare(0, 1,
"\n") ? tmposs.str().erase(0, 1) : tmposs.str();
314 void ELUDP::routePayload(
const std::ostringstream& oss
315 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
316 ,
const ErrorObj& msg, ELcontextSupplier
const&
322 if (error_count_ < error_max_)
324 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
327 auto pid = msg.xid().pid;
330 auto string =
"UDPMFMESSAGE" + std::to_string(pid) +
"|" + oss.str();
332 auto message = boost::asio::buffer(
string);
336 socket_.send_to(message, remote_endpoint_);
337 ++consecutive_success_count_;
338 if (consecutive_success_count_ >= 5)
341 next_error_report_ = 1;
345 catch (boost::system::system_error& err)
347 consecutive_success_count_ = 0;
349 if (error_count_ == next_error_report_)
351 std::cerr <<
"An exception occurred when trying to send message " << std::to_string(seqNum_) <<
" to "
352 << remote_endpoint_ << std::endl
353 <<
" message = " << oss.str() << std::endl
354 <<
" exception = " << err.what() << std::endl;
355 next_error_report_ *= error_report_backoff_factor_;
378 auto makePlugin(
const std::string&,
379 const fhicl::ParameterSet& pset)
381 return std::make_unique<mfplugins::ELUDP>(pset);
385 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Message Facility UDP Streamer Destination Formats messages into a delimited string and sends via UDP ...