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