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 < 0x20201 // v2_02_01 is s67
7 # include "messagefacility/MessageService/MessageDrop.h"
9 # include "messagefacility/MessageLogger/MessageLogger.h"
11 #include "messagefacility/Utilities/exception.h"
12 #include "cetlib/compiler_macros.h"
19 #include <arpa/inet.h>
22 #include <netinet/in.h>
26 #include <boost/asio.hpp>
27 #include <boost/algorithm/string.hpp>
29 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
30 #define format_ format
35 using mf::service::ELdestination;
36 using mf::ELseverityLevel;
38 using boost::asio::ip::udp;
44 class ELUDP :
public ELdestination
46 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
49 fhicl::TableFragment<ELdestination::Config> elDestConfig;
50 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 };
51 fhicl::Atom<int> error_report{ fhicl::Name{
"error_report_backoff_factor" },fhicl::Comment{
"Print an error message every N errors" },100 };
52 fhicl::Atom<std::string> host{ fhicl::Name{
"host" },fhicl::Comment{
"Address to send messages to" },
"227.128.12.27" };
53 fhicl::Atom<int> port{ fhicl::Name{
"port" },fhicl::Comment{
"Port to send messages to" },5140 };
55 using Parameters = fhicl::WrappedTable<Config>;
58 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
59 ELUDP(
const fhicl::ParameterSet& pset);
61 ELUDP(Parameters
const& pset);
64 virtual void fillPrefix(std::ostringstream&,
const ErrorObj&)
override;
66 virtual void fillUsrMsg(std::ostringstream&,
const ErrorObj&)
override;
68 virtual void fillSuffix(std::ostringstream&,
const ErrorObj&)
override {}
70 virtual void routePayload(
const std::ostringstream&,
const ErrorObj&)
override;
73 void reconnect_(
bool quiet =
false);
76 int error_report_backoff_factor_;
82 boost::asio::io_service io_service_;
84 udp::endpoint remote_endpoint_;
85 int consecutive_success_count_;
87 int next_error_report_;
92 std::string hostname_;
93 std::string hostaddr_;
106 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
107 ELUDP::ELUDP(
const fhicl::ParameterSet& pset)
108 : ELdestination(pset)
109 , error_report_backoff_factor_(pset.get<int>(
"error_report_backoff_factor", 100))
110 , error_max_(pset.get<int>(
"error_turnoff_threshold", 0))
111 , host_(pset.get<std::string>(
"host",
"227.128.12.27"))
112 , port_(pset.get<int>(
"port", 5140))
115 : ELdestination(pset().elDestConfig())
116 , error_report_backoff_factor_(pset().error_report())
117 , error_max_(pset().error_max())
118 , host_(pset().host())
119 , port_(pset().port())
122 , socket_(io_service_)
124 , consecutive_success_count_(0)
126 , next_error_report_(1)
128 , pid_(static_cast<long>(getpid()))
133 char hostname_c[1024];
134 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c :
"Unkonwn Host";
137 hostent* host =
nullptr;
138 host = gethostbyname(hostname_c);
143 char* ip = inet_ntoa(*(
struct in_addr *)host->h_addr);
149 struct ifaddrs* ifAddrStruct =
nullptr;
150 struct ifaddrs* ifa =
nullptr;
151 void* tmpAddrPtr =
nullptr;
153 if (getifaddrs(&ifAddrStruct))
156 hostaddr_ =
"127.0.0.1";
161 for (ifa = ifAddrStruct; ifa !=
nullptr; ifa = ifa->ifa_next)
163 if (ifa->ifa_addr->sa_family == AF_INET)
166 tmpAddrPtr = &((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
167 char addressBuffer[INET_ADDRSTRLEN];
168 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
169 hostaddr_ = addressBuffer;
172 else if (ifa->ifa_addr->sa_family == AF_INET6)
175 tmpAddrPtr = &((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
176 char addressBuffer[INET6_ADDRSTRLEN];
177 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
178 hostaddr_ = addressBuffer;
182 if (!hostaddr_.empty()
183 && hostaddr_.compare(
"127.0.0.1")
184 && hostaddr_.compare(
"::1"))
188 if (hostaddr_.empty())
189 hostaddr_ =
"127.0.0.1";
196 std::ostringstream pid_ostr;
197 pid_ostr <<
"/proc/" << pid_ <<
"/exe";
198 exe = realpath(pid_ostr.str().c_str(), NULL);
200 size_t end = exe.find(
'\0');
201 size_t start = exe.find_last_of(
'/', end);
203 app_ = exe.substr(start + 1, end - start - 1);
206 std::stringstream ss;
207 ss <<
"//proc//" << pid_ <<
"//cmdline";
208 std::ifstream procfile{ ss.str().c_str() };
210 std::string procinfo;
212 if (procfile.is_open())
214 procfile >> procinfo;
218 size_t end = procinfo.find(
'\0');
219 size_t start = procinfo.find_last_of(
'/', end);
221 app_ = procinfo.substr(start + 1, end - start - 1);
225 void ELUDP::reconnect_(
bool quiet)
227 boost::system::error_code ec;
228 socket_.open(udp::v4());
229 socket_.set_option(boost::asio::socket_base::reuse_address(
true), ec);
232 std::cerr <<
"An error occurred setting reuse_address to true: "
233 << ec.message() << std::endl;
236 if (boost::iequals(host_,
"Broadcast") || host_ ==
"255.255.255.255")
238 socket_.set_option(boost::asio::socket_base::broadcast(
true), ec);
239 remote_endpoint_ = udp::endpoint(boost::asio::ip::address_v4::broadcast(), port_);
243 udp::resolver resolver(io_service_);
244 udp::resolver::query query(udp::v4(), host_, std::to_string(port_));
245 remote_endpoint_ = *resolver.resolve(query);
248 socket_.connect(remote_endpoint_, ec);
253 std::cerr <<
"An Error occurred in connect(): " << ec.message() << std::endl
254 <<
" endpoint = " << remote_endpoint_ << std::endl;
267 void ELUDP::fillPrefix(std::ostringstream& oss,
const ErrorObj& msg)
269 const auto& xid = msg.xid();
272 auto module = xid.module();
274 std::replace(
id.begin(),
id.end(),
'|',
'!');
275 std::replace(app.begin(), app.end(),
'|',
'!');
276 std::replace(module.begin(), module.end(),
'|',
'!');
278 oss << format_.timestamp(msg.timestamp()) <<
"|";
279 oss << std::to_string(++seqNum_) <<
"|";
280 oss << hostname_ <<
"|";
281 oss << hostaddr_ <<
"|";
282 oss << xid.severity().getName() <<
"|";
285 # if MESSAGEFACILITY_HEX_VERSION >= 0x20201 // an indication of s67
287 oss << mf::GetIteration() <<
"|";
290 oss << mf::MessageDrop::instance()->iteration <<
"|";
292 oss << module <<
"|";
293 #if MESSAGEFACILITY_HEX_VERSION >= 0x20201
294 oss << msg.filename() <<
"|" << std::to_string(msg.lineNumber()) <<
"|";
301 void ELUDP::fillUsrMsg(std::ostringstream& oss,
const ErrorObj& msg)
303 std::ostringstream tmposs;
305 for (
auto const& val : msg.items())
311 const std::string& usrMsg = !tmposs.str().compare(0, 1,
"\n") ? tmposs.str().erase(0, 1) : tmposs.str();
319 void ELUDP::routePayload(
const std::ostringstream& oss,
const ErrorObj&)
321 if (error_count_ < error_max_ || error_max_ == 0)
325 auto string =
"UDPMFMESSAGE" + std::to_string(pid) +
"|" + oss.str();
327 auto message = boost::asio::buffer(
string);
331 socket_.send_to(message, remote_endpoint_);
332 ++consecutive_success_count_;
333 if (consecutive_success_count_ >= 5)
336 next_error_report_ = 1;
340 catch (boost::system::system_error& err)
342 consecutive_success_count_ = 0;
344 if (error_count_ == next_error_report_)
346 std::cerr <<
"An exception occurred when trying to send message " << std::to_string(seqNum_) <<
" to "
347 << remote_endpoint_ << std::endl
348 <<
" message = " << oss.str() << std::endl
349 <<
" exception = " << err.what() << std::endl;
350 next_error_report_ *= error_report_backoff_factor_;
371 #ifndef EXTERN_C_FUNC_DECLARE_START
372 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
375 EXTERN_C_FUNC_DECLARE_START
376 auto makePlugin(
const std::string&,
377 const fhicl::ParameterSet& pset)
379 return std::make_unique<mfplugins::ELUDP>(pset);
383 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Message Facility UDP Streamer Destination Formats messages into a delimited string and sends via UDP ...