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