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