artdaq_utilities  v1_06_01
graphite_metric.cc
1 // graphite_metric.cc: Graphite Metric Plugin
2 // Author: Eric Flumerfelt
3 // Last Modified: 11/13/2014
4 //
5 // An implementation of the MetricPlugin for Graphite
6 
7 #include "artdaq-utilities/Plugins/MetricMacros.hh"
8 #include "fhiclcpp/ParameterSet.h"
9 #include "messagefacility/MessageLogger/MessageLogger.h"
10 
11 #include <algorithm>
12 #include <boost/asio.hpp>
13 #include <chrono>
14 #include <ctime>
15 #include <iostream>
16 #include <string>
17 
18 using boost::asio::ip::tcp;
19 
20 namespace artdaq {
31 class GraphiteMetric final : public MetricPlugin
32 {
33 private:
34  std::string host_;
35  int port_;
36  std::string namespace_;
37  boost::asio::io_service io_service_;
38  tcp::socket socket_;
39  bool stopped_;
40  int errorCount_;
41  std::chrono::steady_clock::time_point waitStart_;
42 
43 public:
56  explicit GraphiteMetric(fhicl::ParameterSet const& config, std::string const& app_name)
57  : MetricPlugin(config, app_name)
58  , host_(pset.get<std::string>("host", "localhost"))
59  , port_(pset.get<int>("port", 2003))
60  , namespace_(pset.get<std::string>("namespace", "artdaq."))
61  , io_service_()
62  , socket_(io_service_)
63  , stopped_(true)
64  , errorCount_(0)
65  {
66  startMetrics();
67  }
68 
72  ~GraphiteMetric() override { stopMetrics(); }
73 
78  std::string getLibName() const override { return "graphite"; }
79 
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 (!stopped_)
89  {
90  boost::asio::streambuf data;
91  auto nameTemp(name);
92  std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
93  std::ostream out(&data);
94  out << namespace_ << nameTemp << " "
95  << value << " "
96  << std::chrono::system_clock::to_time_t(time) << std::endl;
97 
98  boost::system::error_code error;
99  boost::asio::write(socket_, data, error);
100  if (error)
101  {
102  errorCount_++;
103  reconnect_();
104  }
105  }
106  }
107 
115  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
116  {
117  sendMetric_(name, std::to_string(value), unit, time);
118  }
119 
127  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
128  {
129  sendMetric_(name, std::to_string(value), unit, time);
130  }
131 
139  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
140  {
141  sendMetric_(name, std::to_string(value), unit, time);
142  }
143 
151  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
152  {
153  sendMetric_(name, std::to_string(value), unit, time);
154  }
155 
159  void startMetrics_() override
160  {
161  if (stopped_)
162  {
163  reconnect_();
164  stopped_ = false;
165  }
166  }
167 
171  void stopMetrics_() override
172  {
173  if (!stopped_)
174  {
175  try
176  {
177  socket_.shutdown(boost::asio::socket_base::shutdown_send);
178  socket_.close();
179  stopped_ = true;
180  }
181  catch (boost::system::system_error& err)
182  {
183  mf::LogWarning("GraphiteMetric") << "In destructor of GraphiteMetric instance associated with " << host_ << ":" << port_ << ", the following boost::system::system_error exception was thrown out of a call to stopMetrics() and caught: " << err.code() << ", \"" << err.what() << "\"";
184  }
185  catch (...)
186  {
187  mf::LogWarning("GraphiteMetric") << "In destructor of GraphiteMetric instance associated with " << host_ << ":" << port_ << ", an *unknown* exception was thrown out of a call to stopMetrics() and caught!";
188  }
189  }
190  }
191 
192 private:
193  GraphiteMetric(const GraphiteMetric&) = delete;
194  GraphiteMetric(GraphiteMetric&&) = delete;
195  GraphiteMetric& operator=(const GraphiteMetric&) = delete;
196  GraphiteMetric& operator=(GraphiteMetric&&) = delete;
197 
201  void reconnect_()
202  {
203  if (errorCount_ < 5)
204  {
205  boost::system::error_code error;
206  tcp::resolver resolver(io_service_);
207  tcp::resolver::query query(host_, std::to_string(port_));
208  boost::asio::connect(socket_, resolver.resolve(query), error);
209  if (!error) { errorCount_ = 0; }
210  else
211  {
212  mf::LogWarning("GraphiteMetric") << "Error reconnecting socket, attempt #" << errorCount_;
213  }
214  waitStart_ = std::chrono::steady_clock::now();
215  }
216  else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5) //Seconds
217  {
218  errorCount_ = 0;
219  }
220  }
221 };
222 } //End namespace artdaq
223 
224 DEFINE_ARTDAQ_METRIC(artdaq::GraphiteMetric)
void sendMetric_(const std::string &name, const float &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Send a metric to Graphite.
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.
fhicl::ParameterSet pset
The ParameterSet used to configure the MetricPlugin.
std::string getLibName() const override
Get the library name for the Graphite metric.
void startMetrics_() override
Perform startup actions. For Graphite, this means reconnecting the socket.
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
Send a metric to Graphite.
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Send a metric to Graphite.
void sendMetric_(const std::string &name, const std::string &value, const std::string &, const std::chrono::system_clock::time_point &time) override
Send a metric to Graphite.
GraphiteMetric(fhicl::ParameterSet const &config, std::string const &app_name)
GraphiteMetric Constructor.
void stopMetrics_() override
Perform shutdown actions. This shuts down the socket and closes it.
~GraphiteMetric() override
GraphiteMetric Destructor. Calls stopMetrics()
Send a metric to Graphite.
void sendMetric_(const std::string &name, const double &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Send a metric to Graphite.