artdaq_utilities  v1_05_07
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 <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:
48  explicit ProcFileMetric(fhicl::ParameterSet const& config, std::string const& app_name)
49  : MetricPlugin(config, app_name)
50  , pipe_(pset.get<std::string>("pipe", "/tmp/eventQueueStat"))
51  , stopped_(true)
52  {
53  auto names = pset.get<std::vector<std::string>>("names", std::vector<std::string>());
54 
55  for (const auto& name : names)
56  {
57  value_map_[name] = "";
58  }
59 
60  int sts = mkfifo(pipe_.c_str(), 0777);
61  if (sts != 0) { perror("ProcFileMetric mkfifo"); }
62  TLOG(10) << "ProcFileMetric mkfifo()" << pipe_ << " sts=" << sts;
63  startMetrics();
64  }
65 
69  ~ProcFileMetric() override
70  {
71  TLOG(11) << "~ProcFileMetric";
72  stopMetrics();
73  }
74 
79  std::string getLibName() const override { return "procFile"; }
80 
86  void sendMetric_(const std::string& name, const std::string& value, const std::string& /*unit*/) override
87  {
88  if (value_map_.count(name) != 0u)
89  {
90  TLOG(12) << "sendMetric_ setting value=" << value;
91  value_map_[name] = value;
92  }
93  }
94 
101  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
102  {
103  sendMetric_(name, std::to_string(value), unit);
104  }
105 
112  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
113  {
114  sendMetric_(name, std::to_string(value), unit);
115  }
116 
123  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
124  {
125  sendMetric_(name, std::to_string(value), unit);
126  }
127 
134  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit) override
135  {
136  sendMetric_(name, std::to_string(value), unit);
137  }
138 
142  void startMetrics_() override
143  {
144  if (stopped_)
145  {
146  // start thread
147  stopped_ = false;
148  boost::thread::attributes attrs;
149  attrs.set_stack_size(4096 * 2000); // 8000 KB
150  try
151  {
152  thread_ = boost::thread(attrs, boost::bind(&ProcFileMetric::writePipe, this));
153  }
154  catch (boost::exception const& e)
155  {
156  std::cerr << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e) << std::endl;
157  exit(4);
158  }
159  }
160  }
161 
165  void stopMetrics_() override
166  {
167  if (!stopped_)
168  {
169  stopped_ = true;
170  // do read on pipe to make sure writePipe is not blocking on open
171  TLOG(11) << "stopMetrics_ before open " << pipe_;
172  int fd = open(pipe_.c_str(), O_RDONLY | O_NONBLOCK);
173  if (fd == -1)
174  {
175  perror("stopMetrics_ open(\"r\")");
176  exit(1);
177  }
178  TLOG(10) << "stopMetrics_ between open and unlink" << pipe_ << " fd=" << fd;
179  unlink(pipe_.c_str());
180  TLOG(11) << "stopMetrics_ unlinked " << pipe_;
181 #if 0
182  char buf[256];
183  read(fd, buf, sizeof(buf));
184 #endif
185  usleep(10000);
186  close(fd);
187  TLOG(11) << "stopMetrics_ after close " << pipe_;
188  if (thread_.joinable())
189  {
190  thread_.join();
191  }
192  }
193  }
194 
198  void writePipe()
199  {
200  while (!stopped_)
201  {
202  TLOG(11) << "writePipe before open";
203  int fd = open(pipe_.c_str(), O_WRONLY);
204  std::string str;
205  for (const auto& value : value_map_)
206  {
207  TLOG(10) << "writePipe open fd=" << fd << " name=" << value.first << " value=" << value.second; // can't have args b/c name may have %
208  str += value.first + ": " + value.second + "\n";
209  //snprintf(buf, sizeof(buf), "%s: %lu\n", value.first.c_str(), value.second);
210  }
211  int sts = write(fd, str.c_str(), str.size());
212  TLOG(11) << "writePipe write complete sts=" << sts;
213  close(fd);
214  TLOG(11) << "writePipe after close -- about to usleep";
215  usleep(400000); // must wait to make sure other end closes
216  }
217  }
218 };
219 } //End namespace artdaq
220 
221 DEFINE_ARTDAQ_METRIC(artdaq::ProcFileMetric)
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit) override
Set the value to be written to the pipe when it is opened by a reader.
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:37
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 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 stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
~ProcFileMetric() override
ProcFileMetric Destructor.
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 std::string &value, const std::string &) 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...
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.