artdaq_utilities  v1_07_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 "TRACE/tracemf.h" // order matters -- trace.h (no "mf") is nested from MetricMacros.hh
8 #define TRACE_NAME (app_name_ + "_graphite_metric").c_str()
9 
10 #include "artdaq-utilities/Plugins/MetricMacros.hh"
11 #include "fhiclcpp/ParameterSet.h"
12 #include "messagefacility/MessageLogger/MessageLogger.h"
13 
14 #include <algorithm>
15 #include <boost/asio.hpp>
16 #include <chrono>
17 #include <ctime>
18 #include <iostream>
19 #include <string>
20 
21 using boost::asio::ip::tcp;
22 
23 namespace artdaq {
34 class GraphiteMetric final : public MetricPlugin
35 {
36 private:
37  std::string host_;
38  int port_;
39  std::string namespace_;
40  boost::asio::io_service io_service_;
41  tcp::socket socket_;
42  bool stopped_;
43  int errorCount_;
44  std::chrono::steady_clock::time_point waitStart_;
45 
46 public:
60  explicit GraphiteMetric(fhicl::ParameterSet const& config, std::string const& app_name, std::string const& metric_name)
61  : MetricPlugin(config, app_name, metric_name)
62  , host_(pset.get<std::string>("host", "localhost"))
63  , port_(pset.get<int>("port", 2003))
64  , namespace_(pset.get<std::string>("namespace", "artdaq."))
65  , io_service_()
66  , socket_(io_service_)
67  , stopped_(true)
68  , errorCount_(0)
69  {
70  METLOG(TLVL_TRACE) << "GraphiteMetric ctor";
71  startMetrics();
72  }
73 
77  ~GraphiteMetric() override { stopMetrics(); }
78 
83  std::string getLibName() const override { return "graphite"; }
84 
91  void sendMetric_(const std::string& name, const std::string& value, const std::string& /*unit*/, const std::chrono::system_clock::time_point& time) override
92  {
93  if (!stopped_)
94  {
95  boost::asio::streambuf data;
96  auto nameTemp(name);
97  std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
98  std::ostream out(&data);
99  out << namespace_ << nameTemp << " "
100  << value << " "
101  << std::chrono::system_clock::to_time_t(time) << std::endl;
102 
103  boost::system::error_code error;
104  boost::asio::write(socket_, data, error);
105  if (error)
106  {
107  errorCount_++;
108  reconnect_();
109  }
110  }
111  }
112 
120  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
121  {
122  sendMetric_(name, std::to_string(value), unit, time);
123  }
124 
132  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
133  {
134  sendMetric_(name, std::to_string(value), unit, time);
135  }
136 
144  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
145  {
146  sendMetric_(name, std::to_string(value), unit, time);
147  }
148 
156  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
157  {
158  sendMetric_(name, std::to_string(value), unit, time);
159  }
160 
164  void startMetrics_() override
165  {
166  if (stopped_)
167  {
168  reconnect_();
169  stopped_ = false;
170  }
171  }
172 
176  void stopMetrics_() override
177  {
178  if (!stopped_)
179  {
180  try
181  {
182  socket_.shutdown(boost::asio::socket_base::shutdown_send);
183  socket_.close();
184  stopped_ = true;
185  }
186  catch (boost::system::system_error& err)
187  {
188  METLOG(TLVL_WARNING) << "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() << "\"";
189  }
190  catch (...)
191  {
192  METLOG(TLVL_WARNING) << "In destructor of GraphiteMetric instance associated with " << host_ << ":" << port_ << ", an *unknown* exception was thrown out of a call to stopMetrics() and caught!";
193  }
194  }
195  }
196 
197 private:
198  GraphiteMetric(const GraphiteMetric&) = delete;
199  GraphiteMetric(GraphiteMetric&&) = delete;
200  GraphiteMetric& operator=(const GraphiteMetric&) = delete;
201  GraphiteMetric& operator=(GraphiteMetric&&) = delete;
202 
206  void reconnect_()
207  {
208  if (errorCount_ < 5)
209  {
210  boost::system::error_code error;
211  tcp::resolver resolver(io_service_);
212  tcp::resolver::query query(host_, std::to_string(port_));
213  boost::asio::connect(socket_, resolver.resolve(query), error);
214  if (!error) { errorCount_ = 0; }
215  else
216  {
217  METLOG(TLVL_WARNING) << "Error reconnecting socket, attempt #" << errorCount_;
218  }
219  waitStart_ = std::chrono::steady_clock::now();
220  }
221  else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5) //Seconds
222  {
223  errorCount_ = 0;
224  }
225  }
226 };
227 } //End namespace artdaq
228 
229 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:41
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, std::string const &metric_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.