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