$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_05_08
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "artdaq-core/Utilities/configureMessageFacility.hh" 00002 #include "messagefacility/MessageLogger/MessageLogger.h" 00003 00004 #include <unistd.h> 00005 #include <boost/filesystem.hpp> 00006 #include <boost/lexical_cast.hpp> 00007 #include <fstream> 00008 #include <sstream> 00009 #include "cetlib_except/exception.h" 00010 #include "fhiclcpp/ParameterSet.h" 00011 #include "fhiclcpp/make_ParameterSet.h" 00012 #define TRACE_NAME "configureMessageFacility" 00013 #include "tracemf.h" // TRACE_CNTL, TRACE 00014 00015 namespace BFS = boost::filesystem; 00016 00017 std::string artdaq::generateMessageFacilityConfiguration(char const* progname, bool useConsole, bool printDebug) 00018 { 00019 std::string logPathProblem = ""; 00020 std::string logfileName = ""; 00021 char* logRootString = getenv("ARTDAQ_LOG_ROOT"); 00022 char* logFhiclCode = getenv("ARTDAQ_LOG_FHICL"); 00023 char* artdaqMfextensionsDir = getenv("ARTDAQ_MFEXTENSIONS_DIR"); 00024 char* useMFExtensionsS = getenv("ARTDAQ_MFEXTENSIONS_ENABLED"); 00025 bool useMFExtensions = false; 00026 if (useMFExtensionsS != nullptr && !(strncmp(useMFExtensionsS, "0", 1) == 0)) 00027 { 00028 useMFExtensions = true; 00029 } 00030 00031 char* printTimestampsToConsoleS = getenv("ARTDAQ_LOG_TIMESTAMPS_TO_CONSOLE"); 00032 bool printTimestampsToConsole = true; 00033 if (printTimestampsToConsoleS != nullptr && strncmp(printTimestampsToConsoleS, "0", 1) == 0) 00034 { 00035 printTimestampsToConsole = false; 00036 } 00037 00038 std::string logfileDir = ""; 00039 if (logRootString != nullptr) 00040 { 00041 if (!BFS::exists(logRootString)) 00042 { 00043 logPathProblem = "Log file root directory "; 00044 logPathProblem.append(logRootString); 00045 logPathProblem.append(" does not exist!"); 00046 throw cet::exception("ConfigureMessageFacility") << logPathProblem; 00047 } 00048 else 00049 { 00050 logfileDir = logRootString; 00051 logfileDir.append("/"); 00052 logfileDir.append(progname); 00053 00054 // As long as the top-level directory exists, I don't think we 00055 // really care if we have to create application directories... 00056 if (!BFS::exists(logfileDir)) 00057 BFS::create_directory(logfileDir); 00058 00059 time_t rawtime; 00060 struct tm* timeinfo; 00061 char timeBuff[256]; 00062 time(&rawtime); 00063 timeinfo = localtime(&rawtime); 00064 strftime(timeBuff, 256, "%Y%m%d%H%M%S", timeinfo); 00065 00066 char hostname[256]; 00067 std::string hostString = ""; 00068 if (gethostname(&hostname[0], 256) == 0) 00069 { 00070 std::string tmpString(hostname); 00071 hostString = tmpString; 00072 size_t pos = hostString.find("."); 00073 if (pos != std::string::npos && pos > 2) 00074 { 00075 hostString = hostString.substr(0, pos); 00076 } 00077 } 00078 00079 logfileName.append(logfileDir); 00080 logfileName.append("/"); 00081 logfileName.append(progname); 00082 logfileName.append("-"); 00083 if (hostString.size() > 0 && logfileName.find(hostString) == std::string::npos) 00084 { 00085 logfileName.append(hostString); 00086 logfileName.append("-"); 00087 } 00088 logfileName.append(timeBuff); 00089 logfileName.append("-"); 00090 logfileName.append(boost::lexical_cast<std::string>(getpid())); 00091 logfileName.append(".log"); 00092 } 00093 } 00094 00095 std::ostringstream ss; 00096 ss << "debugModules:[\"*\"] " 00097 << " destinations : { "; 00098 00099 if (useConsole) 00100 { 00101 std::string outputLevel = "\"INFO\" "; 00102 if (printDebug) outputLevel = "\"DEBUG\" "; 00103 if (artdaqMfextensionsDir != nullptr && useMFExtensions) 00104 { 00105 ss << " console : { " 00106 << " type : \"ANSI\" threshold : " << outputLevel; 00107 if (!printTimestampsToConsole) 00108 { 00109 ss << " format: { timestamp: none } "; 00110 } 00111 ss << " bell_on_error: true "; 00112 ss << " } "; 00113 } 00114 else 00115 { 00116 ss << " console : { " 00117 << " type : \"cout\" threshold :" << outputLevel; 00118 if (!printTimestampsToConsole) 00119 { 00120 ss << " format: { timestamp: none } "; 00121 } 00122 ss << " } "; 00123 } 00124 } 00125 00126 if (logfileDir.size()) 00127 { 00128 ss << " file: {"; 00129 ss << " type: \"GenFile\" threshold: \"DEBUG\" seperator: \"-\""; 00130 ss << " pattern: \"" << progname << "-%?H%t-%p.log" 00131 << "\""; 00132 ss << " timestamp_pattern: \"%Y%m%d%H%M%S\""; 00133 ss << " directory: \"" << logfileDir << "\""; 00134 ss << " append : false"; 00135 ss << " }"; 00136 } 00137 #if 0 // ELF 01/17/2018 Removed because it violates the "every EVB art process must have identical configuration" rule 00138 else if (logfileName.length() > 0) 00139 { 00140 ss << " file : { " 00141 << " type : \"file\" threshold : \"DEBUG\" " 00142 << " filename : \"" << logfileName << "\" " 00143 << " append : false " 00144 << " } "; 00145 } 00146 #endif 00147 00148 if (artdaqMfextensionsDir != nullptr && useMFExtensions) 00149 { 00150 ss << " trace : { " 00151 << " type : \"TRACE\" threshold : \"DEBUG\" format:{noLineBreaks: true} lvls: 0x7 lvlm: 0xF" 00152 << " } "; 00153 } 00154 00155 if (logFhiclCode != nullptr) 00156 { 00157 std::ifstream logfhicl(logFhiclCode); 00158 00159 if (logfhicl.is_open()) 00160 { 00161 std::stringstream fhiclstream; 00162 fhiclstream << logfhicl.rdbuf(); 00163 ss << fhiclstream.str(); 00164 } 00165 else 00166 { 00167 throw cet::exception("configureMessageFacility") << "Unable to open requested fhicl file \"" << logFhiclCode << "\"."; 00168 } 00169 } 00170 00171 ss << " } "; 00172 00173 std::string pstr(ss.str()); 00174 00175 //Canonicalize string: 00176 fhicl::ParameterSet tmp_pset; 00177 fhicl::make_ParameterSet(pstr, tmp_pset); 00178 return tmp_pset.to_string(); 00179 } 00180 // generateMessageFacilityConfiguration 00181 00182 void artdaq::configureTRACE(fhicl::ParameterSet& trace_pset) 00183 { 00184 /* The following code handles this example fhicl: 00185 TRACE:{ 00186 TRACE_NUMENTS:500000 00187 TRACE_ARGSMAX:10 00188 TRACE_MSGMAX:0 00189 TRACE_FILE:"/tmp/trace_buffer_%u" # this is the default 00190 TRACE_LIMIT_MS:[8,80,800] 00191 TRACE_MODE:0xf 00192 TRACE_NAMLVLSET:{ 00193 #name:[lvlsmskM,lvlsmskS[,lvlsmskT]] lvlsmskT is optional 00194 name0:[0x1f,0x7] 00195 name1:[0x2f,0xf] 00196 name2:[0x3f,0x7,0x1] 00197 } 00198 } 00199 */ 00200 std::vector<std::string> names = trace_pset.get_names(); 00201 std::vector<std::string> trace_envs = {//"TRACE_NUMENTS", "TRACE_ARGSMAX", "TRACE_MSGMAX", "TRACE_FILE", 00202 "TRACE_LIMIT_MS", "TRACE_MODE", "TRACE_NAMLVLSET"}; 00203 std::unordered_map<std::string, bool> envs_set_to_unset; 00204 for (auto env : trace_envs) envs_set_to_unset[env] = false; 00205 // tricky - some env. vars. will over ride info in "mapped" (file) context while others cannot. 00206 for (auto name : names) 00207 { 00208 if (name == "TRACE_NUMENTS" || name == "TRACE_ARGSMAX" || name == "TRACE_MSGMAX" || name == "TRACE_FILE") // only applicable if env.var. set before before traceInit 00209 // don't override and don't "set_to_unset" (if "mapping", want any subprocess to map also) 00210 setenv(name.c_str(), trace_pset.get<std::string>(name).c_str(), 0); 00211 // These next 3 are looked at when TRACE_CNTL("namlvlset") is called. And, if mapped, get into file! (so may want to unset env???) 00212 else if (name == "TRACE_LIMIT_MS") 00213 { // there is also TRACE_CNTL 00214 if (!getenv(name.c_str())) 00215 { 00216 envs_set_to_unset[name] = true; 00217 std::vector<uint32_t> limit = trace_pset.get<std::vector<uint32_t>>(name); 00218 // could check that it is size()==3??? 00219 std::string limits = std::to_string(limit[0]) + "," + std::to_string(limit[1]) + "," + std::to_string(limit[2]); 00220 setenv(name.c_str(), limits.c_str(), 0); 00221 } 00222 } 00223 else if (name == "TRACE_MODE") 00224 { // env.var. only applicable if TRACE_NAMLVLSET is set, BUT could TRACE_CNTL("mode",mode)??? 00225 if (!getenv(name.c_str())) 00226 { 00227 envs_set_to_unset[name] = true; 00228 setenv(name.c_str(), trace_pset.get<std::string>(name).c_str(), 0); 00229 } 00230 } 00231 else if (name == "TRACE_NAMLVLSET") 00232 { 00233 if (!getenv(name.c_str())) 00234 { 00235 envs_set_to_unset[name] = true; 00236 std::stringstream lvlsbldr; // levels builder 00237 fhicl::ParameterSet lvls_pset = trace_pset.get<fhicl::ParameterSet>(name); 00238 std::vector<std::string> tnames = lvls_pset.get_names(); 00239 for (auto tname : tnames) 00240 { 00241 lvlsbldr << tname; 00242 std::vector<uint64_t> msks = lvls_pset.get<std::vector<uint64_t>>(tname); 00243 for (auto msk : msks) 00244 { 00245 lvlsbldr << " 0x" << std::hex << (unsigned long long)msk; 00246 } 00247 lvlsbldr << "\n"; 00248 } 00249 setenv(name.c_str(), lvlsbldr.str().c_str(), 0); // 0 means: won't overwrite 00250 } 00251 } 00252 } 00253 TRACE_CNTL("namlvlset"); // acts upon env.var. 00254 for (auto env : trace_envs) 00255 if (envs_set_to_unset[env]) unsetenv(env.c_str()); 00256 } 00257 00258 void artdaq::configureMessageFacility(char const* progname, bool useConsole, bool printDebug) 00259 { 00260 auto pstr = generateMessageFacilityConfiguration(progname, useConsole, printDebug); 00261 fhicl::ParameterSet pset; 00262 fhicl::make_ParameterSet(pstr, pset); 00263 00264 fhicl::ParameterSet trace_pset; 00265 if (!pset.get_if_present<fhicl::ParameterSet>("TRACE", trace_pset)) 00266 { 00267 fhicl::ParameterSet trace_dflt_pset; 00268 fhicl::make_ParameterSet("TRACE:{TRACE_MSGMAX:0 TRACE_LIMIT_MS:[10,500,1500]}", trace_dflt_pset); 00269 pset.put<fhicl::ParameterSet>("TRACE", trace_dflt_pset.get<fhicl::ParameterSet>("TRACE")); 00270 trace_pset = pset.get<fhicl::ParameterSet>("TRACE"); 00271 } 00272 configureTRACE(trace_pset); 00273 pstr = pset.to_string(); 00274 pset.erase("TRACE"); 00275 00276 #if CANVAS_HEX_VERSION >= 0x30300 // art v2_11_00 00277 mf::StartMessageFacility(pset, progname); 00278 00279 #else 00280 mf::StartMessageFacility(pset); 00281 00282 mf::SetApplicationName(progname); 00283 00284 mf::setEnabledState(""); 00285 #endif 00286 TLOG(TLVL_TRACE) << "Message Facility Config input is: " << pstr; 00287 TLOG(TLVL_INFO) << "Message Facility Application " << progname << " configured with: " << pset.to_string(); 00288 } 00289 00290 std::string artdaq::setMsgFacAppName(const std::string& appType, unsigned short port) 00291 { 00292 std::string appName(appType); 00293 00294 char hostname[256]; 00295 if (gethostname(&hostname[0], 256) == 0) 00296 { 00297 std::string hostString(hostname); 00298 size_t pos = hostString.find("."); 00299 if (pos != std::string::npos && pos > 2) 00300 { 00301 hostString = hostString.substr(0, pos); 00302 } 00303 appName.append("-"); 00304 appName.append(hostString); 00305 } 00306 00307 appName.append("-"); 00308 appName.append(boost::lexical_cast<std::string>(port)); 00309 00310 mf::SetApplicationName(appName); 00311 return appName; 00312 }