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