artdaq_utilities  1.08.06
procFile_metric.cc
1 
2 #include "TRACE/tracemf.h" // order matters -- trace.h (no "mf") is nested from MetricMacros.hh
3 #define TRACE_NAME (app_name_ + "_procfile_metric").c_str()
4 
5 #include "artdaq-utilities/Plugins/MetricMacros.hh"
6 #include "fhiclcpp/ParameterSet.h"
7 
8 #include <fcntl.h> // open
9 #include <sys/stat.h> // mkfifo
10 #include <boost/thread.hpp>
11 #include <cstdlib> // exit
12 #include <ctime>
13 #include <map>
14 #include <string>
15 
16 namespace artdaq {
23 class ProcFileMetric final : public MetricPlugin
24 {
25 private:
26  std::string pipe_;
27  std::unordered_map<std::string, std::string> value_map_;
28  bool stopped_;
29  boost::thread thread_;
30 
31  ProcFileMetric(const ProcFileMetric&) = delete;
32  ProcFileMetric(ProcFileMetric&&) = delete;
33  ProcFileMetric& operator=(const ProcFileMetric&) = delete;
34  ProcFileMetric& operator=(ProcFileMetric&&) = delete;
35 
36 public:
49  explicit ProcFileMetric(fhicl::ParameterSet const& config, std::string const& app_name, std::string const& metric_name)
50  : MetricPlugin(config, app_name, metric_name)
51  , pipe_(pset.get<std::string>("pipe", "/tmp/eventQueueStat"))
52  , stopped_(true)
53  {
54  METLOG(TLVL_DEBUG + 33) << "ProcFileMetric ctor";
55  auto names = pset.get<std::vector<std::string>>("names", std::vector<std::string>());
56 
57  for (const auto& name : names)
58  {
59  value_map_[name] = "";
60  }
61 
62  int sts = mkfifo(pipe_.c_str(), 0777);
63  if (sts != 0) { perror("ProcFileMetric mkfifo"); }
64  METLOG(TLVL_DEBUG + 35) << "ProcFileMetric mkfifo()" << pipe_ << " sts=" << sts;
65  startMetrics();
66  }
67 
71  ~ProcFileMetric() override
72  {
73  METLOG(TLVL_DEBUG + 36) << "~ProcFileMetric";
74  stopMetrics();
75  }
76 
81  std::string getLibName() const override { return "procFile"; }
82 
88  void sendMetric_(const std::string& name, const std::string& value, const std::string& /*unit*/, const std::chrono::system_clock::time_point& /*time*/) override
89  {
90  if (value_map_.count(name) != 0u)
91  {
92  METLOG(TLVL_DEBUG + 37) << "sendMetric_ setting value=" << value;
93  value_map_[name] = value;
94  }
95  }
96 
104  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
105  {
106  sendMetric_(name, std::to_string(value), unit, time);
107  }
108 
116  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
117  {
118  sendMetric_(name, std::to_string(value), unit, time);
119  }
120 
128  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
129  {
130  sendMetric_(name, std::to_string(value), unit, time);
131  }
132 
140  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
141  {
142  sendMetric_(name, std::to_string(value), unit, time);
143  }
144 
148  void startMetrics_() override
149  {
150  if (stopped_)
151  {
152  // start thread
153  stopped_ = false;
154  boost::thread::attributes attrs;
155  attrs.set_stack_size(4096 * 2000); // 8000 KB
156  try
157  {
158  thread_ = boost::thread(attrs, boost::bind(&ProcFileMetric::writePipe, this));
159  }
160  catch (boost::exception const& e)
161  {
162  TLOG(TLVL_ERROR) << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e);
163  std::cerr << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e) << std::endl;
164  exit(4);
165  }
166  }
167  }
168 
172  void stopMetrics_() override
173  {
174  if (!stopped_)
175  {
176  stopped_ = true;
177  // do read on pipe to make sure writePipe is not blocking on open
178  METLOG(TLVL_DEBUG + 36) << "stopMetrics_ before open " << pipe_;
179  int fd = open(pipe_.c_str(), O_RDONLY | O_NONBLOCK);
180  if (fd == -1)
181  {
182  perror("stopMetrics_ open(\"r\")");
183  exit(1);
184  }
185  METLOG(TLVL_DEBUG + 35) << "stopMetrics_ between open and unlink" << pipe_ << " fd=" << fd;
186  unlink(pipe_.c_str());
187  METLOG(TLVL_DEBUG + 36) << "stopMetrics_ unlinked " << pipe_;
188 #if 0
189  char buf[256];
190  read(fd, buf, sizeof(buf));
191 #endif
192  usleep(10000);
193  close(fd);
194  METLOG(TLVL_DEBUG + 36) << "stopMetrics_ after close " << pipe_;
195  if (thread_.joinable())
196  {
197  thread_.join();
198  }
199  }
200  }
201 
205  void writePipe()
206  {
207  while (!stopped_)
208  {
209  METLOG(TLVL_DEBUG + 36) << "writePipe before open";
210  int fd = open(pipe_.c_str(), O_WRONLY);
211  std::string str;
212  for (const auto& value : value_map_)
213  {
214  METLOG(TLVL_DEBUG + 35) << "writePipe open fd=" << fd << " name=" << value.first << " value=" << value.second; // can't have args b/c name may have %
215  str += value.first + ": " + value.second + "\n";
216  // snprintf(buf, sizeof(buf), "%s: %lu\n", value.first.c_str(), value.second);
217  }
218  int sts = write(fd, str.c_str(), str.size());
219  METLOG(TLVL_DEBUG + 36) << "writePipe write complete sts=" << sts;
220  close(fd);
221  METLOG(TLVL_DEBUG + 36) << "writePipe after close -- about to usleep";
222  usleep(400000); // must wait to make sure other end closes
223  }
224  }
225 };
226 } // End namespace artdaq
227 
228 DEFINE_ARTDAQ_METRIC(artdaq::ProcFileMetric)
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:41
void sendMetric_(const std::string &name, const std::string &value, const std::string &, const std::chrono::system_clock::time_point &) override
Set the value to be written to the pipe when it is opened by a reader.
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
std::string getLibName() const override
Get the &quot;library name&quot; of this Metric.
void stopMetrics_() override
Open the pipe for reading to allow the metric-sending thread to end gracefully.
fhicl::ParameterSet pset
The ParameterSet used to configure the MetricPlugin.
void startMetrics_() override
Start the metric-sending thread.
void writePipe()
Wait for the pipe to be opened and then write the current value to it.
void stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
void sendMetric_(const std::string &name, const int &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Set the value to be written to the pipe when it is opened by a reader.
~ProcFileMetric() override
ProcFileMetric Destructor.
ProcFileMetric(fhicl::ParameterSet const &config, std::string const &app_name, std::string const &metric_name)
ProcFileMetric Constructor.
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Set the value to be written to the pipe when it is opened by a reader.
void sendMetric_(const std::string &name, const float &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Set the value to be written to the pipe when it is opened by a reader.
void sendMetric_(const std::string &name, const double &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Set the value to be written to the pipe when it is opened by a reader.
A MetricPlugin which writes a long unsigned int metric with a given name to a given pipe...