$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_06_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 00002 #include "tracemf.h" 00003 #define TRACE_NAME "GenFileOutput" 00004 00005 #include <boost/date_time/posix_time/posix_time.hpp> 00006 #include <fstream> 00007 #include "cetlib/PluginTypeDeducer.h" 00008 #include "cetlib/ProvideMakePluginMacros.h" 00009 #include "cetlib/ostream_handle.h" 00010 #include "fhiclcpp/ParameterSet.h" 00011 #include "messagefacility/MessageService/ELdestination.h" 00012 #include "messagefacility/Utilities/ELseverityLevel.h" 00013 #include "messagefacility/Utilities/exception.h" 00014 00015 namespace mfplugins { 00016 using mf::ErrorObj; 00017 using mf::service::ELdestination; 00018 00023 class ELGenFileOutput : public ELdestination 00024 { 00025 public: 00029 struct Config 00030 { 00032 fhicl::TableFragment<ELdestination::Config> elDestConfig; 00034 fhicl::Atom<bool> append = fhicl::Atom<bool>{ 00035 fhicl::Name{"append"}, fhicl::Comment{"Whether to append to the file or recreate it"}, true}; 00037 fhicl::Atom<std::string> baseDir = fhicl::Atom<std::string>{ 00038 fhicl::Name{"directory"}, fhicl::Comment{"The directory into which files will be saved"}, "/tmp"}; 00040 fhicl::Atom<std::string> sep = fhicl::Atom<std::string>{ 00041 fhicl::Name{"seperator"}, fhicl::Comment{"Separator to use after optional replacement parameters"}, "-"}; 00043 fhicl::Atom<std::string> timePattern = fhicl::Atom<std::string>{ 00044 fhicl::Name{"timestamp_pattern"}, fhicl::Comment{"Pattern to use for %t strftime replacement"}, "%Y%m%d%H%M%S"}; 00059 fhicl::Atom<std::string> filePattern = fhicl::Atom<std::string>{fhicl::Name{"pattern"}, fhicl::Comment{"Pattern to use for file naming.\n" 00060 " Supported parameters are:\n" 00061 " %%: Print a % sign\n" 00062 " %N: Print the executable name, as retrieved from /proc/<pid>/exe\n" 00063 " %?N: Print the executable name only if it does not already appear in the parsed format. " 00064 "Format is parsed left-to-right.\n" 00065 " These options add a seperator AFTER if they are filled and if they are not the last token in " 00066 "the file pattern, before the last '.' character.\n" 00067 " %H: Print the hostname, without any domain specifiers (i.e. work.fnal.gov will become work)\n" 00068 " %?H: Print the hostname only if it does not already appear in the parsed format.\n" 00069 " %p: Print the PID of the application configuring MessageFacility\n" 00070 " %t: Print the timestamp using the format specified by timestamp_pattern\n" 00071 " %T: Print the timestamp in ISO format"}, 00072 "%N-%?H%t-%p.log"}; 00073 }; 00075 using Parameters = fhicl::WrappedTable<Config>; 00076 00077 public: 00082 explicit ELGenFileOutput(Parameters const& pset); 00083 00089 void routePayload(const std::ostringstream& o, const ErrorObj& e) override; 00090 00094 void flush() override; 00095 00096 private: 00097 std::unique_ptr<cet::ostream_handle> output_; 00098 }; 00099 00100 // END DECLARATION 00101 //====================================================================== 00102 // BEGIN IMPLEMENTATION 00103 00104 //====================================================================== 00105 // ELGenFileOutput c'tor 00106 //====================================================================== 00107 00108 ELGenFileOutput::ELGenFileOutput(Parameters const& pset) 00109 : ELdestination(pset().elDestConfig()) 00110 { 00111 bool append = pset().append(); 00112 std::string baseDir = pset().baseDir(); 00113 std::string sep = pset().sep(); 00114 std::string timePattern = pset().timePattern(); 00115 std::string filePattern = pset().filePattern(); 00116 00117 auto pid = getpid(); 00118 std::string exeString; 00119 std::string hostString; 00120 std::string timeBuffISO; // Using boost::posix_time::to_iso_string (%T) 00121 std::string timeBuff; // Using timestamp_pattern (%t) 00122 00123 // Determine image name 00124 if (filePattern.find("%N") != std::string::npos || filePattern.find("%?N") != std::string::npos) 00125 { 00126 // get process name from '/proc/pid/exe' 00127 std::string exe; 00128 std::ostringstream pid_ostr; 00129 pid_ostr << "/proc/" << pid << "/exe"; 00130 exe = std::string(realpath(pid_ostr.str().c_str(), nullptr)); 00131 00132 size_t end = exe.find('\0'); 00133 size_t start = exe.find_last_of('/', end); 00134 exeString = exe.substr(start + 1, end - start - 1); 00135 } 00136 00137 // Get Host name 00138 if (filePattern.find("%H") != std::string::npos || filePattern.find("%?H") != std::string::npos) 00139 { 00140 char hostname[256]; 00141 if (gethostname(&hostname[0], 256) == 0) 00142 { 00143 std::string tmpString(hostname); 00144 hostString = tmpString; 00145 size_t pos = hostString.find('.'); 00146 if (pos != std::string::npos && pos > 2) 00147 { 00148 hostString = hostString.substr(0, pos); 00149 } 00150 } 00151 } 00152 if (filePattern.find("%T") != std::string::npos) 00153 { 00154 timeBuffISO = boost::posix_time::to_iso_string(boost::posix_time::second_clock::universal_time()); 00155 } 00156 if (filePattern.find("%t") != std::string::npos) 00157 { 00158 time_t rawtime; 00159 struct tm* timeinfo; 00160 char timeBuffC[256]; 00161 time(&rawtime); 00162 timeinfo = localtime(&rawtime); 00163 strftime(timeBuffC, 256, timePattern.c_str(), timeinfo); 00164 timeBuff = std::string(timeBuffC); 00165 } 00166 00167 size_t pos = 0; 00168 TLOG(TLVL_DEBUG) << "filePattern is: " << filePattern; 00169 while (filePattern.find('%', pos) != std::string::npos) 00170 { 00171 pos = filePattern.find('%', pos) + 1; 00172 TLOG(5, 1) << "Found % at " << (pos - 1) << ", next char: " << filePattern[pos] << "."; 00173 switch (filePattern[pos]) 00174 { 00175 case '%': // "%%" 00176 filePattern = filePattern.replace(pos - 1, 2, "%"); 00177 pos--; 00178 break; 00179 case '?': 00180 { 00181 char next = filePattern[pos + 1]; 00182 switch (next) 00183 { 00184 case 'N': 00185 if (filePattern.find(exeString) != std::string::npos) 00186 { 00187 filePattern = filePattern.erase(pos - 1, 3); 00188 } 00189 else 00190 { 00191 std::string repString = exeString; 00192 // Only append separator if we're not at the end of the pattern 00193 if (!(pos + 1 == filePattern.size() - 1 || pos + 2 == filePattern.find_last_of('.'))) 00194 { 00195 repString += sep; 00196 } 00197 filePattern = filePattern.replace(pos - 1, 3, repString); 00198 } 00199 break; 00200 case 'H': 00201 if (filePattern.find(hostString) != std::string::npos) 00202 { 00203 filePattern = filePattern.erase(pos - 1, 3); 00204 } 00205 else 00206 { 00207 std::string repString = hostString; 00208 // Only append separator if we're not at the end of the pattern 00209 if (!(pos + 1 == filePattern.size() - 1 || pos + 2 == filePattern.find_last_of('.'))) 00210 { 00211 repString += sep; 00212 } 00213 filePattern = filePattern.replace(pos - 1, 3, repString); 00214 } 00215 break; 00216 default: 00217 pos += 3; 00218 break; 00219 } 00220 pos -= 3; 00221 } 00222 break; 00223 case 'N': 00224 filePattern = filePattern.replace(pos - 1, 2, exeString); 00225 pos -= 2; 00226 break; 00227 case 'H': 00228 filePattern = filePattern.replace(pos - 1, 2, hostString); 00229 pos -= 2; 00230 break; 00231 case 'p': 00232 filePattern = filePattern.replace(pos - 1, 2, std::to_string(pid)); 00233 pos -= 2; 00234 break; 00235 case 't': 00236 filePattern = filePattern.replace(pos - 1, 2, timeBuff); 00237 pos -= 2; 00238 break; 00239 case 'T': 00240 filePattern = filePattern.replace(pos - 1, 2, timeBuffISO); 00241 pos -= 2; 00242 break; 00243 default: 00244 break; 00245 } 00246 TLOG(6) << "filePattern is now: " << filePattern; 00247 } 00248 std::string fileName = baseDir + "/" + filePattern; 00249 TLOG(TLVL_DEBUG) << "fileName is: " << fileName; 00250 00251 output_ = std::make_unique<cet::ostream_handle>(fileName.c_str(), append ? std::ios::app : std::ios::trunc); 00252 } 00253 00254 //====================================================================== 00255 // Message router ( overriddes ELdestination::routePayload ) 00256 //====================================================================== 00257 void ELGenFileOutput::routePayload(const std::ostringstream& oss, const ErrorObj& /*msg*/) 00258 { 00259 *output_ << oss.str(); 00260 flush(); 00261 } 00262 00263 void ELGenFileOutput::flush() 00264 { 00265 output_->flush(); 00266 } 00267 } // end namespace mfplugins 00268 00269 //====================================================================== 00270 // 00271 // makePlugin function 00272 // 00273 //====================================================================== 00274 00275 extern "C" { 00276 MAKE_PLUGIN_START(auto, std::string const&, fhicl::ParameterSet const& pset) 00277 { 00278 return std::make_unique<mfplugins::ELGenFileOutput>(pset); 00279 } 00280 MAKE_PLUGIN_END 00281 } 00282 00283 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)