artdaq_core  v3_05_10
configureMessageFacility.cc
1 #include "artdaq-core/Utilities/configureMessageFacility.hh"
2 #include "messagefacility/MessageLogger/MessageLogger.h"
3 
4 #include <unistd.h>
5 #include <boost/filesystem.hpp>
6 #include <boost/lexical_cast.hpp>
7 #include <fstream>
8 #include <sstream>
9 #include "cetlib_except/exception.h"
10 #include "fhiclcpp/ParameterSet.h"
11 #include "fhiclcpp/make_ParameterSet.h"
12 #define TRACE_NAME "configureMessageFacility"
13 #include "tracemf.h" // TRACE_CNTL, TRACE
14 
15 namespace BFS = boost::filesystem;
16 
17 std::string artdaq::generateMessageFacilityConfiguration(char const* progname, bool useConsole, bool printDebug)
18 {
19  std::string logPathProblem = "";
20  std::string logfileName = "";
21  char* logRootString = getenv("ARTDAQ_LOG_ROOT");
22  char* logFhiclCode = getenv("ARTDAQ_LOG_FHICL");
23  char* artdaqMfextensionsDir = getenv("ARTDAQ_MFEXTENSIONS_DIR");
24  char* useMFExtensionsS = getenv("ARTDAQ_MFEXTENSIONS_ENABLED");
25  bool useMFExtensions = false;
26  if (useMFExtensionsS != nullptr && !(strncmp(useMFExtensionsS, "0", 1) == 0))
27  {
28  useMFExtensions = true;
29  }
30 
31  char* printTimestampsToConsoleS = getenv("ARTDAQ_LOG_TIMESTAMPS_TO_CONSOLE");
32  bool printTimestampsToConsole = true;
33  if (printTimestampsToConsoleS != nullptr && strncmp(printTimestampsToConsoleS, "0", 1) == 0)
34  {
35  printTimestampsToConsole = false;
36  }
37 
38  std::string logfileDir = "";
39  if (logRootString != nullptr)
40  {
41  if (!BFS::exists(logRootString))
42  {
43  logPathProblem = "Log file root directory ";
44  logPathProblem.append(logRootString);
45  logPathProblem.append(" does not exist!");
46  throw cet::exception("ConfigureMessageFacility") << logPathProblem;
47  }
48  else
49  {
50  logfileDir = logRootString;
51  logfileDir.append("/");
52  logfileDir.append(progname);
53 
54  // As long as the top-level directory exists, I don't think we
55  // really care if we have to create application directories...
56  if (!BFS::exists(logfileDir))
57  {
58  BFS::create_directory(logfileDir);
59  BFS::permissions(logfileDir, BFS::add_perms | BFS::owner_all | BFS::group_all | BFS::others_read);
60  }
61 
62  time_t rawtime;
63  struct tm* timeinfo;
64  char timeBuff[256];
65  time(&rawtime);
66  timeinfo = localtime(&rawtime);
67  strftime(timeBuff, 256, "%Y%m%d%H%M%S", timeinfo);
68 
69  char hostname[256];
70  std::string hostString = "";
71  if (gethostname(&hostname[0], 256) == 0)
72  {
73  std::string tmpString(hostname);
74  hostString = tmpString;
75  size_t pos = hostString.find(".");
76  if (pos != std::string::npos && pos > 2)
77  {
78  hostString = hostString.substr(0, pos);
79  }
80  }
81 
82  logfileName.append(logfileDir);
83  logfileName.append("/");
84  logfileName.append(progname);
85  logfileName.append("-");
86  if (hostString.size() > 0 && logfileName.find(hostString) == std::string::npos)
87  {
88  logfileName.append(hostString);
89  logfileName.append("-");
90  }
91  logfileName.append(timeBuff);
92  logfileName.append("-");
93  logfileName.append(boost::lexical_cast<std::string>(getpid()));
94  logfileName.append(".log");
95  }
96  }
97 
98  std::ostringstream ss;
99  //ss << "debugModules:[\"*\"] "
100  ss << " destinations : { ";
101 
102  if (useConsole)
103  {
104  std::string outputLevel = "\"INFO\" ";
105  if (printDebug) outputLevel = "\"DEBUG\" ";
106  if (artdaqMfextensionsDir != nullptr && useMFExtensions)
107  {
108  ss << " console : { "
109  << " type : \"ANSI\" threshold : " << outputLevel;
110  if (!printTimestampsToConsole)
111  {
112  ss << " format: { timestamp: none } ";
113  }
114  ss << " bell_on_error: true ";
115  ss << " } ";
116  }
117  else
118  {
119  ss << " console : { "
120  << " type : \"cout\" threshold :" << outputLevel;
121  if (!printTimestampsToConsole)
122  {
123  ss << " format: { timestamp: none } ";
124  }
125  ss << " } ";
126  }
127  }
128 
129  if (logfileDir.size())
130  {
131  ss << " file: {";
132  ss << " type: \"GenFile\" threshold: \"DEBUG\" seperator: \"-\"";
133  ss << " pattern: \"" << progname << "-%?H%t-%p.log"
134  << "\"";
135  ss << " timestamp_pattern: \"%Y%m%d%H%M%S\"";
136  ss << " directory: \"" << logfileDir << "\"";
137  ss << " append : false";
138  ss << " }";
139  }
140 #if 0 // ELF 01/17/2018 Removed because it violates the "every EVB art process must have identical configuration" rule
141  else if (logfileName.length() > 0)
142  {
143  ss << " file : { "
144  << " type : \"file\" threshold : \"DEBUG\" "
145  << " filename : \"" << logfileName << "\" "
146  << " append : false "
147  << " } ";
148  }
149 #endif
150 
151  if (artdaqMfextensionsDir != nullptr && useMFExtensions)
152  {
153  ss << " trace : { "
154  << " type : \"TRACE\" threshold : \"DEBUG\" format:{noLineBreaks: true} lvls: 0x7 lvlm: 0xF"
155  << " } ";
156  }
157 
158  if (logFhiclCode != nullptr)
159  {
160  std::ifstream logfhicl(logFhiclCode);
161 
162  if (logfhicl.is_open())
163  {
164  std::stringstream fhiclstream;
165  fhiclstream << logfhicl.rdbuf();
166  ss << fhiclstream.str();
167  }
168  else
169  {
170  throw cet::exception("configureMessageFacility") << "Unable to open requested fhicl file \"" << logFhiclCode << "\".";
171  }
172  }
173 
174  ss << " } ";
175 
176  std::string pstr(ss.str());
177 
178  //Canonicalize string:
179  fhicl::ParameterSet tmp_pset;
180  fhicl::make_ParameterSet(pstr, tmp_pset);
181  return tmp_pset.to_string();
182 }
183 // generateMessageFacilityConfiguration
184 
185 void artdaq::configureTRACE(fhicl::ParameterSet& trace_pset)
186 {
187  /* The following code handles this example fhicl:
188  TRACE:{
189  TRACE_NUMENTS:500000
190  TRACE_ARGSMAX:10
191  TRACE_MSGMAX:0
192  TRACE_FILE:"/tmp/trace_buffer_%u" # this is the default
193  TRACE_LIMIT_MS:[8,80,800]
194  TRACE_MODE:0xf
195  TRACE_NAMLVLSET:{
196  #name:[lvlsmskM,lvlsmskS[,lvlsmskT]] lvlsmskT is optional
197  name0:[0x1f,0x7]
198  name1:[0x2f,0xf]
199  name2:[0x3f,0x7,0x1]
200  }
201  }
202  */
203  std::vector<std::string> names = trace_pset.get_names();
204  std::vector<std::string> trace_envs = {//"TRACE_NUMENTS", "TRACE_ARGSMAX", "TRACE_MSGMAX", "TRACE_FILE",
205  "TRACE_LIMIT_MS", "TRACE_MODE", "TRACE_NAMLVLSET"};
206  std::unordered_map<std::string, bool> envs_set_to_unset;
207  for (auto env : trace_envs) envs_set_to_unset[env] = false;
208  // tricky - some env. vars. will over ride info in "mapped" (file) context while others cannot.
209  for (auto name : names)
210  {
211  if (name == "TRACE_NUMENTS" || name == "TRACE_ARGSMAX" || name == "TRACE_MSGMAX" || name == "TRACE_FILE") // only applicable if env.var. set before before traceInit
212  // don't override and don't "set_to_unset" (if "mapping", want any subprocess to map also)
213  setenv(name.c_str(), trace_pset.get<std::string>(name).c_str(), 0);
214  // These next 3 are looked at when TRACE_CNTL("namlvlset") is called. And, if mapped, get into file! (so may want to unset env???)
215  else if (name == "TRACE_LIMIT_MS")
216  { // there is also TRACE_CNTL
217  if (!getenv(name.c_str()))
218  {
219  envs_set_to_unset[name] = true;
220  std::vector<uint32_t> limit = trace_pset.get<std::vector<uint32_t>>(name);
221  // could check that it is size()==3???
222  std::string limits = std::to_string(limit[0]) + "," + std::to_string(limit[1]) + "," + std::to_string(limit[2]);
223  setenv(name.c_str(), limits.c_str(), 0);
224  }
225  }
226  else if (name == "TRACE_MODE")
227  { // env.var. only applicable if TRACE_NAMLVLSET is set, BUT could TRACE_CNTL("mode",mode)???
228  if (!getenv(name.c_str()))
229  {
230  envs_set_to_unset[name] = true;
231  setenv(name.c_str(), trace_pset.get<std::string>(name).c_str(), 0);
232  }
233  }
234  else if (name == "TRACE_NAMLVLSET")
235  {
236  if (!getenv(name.c_str()))
237  {
238  envs_set_to_unset[name] = true;
239  std::stringstream lvlsbldr; // levels builder
240  fhicl::ParameterSet lvls_pset = trace_pset.get<fhicl::ParameterSet>(name);
241  std::vector<std::string> tnames = lvls_pset.get_names();
242  for (auto tname : tnames)
243  {
244  lvlsbldr << tname;
245  std::vector<uint64_t> msks = lvls_pset.get<std::vector<uint64_t>>(tname);
246  for (auto msk : msks)
247  {
248  lvlsbldr << " 0x" << std::hex << (unsigned long long)msk;
249  }
250  lvlsbldr << "\n";
251  }
252  setenv(name.c_str(), lvlsbldr.str().c_str(), 0); // 0 means: won't overwrite
253  }
254  }
255  }
256  TRACE_CNTL("namlvlset"); // acts upon env.var.
257  for (auto env : trace_envs)
258  if (envs_set_to_unset[env]) unsetenv(env.c_str());
259 }
260 
261 void artdaq::configureMessageFacility(char const* progname, bool useConsole, bool printDebug)
262 {
263  auto pstr = generateMessageFacilityConfiguration(progname, useConsole, printDebug);
264  fhicl::ParameterSet pset;
265  fhicl::make_ParameterSet(pstr, pset);
266 
267  fhicl::ParameterSet trace_pset;
268  if (!pset.get_if_present<fhicl::ParameterSet>("TRACE", trace_pset))
269  {
270  fhicl::ParameterSet trace_dflt_pset;
271  fhicl::make_ParameterSet("TRACE:{TRACE_MSGMAX:0 TRACE_LIMIT_MS:[10,500,1500]}", trace_dflt_pset);
272  pset.put<fhicl::ParameterSet>("TRACE", trace_dflt_pset.get<fhicl::ParameterSet>("TRACE"));
273  trace_pset = pset.get<fhicl::ParameterSet>("TRACE");
274  }
275  configureTRACE(trace_pset);
276  pstr = pset.to_string();
277  pset.erase("TRACE");
278 
279 #if CANVAS_HEX_VERSION >= 0x30300 // art v2_11_00
280  mf::StartMessageFacility(pset, progname);
281 
282 #else
283  mf::StartMessageFacility(pset);
284 
285  mf::SetApplicationName(progname);
286 
287  mf::setEnabledState("");
288 #endif
289  TLOG(TLVL_TRACE) << "Message Facility Config input is: " << pstr;
290  TLOG(TLVL_INFO) << "Message Facility Application " << progname << " configured with: " << pset.to_string();
291 }
292 
293 std::string artdaq::setMsgFacAppName(const std::string& appType, unsigned short port)
294 {
295  std::string appName(appType);
296 
297  char hostname[256];
298  if (gethostname(&hostname[0], 256) == 0)
299  {
300  std::string hostString(hostname);
301  size_t pos = hostString.find(".");
302  if (pos != std::string::npos && pos > 2)
303  {
304  hostString = hostString.substr(0, pos);
305  }
306  appName.append("-");
307  appName.append(hostString);
308  }
309 
310  appName.append("-");
311  appName.append(boost::lexical_cast<std::string>(port));
312 
313  mf::SetApplicationName(appName);
314  return appName;
315 }
void configureTRACE(fhicl::ParameterSet &trace_pset)
Configure TRACE.
std::string generateMessageFacilityConfiguration(char const *progname, bool useConsole=true, bool printDebug=false)
Create the MessageFacility configuration Fhicl string.
void configureMessageFacility(char const *progname, bool useConsole=true, bool printDebug=false)
Configure and start the message facility. Provide the program name so that messages will be appropria...
std::string setMsgFacAppName(const std::string &appType, unsigned short port)
Set the message facility application name using the specified application type and port number...