1 #include "cetlib/PluginTypeDeducer.h"
2 #include "cetlib/ostream_handle.h"
3 #if MESSAGEFACILITY_HEX_VERSION >= 0x20106 // v2_01_06 => cetlib v3_02_00 => new clang support
4 #include "cetlib/ProvideMakePluginMacros.h"
6 #include "fhiclcpp/ParameterSet.h"
8 #include "boost/date_time/posix_time/posix_time.hpp"
10 #include "messagefacility/MessageService/ELdestination.h"
11 # include "messagefacility/Utilities/ELseverityLevel.h"
12 #if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
13 # include "messagefacility/MessageService/ELcontextSupplier.h"
14 # include "messagefacility/MessageLogger/MessageDrop.h"
16 #include "messagefacility/Utilities/exception.h"
23 using mf::service::ELdestination;
24 using mf::ELseverityLevel;
26 #if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
27 using mf::service::ELcontextSupplier;
36 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
39 fhicl::TableFragment<ELdestination::Config> elDestConfig;
40 fhicl::Atom<bool> append{ fhicl::Name{
"append"},fhicl::Comment {
"Whether to append to the file or recreate it"},
true };
41 fhicl::Atom<std::string> baseDir{ fhicl::Name{
"directory"},fhicl::Comment{
"The directory into which files will be saved"},
"/tmp" };
42 fhicl::Atom<std::string> sep{ fhicl::Name{
"separator"},fhicl::Comment{
"Separator to use after optional replacement parameters"},
"-" };
43 fhicl::Atom<std::string> timePattern{ fhicl::Name{
"timestamp_pattern"},fhicl::Comment{
"Pattern to use for %t strftime replacement"},
"%Y%m%d%H%M%S" };
44 fhicl::Atom<std::string> filePattern{ fhicl::Name{
"pattern" },fhicl::Comment{
"Pattern to use for file naming.\n"
45 " Supported parameters are:\n"
46 " %%: Print a % sign\n"
47 " %N: Print the executable name, as retrieved from /proc/<pid>/exe\n"
48 " %?N: Print the executable name only if it does not already appear in the parsed format. Format is parsed left-to-right.\n"
49 " These options add a separator AFTER if they are filled and if they are not the last token in the file pattern, before the last '.' character.\n"
50 " %H: Print the hostname, without any domain specifiers (i.e. work.fnal.gov will become work)\n"
51 " %?H: Print the hostname only if it does not already appear in the parsed format.\n"
52 " %p: Print the PID of the application configuring MessageFacility\n"
53 " %t: Print the timestamp using the format specified by timestamp_pattern\n"
54 " %T: Print the timestamp in ISO format"
55 },
"%N-%?H%t-%p.log" };
59 using Parameters = fhicl::WrappedTable<Config>;
63 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
71 virtual void routePayload(
const std::ostringstream&,
const ErrorObj&
72 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
73 ,
const ELcontextSupplier&
78 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
79 const ELcontextSupplier&
84 std::unique_ptr<cet::ostream_handle> output_;
95 #if MESSAGEFACILITY_HEX_VERSION < 0x20103
96 ELGenFileOutput::ELGenFileOutput(
const fhicl::ParameterSet& pset)
99 bool append = pset.get<
bool>(
"append",
true);
100 std::string baseDir = pset.get<std::string>(
"directory",
"/tmp");
101 std::string sep = pset.get<std::string>(
"separator",
"-");
102 std::string timePattern = pset.get<std::string>(
"timestamp_pattern",
"%Y%m%d%H%M%S");
103 std::string filePattern = pset.get<std::string>(
"pattern",
"%N-%?H%t-%p.log");
105 ELGenFileOutput::ELGenFileOutput(Parameters
const& pset) : ELdestination(pset().elDestConfig())
107 bool append = pset().append();
108 std::string baseDir = pset().baseDir();
109 std::string sep = pset().sep();
110 std::string timePattern = pset().timePattern();
111 std::string filePattern = pset().filePattern();
115 std::string exeString =
"";
116 std::string hostString =
"";
117 std::string timeBuffISO =
"";
118 std::string timeBuff =
"";
122 if (filePattern.find(
"%N") != std::string::npos || filePattern.find(
"%?N") != std::string::npos)
126 std::ostringstream pid_ostr;
127 pid_ostr <<
"/proc/" << pid <<
"/exe";
128 exe = std::string(realpath(pid_ostr.str().c_str(), NULL));
130 size_t end = exe.find(
'\0');
131 size_t start = exe.find_last_of(
'/', end);
132 exeString = exe.substr(start + 1, end - start - 1);
136 if (filePattern.find(
"%H") != std::string::npos || filePattern.find(
"%?H") != std::string::npos)
139 if (gethostname(&hostname[0], 256) == 0)
141 std::string tmpString(hostname);
142 hostString = tmpString;
143 size_t pos = hostString.find(
".");
144 if (pos != std::string::npos && pos > 2)
146 hostString = hostString.substr(0, pos);
150 if (filePattern.find(
"%T") != std::string::npos)
152 timeBuffISO = boost::posix_time::to_iso_string(boost::posix_time::second_clock::universal_time());
154 if (filePattern.find(
"%t") != std::string::npos)
161 timeinfo = localtime(&rawtime);
162 strftime(timeBuffC, 256, timePattern.c_str(), timeinfo);
163 timeBuff = std::string(timeBuffC);
167 TLOG_DEBUG(
"GenFile") <<
"filePattern is: " << filePattern << TLOG_ENDL;
168 while (filePattern.find(
"%", pos) != std::string::npos)
170 pos = filePattern.find(
"%", pos) + 1;
171 TLOG_ARB(5,
"GenFile") <<
"Found % at " << std::to_string(pos - 1) <<
", next char: " << filePattern[pos] <<
"." << TLOG_ENDL;
172 switch (filePattern[pos])
175 filePattern = filePattern.replace(pos - 1, 2,
"%");
180 char next = filePattern[pos + 1];
183 if (filePattern.find(exeString) != std::string::npos) {
184 filePattern = filePattern.erase(pos - 1, 3);
187 std::string repString = exeString;
189 if (!(pos + 1 == filePattern.size() - 1 || pos + 2 == filePattern.find_last_of(
'.'))) {
192 filePattern = filePattern.replace(pos - 1, 3, repString);
196 if (filePattern.find(hostString) != std::string::npos) {
197 filePattern = filePattern.erase(pos - 1, 3);
200 std::string repString = hostString;
202 if (!(pos + 1 == filePattern.size() - 1 || pos + 2 == filePattern.find_last_of(
'.'))) {
205 filePattern = filePattern.replace(pos - 1, 3, repString);
213 filePattern = filePattern.replace(pos - 1, 2, exeString);
217 filePattern = filePattern.replace(pos - 1, 2, hostString);
221 filePattern = filePattern.replace(pos - 1, 2, std::to_string(pid));
225 filePattern = filePattern.replace(pos - 1, 2, timeBuff);
229 filePattern = filePattern.replace(pos - 1, 2, timeBuffISO);
233 TLOG_ARB(6,
"GenFile") <<
"filePattern is now: " << filePattern << TLOG_ENDL;
235 std::string fileName = baseDir +
"/" + filePattern;
236 TLOG_DEBUG(
"GenFile") <<
"fileName is: " << fileName << TLOG_ENDL;
238 output_ = std::make_unique<cet::ostream_handle>(fileName.c_str(), append ? std::ios::app : std::ios::trunc);
244 void ELGenFileOutput::routePayload(
const std::ostringstream& oss,
const ErrorObj&
245 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
246 , ELcontextSupplier
const& sup
250 *output_ << oss.str();
252 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
258 void ELGenFileOutput::flush(
259 #
if MESSAGEFACILITY_HEX_VERSION < 0x20002
260 ELcontextSupplier
const&
277 #if MESSAGEFACILITY_HEX_VERSION >= 0x20106 // v2_01_06 => cetlib v3_02_00 => new clang support
278 MAKE_PLUGIN_START(
auto, std::string
const&, fhicl::ParameterSet
const& pset)
280 return std::make_unique<mfplugins::ELGenFileOutput>(pset);
283 auto makePlugin(std::string
const&, fhicl::ParameterSet
const& pset) {
284 return std::make_unique<mfplugins::ELGenFileOutput>(pset);
289 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
Message Facility destination which generates the output file name based on some combination of PID...