artdaq_utilities  v1_05_11
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*/, const std::chrono::system_clock::time_point& /*time*/) 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 
102  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
103  {
104  sendMetric_(name, std::to_string(value), unit, time);
105  }
106 
114  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
115  {
116  sendMetric_(name, std::to_string(value), unit, time);
117  }
118 
126  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
127  {
128  sendMetric_(name, std::to_string(value), unit, time);
129  }
130 
138  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
139  {
140  sendMetric_(name, std::to_string(value), unit, time);
141  }
142 
146  void startMetrics_() override
147  {
148  if (stopped_)
149  {
150  // start thread
151  stopped_ = false;
152  boost::thread::attributes attrs;
153  attrs.set_stack_size(4096 * 2000); // 8000 KB
154  try
155  {
156  thread_ = boost::thread(attrs, boost::bind(&ProcFileMetric::writePipe, this));
157  }
158  catch (boost::exception const& e)
159  {
160  std::cerr << "Creating ProcFile Metric thread failed! e: " << boost::diagnostic_information(e) << std::endl;
161  exit(4);
162  }
163  }
164  }
165 
169  void stopMetrics_() override
170  {
171  if (!stopped_)
172  {
173  stopped_ = true;
174  // do read on pipe to make sure writePipe is not blocking on open
175  TLOG(11) << "stopMetrics_ before open " << pipe_;
176  int fd = open(pipe_.c_str(), O_RDONLY | O_NONBLOCK);
177  if (fd == -1)
178  {
179  perror("stopMetrics_ open(\"r\")");
180  exit(1);
181  }
182  TLOG(10) << "stopMetrics_ between open and unlink" << pipe_ << " fd=" << fd;
183  unlink(pipe_.c_str());
184  TLOG(11) << "stopMetrics_ unlinked " << pipe_;
185 #if 0
186  char buf[256];
187  read(fd, buf, sizeof(buf));
188 #endif
189  usleep(10000);
190  close(fd);
191  TLOG(11) << "stopMetrics_ after close " << pipe_;
192  if (thread_.joinable())
193  {
194  thread_.join();
195  }
196  }
197  }
198 
202  void writePipe()
203  {
204  while (!stopped_)
205  {
206  TLOG(11) << "writePipe before open";
207  int fd = open(pipe_.c_str(), O_WRONLY);
208  std::string str;
209  for (const auto& value : value_map_)
210  {
211  TLOG(10) << "writePipe open fd=" << fd << " name=" << value.first << " value=" << value.second; // can't have args b/c name may have %
212  str += value.first + ": " + value.second + "\n";
213  //snprintf(buf, sizeof(buf), "%s: %lu\n", value.first.c_str(), value.second);
214  }
215  int sts = write(fd, str.c_str(), str.size());
216  TLOG(11) << "writePipe write complete sts=" << sts;
217  close(fd);
218  TLOG(11) << "writePipe after close -- about to usleep";
219  usleep(400000); // must wait to make sure other end closes
220  }
221  }
222 };
223 } //End namespace artdaq
224 
225 DEFINE_ARTDAQ_METRIC(artdaq::ProcFileMetric)
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:37
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.
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.
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.
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...