artdaq_utilities  v1_04_10
procFile_metric.cc
1 
2 #include "artdaq-utilities/Plugins/MetricMacros.hh"
3 #include "fhiclcpp/ParameterSet.h"
4 #include "messagefacility/MessageLogger/MessageLogger.h"
5 #define TRACE_NAME "procFile_metric"
6 #include "trace.h"
7 
8 #include <sys/stat.h> // mkfifo
9 #include <fcntl.h> // open
10 #include <stdlib.h> // exit
11 #include <ctime>
12 #include <string>
13 #include <boost/thread.hpp>
14 #include <map>
15 
16 namespace artdaq
17 {
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  public:
43  explicit ProcFileMetric(fhicl::ParameterSet const& config, std::string const& app_name) : MetricPlugin(config, app_name)
44  , pipe_(pset.get<std::string>("pipe", "/tmp/eventQueueStat"))
45  , value_map_()
46  , stopped_(true)
47  {
48  auto names = pset.get<std::vector<std::string>>("names", std::vector<std::string>());
49 
50  for (auto name : names)
51  {
52  value_map_[name] = "";
53  }
54 
55  int sts = mkfifo(pipe_.c_str(), 0777);
56  if (sts != 0) { perror("ProcFileMetric mkfifo"); }
57  TLOG(10) << "ProcFileMetric mkfifo()" << pipe_ << " sts=" << sts;
58  startMetrics();
59  }
60 
65  TLOG(11) << "~ProcFileMetric" ;
66  stopMetrics();
67  }
68 
73  std::string getLibName() const override { return "procFile"; }
74 
80  void sendMetric_(const std::string& name, const std::string& value, const std::string&) override {
81  if (value_map_.count(name)) {
82  TLOG(12) << "sendMetric_ setting value=" << value;
83  value_map_[name] = value;
84  }
85  }
86 
93  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override {
94  sendMetric_(name, std::to_string(value), unit);
95  }
96 
103  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override {
104  sendMetric_(name, std::to_string(value), unit);
105  }
106 
113  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override {
114  sendMetric_(name, std::to_string(value), unit);
115  }
116 
123  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
124  {
125  sendMetric_(name, std::to_string(value), unit);
126  }
127 
131  void startMetrics_() override
132  {
133  if (stopped_)
134  {
135  // start thread
136  stopped_ = false;
137  boost::thread::attributes attrs;
138  attrs.set_stack_size(4096 * 2000); // 8000 KB
139  try {
140  thread_ = boost::thread(attrs, boost::bind(&ProcFileMetric::writePipe, this));
141  }
142  catch (boost::exception const& e)
143  {
144  std::cerr << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e) << std::endl;
145  exit(4);
146  }
147  }
148  }
149 
153  void stopMetrics_() override
154  {
155  if (!stopped_)
156  {
157  stopped_ = true;
158  // do read on pipe to make sure writePipe is not blocking on open
159  TLOG(11) << "stopMetrics_ before open " << pipe_;
160  int fd = open(pipe_.c_str(), O_RDONLY | O_NONBLOCK);
161  if (fd == -1) { perror("stopMetrics_ open(\"r\")"); exit(1); }
162  TLOG(10) << "stopMetrics_ between open and unlink" << pipe_ << " fd=" << fd;
163  unlink(pipe_.c_str());
164  TLOG(11) << "stopMetrics_ unlinked " << pipe_;
165 # if 0
166  char buf[256];
167  read(fd, buf, sizeof(buf));
168 # endif
169  usleep(10000);
170  close(fd);
171  TLOG(11) << "stopMetrics_ after close " << pipe_;
172  if (thread_.joinable()) thread_.join();
173  }
174  }
175 
179  void writePipe()
180  {
181  while (!stopped_)
182  {
183  TLOG(11) << "writePipe before open";
184  int fd = open(pipe_.c_str(), O_WRONLY);
185  std::string str;
186  for (auto value : value_map_) {
187  TLOG(10) << "writePipe open fd=" << fd << " name=" << value.first << " value=" << value.second; // can't have args b/c name may have %
188  str += value.first + ": " + value.second + "\n";
189  //snprintf(buf, sizeof(buf), "%s: %lu\n", value.first.c_str(), value.second);
190  }
191  int sts = write(fd, str.c_str(), str.size());
192  TLOG(11) << "writePipe write complete sts=" << sts;
193  close(fd);
194  TLOG(11) << "writePipe after close -- about to usleep";
195  usleep(400000); // must wait to make sure other end closes
196  }
197 
198  }
199  };
200 } //End namespace artdaq
201 
202 DEFINE_ARTDAQ_METRIC(artdaq::ProcFileMetric)
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 sendMetric_(const std::string &name, const double &value, const std::string &unit) override
Set the value to be written to the pipe when it is opened by a reader.
void startMetrics_() override
Start the metric-sending thread.
ProcFileMetric(fhicl::ParameterSet const &config, std::string const &app_name)
ProcFileMetric Constructor.
void writePipe()
Wait for the pipe to be opened and then write the current value to it.
void sendMetric_(const std::string &name, const int &value, const std::string &unit) override
Set the value to be written to the pipe when it is opened by a reader.
void sendMetric_(const std::string &name, const unsigned long int &value, const std::string &unit) override
Set the value to be written to the pipe when it is opened by a reader.
void sendMetric_(const std::string &name, const std::string &value, const std::string &) override
Set the value to be written to the pipe when it is opened by a reader.
~ProcFileMetric()
ProcFileMetric Destructor.
A MetricPlugin which writes a long unsigned int metric with a given name to a given pipe...
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Set the value to be written to the pipe when it is opened by a reader.