artdaq_utilities  v1_07_00
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 #include "messagefacility/MessageLogger/MessageLogger.h"
8 
9 #include <fcntl.h> // open
10 #include <sys/stat.h> // mkfifo
11 #include <boost/thread.hpp>
12 #include <cstdlib> // exit
13 #include <ctime>
14 #include <map>
15 #include <string>
16 
17 namespace artdaq {
24 class ProcFileMetric final : public MetricPlugin
25 {
26 private:
27  std::string pipe_;
28  std::unordered_map<std::string, std::string> value_map_;
29  bool stopped_;
30  boost::thread thread_;
31 
32  ProcFileMetric(const ProcFileMetric&) = delete;
33  ProcFileMetric(ProcFileMetric&&) = delete;
34  ProcFileMetric& operator=(const ProcFileMetric&) = delete;
35  ProcFileMetric& operator=(ProcFileMetric&&) = delete;
36 
37 public:
50  explicit ProcFileMetric(fhicl::ParameterSet const& config, std::string const& app_name, std::string const& metric_name)
51  : MetricPlugin(config, app_name, metric_name)
52  , pipe_(pset.get<std::string>("pipe", "/tmp/eventQueueStat"))
53  , stopped_(true)
54  {
55  METLOG(TLVL_TRACE) << "ProcFileMetric ctor";
56  auto names = pset.get<std::vector<std::string>>("names", std::vector<std::string>());
57 
58  for (const auto& name : names)
59  {
60  value_map_[name] = "";
61  }
62 
63  int sts = mkfifo(pipe_.c_str(), 0777);
64  if (sts != 0) { perror("ProcFileMetric mkfifo"); }
65  METLOG(10) << "ProcFileMetric mkfifo()" << pipe_ << " sts=" << sts;
66  startMetrics();
67  }
68 
72  ~ProcFileMetric() override
73  {
74  METLOG(11) << "~ProcFileMetric";
75  stopMetrics();
76  }
77 
82  std::string getLibName() const override { return "procFile"; }
83 
89  void sendMetric_(const std::string& name, const std::string& value, const std::string& /*unit*/, const std::chrono::system_clock::time_point& /*time*/) override
90  {
91  if (value_map_.count(name) != 0u)
92  {
93  METLOG(12) << "sendMetric_ setting value=" << value;
94  value_map_[name] = value;
95  }
96  }
97 
105  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
106  {
107  sendMetric_(name, std::to_string(value), unit, time);
108  }
109 
117  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
118  {
119  sendMetric_(name, std::to_string(value), unit, time);
120  }
121 
129  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
130  {
131  sendMetric_(name, std::to_string(value), unit, time);
132  }
133 
141  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
142  {
143  sendMetric_(name, std::to_string(value), unit, time);
144  }
145 
149  void startMetrics_() override
150  {
151  if (stopped_)
152  {
153  // start thread
154  stopped_ = false;
155  boost::thread::attributes attrs;
156  attrs.set_stack_size(4096 * 2000); // 8000 KB
157  try
158  {
159  thread_ = boost::thread(attrs, boost::bind(&ProcFileMetric::writePipe, this));
160  }
161  catch (boost::exception const& e)
162  {
163  TLOG(TLVL_ERROR) << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e);
164  std::cerr << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e) << std::endl;
165  exit(4);
166  }
167  }
168  }
169 
173  void stopMetrics_() override
174  {
175  if (!stopped_)
176  {
177  stopped_ = true;
178  // do read on pipe to make sure writePipe is not blocking on open
179  METLOG(11) << "stopMetrics_ before open " << pipe_;
180  int fd = open(pipe_.c_str(), O_RDONLY | O_NONBLOCK);
181  if (fd == -1)
182  {
183  perror("stopMetrics_ open(\"r\")");
184  exit(1);
185  }
186  METLOG(10) << "stopMetrics_ between open and unlink" << pipe_ << " fd=" << fd;
187  unlink(pipe_.c_str());
188  METLOG(11) << "stopMetrics_ unlinked " << pipe_;
189 #if 0
190  char buf[256];
191  read(fd, buf, sizeof(buf));
192 #endif
193  usleep(10000);
194  close(fd);
195  METLOG(11) << "stopMetrics_ after close " << pipe_;
196  if (thread_.joinable())
197  {
198  thread_.join();
199  }
200  }
201  }
202 
206  void writePipe()
207  {
208  while (!stopped_)
209  {
210  METLOG(11) << "writePipe before open";
211  int fd = open(pipe_.c_str(), O_WRONLY);
212  std::string str;
213  for (const auto& value : value_map_)
214  {
215  METLOG(10) << "writePipe open fd=" << fd << " name=" << value.first << " value=" << value.second; // can't have args b/c name may have %
216  str += value.first + ": " + value.second + "\n";
217  //snprintf(buf, sizeof(buf), "%s: %lu\n", value.first.c_str(), value.second);
218  }
219  int sts = write(fd, str.c_str(), str.size());
220  METLOG(11) << "writePipe write complete sts=" << sts;
221  close(fd);
222  METLOG(11) << "writePipe after close -- about to usleep";
223  usleep(400000); // must wait to make sure other end closes
224  }
225  }
226 };
227 } //End namespace artdaq
228 
229 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...