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