artdaq_utilities  v1_02_02
 All Classes
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 <iostream>
12 #include <ctime>
13 #include <string>
14 #include <algorithm>
15 #include <boost/asio.hpp>
16 #include <chrono>
17 
18 using boost::asio::ip::tcp;
19 
20 namespace artdaq
21 {
23  {
24  private:
25  std::string host_;
26  int port_;
27  std::string namespace_;
28  boost::asio::io_service io_service_;
29  tcp::socket socket_;
30  bool stopped_;
31  int errorCount_;
32  std::chrono::steady_clock::time_point waitStart_;
33  public:
34  GraphiteMetric(fhicl::ParameterSet config) : MetricPlugin(config)
35  , host_(pset.get<std::string>("host", "localhost"))
36  , port_(pset.get<int>("port", 2003))
37  , namespace_(pset.get<std::string>("namespace", "artdaq."))
38  , io_service_()
39  , socket_(io_service_)
40  , stopped_(true)
41  , errorCount_(0)
42  {
43  startMetrics();
44  }
45 
46  ~GraphiteMetric() { stopMetrics(); }
47  virtual std::string getLibName() const { return "graphite"; }
48 
49  virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit)
50  {
51  if (!stopped_)
52  {
53  std::string unitWarn = unit;
54  const std::time_t result = std::time(0);
55  boost::asio::streambuf data;
56  std::string nameTemp(name);
57  std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
58  std::ostream out(&data);
59  out << namespace_ << nameTemp << " "
60  << value << " "
61  << result << std::endl;
62 
63  boost::system::error_code error;
64  boost::asio::write(socket_, data, error);
65  if (error)
66  {
67  errorCount_++;
68  reconnect_();
69  }
70  }
71  }
72 
73  virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit)
74  {
75  sendMetric(name, std::to_string(value), unit);
76  }
77 
78  virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit)
79  {
80  sendMetric(name, std::to_string(value), unit);
81  }
82 
83  virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit)
84  {
85  sendMetric(name, std::to_string(value), unit);
86  }
87 
88  virtual void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit)
89  {
90  sendMetric(name, std::to_string(value), unit);
91  }
92 
93  virtual void startMetrics_()
94  {
95  if (stopped_)
96  {
97  reconnect_();
98  stopped_ = false;
99  }
100  }
101 
102  virtual void stopMetrics_()
103  {
104  if (!stopped_)
105  {
106  socket_.shutdown(boost::asio::socket_base::shutdown_send);
107  socket_.close();
108  stopped_ = true;
109  }
110  }
111 
112  void reconnect_()
113  {
114  if (errorCount_ < 5)
115  {
116  boost::system::error_code error;
117  tcp::resolver resolver(io_service_);
118  tcp::resolver::query query(host_, std::to_string(port_));
119  boost::asio::connect(socket_, resolver.resolve(query), error);
120  if (!error) { errorCount_ = 0; }
121  else { mf::LogWarning("GraphiteMetric") << "Error reconnecting socket, attempt #" << errorCount_; }
122  waitStart_ = std::chrono::steady_clock::now();
123  }
124  else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5)//Seconds
125  {
126  errorCount_ = 0;
127  }
128  }
129  };
130 } //End namespace artdaq
131 
132 DEFINE_ARTDAQ_METRIC(artdaq::GraphiteMetric)