00001
00002
00003
00004
00005
00006
00007 #include "artdaq-utilities/Plugins/MetricMacros.hh"
00008 #include "fhiclcpp/ParameterSet.h"
00009 #include "messagefacility/MessageLogger/MessageLogger.h"
00010
00011 #include <iostream>
00012 #include <ctime>
00013 #include <string>
00014 #include <algorithm>
00015 #include <boost/asio.hpp>
00016 #include <chrono>
00017
00018 using boost::asio::ip::tcp;
00019
00020 namespace artdaq
00021 {
00032 class GraphiteMetric : public MetricPlugin
00033 {
00034 private:
00035 std::string host_;
00036 int port_;
00037 std::string namespace_;
00038 boost::asio::io_service io_service_;
00039 tcp::socket socket_;
00040 bool stopped_;
00041 int errorCount_;
00042 std::chrono::steady_clock::time_point waitStart_;
00043 public:
00055 explicit GraphiteMetric(fhicl::ParameterSet config) : MetricPlugin(config)
00056 , host_(pset.get<std::string>("host", "localhost"))
00057 , port_(pset.get<int>("port", 2003))
00058 , namespace_(pset.get<std::string>("namespace", "artdaq."))
00059 , io_service_()
00060 , socket_(io_service_)
00061 , stopped_(true)
00062 , errorCount_(0)
00063 {
00064 startMetrics();
00065 }
00066
00070 virtual ~GraphiteMetric() { stopMetrics(); }
00071
00076 std::string getLibName() const override { return "graphite"; }
00077
00083 void sendMetric_(const std::string& name, const std::string& value, const std::string&) override
00084 {
00085 if (!stopped_)
00086 {
00087 const auto result = std::time(0);
00088 boost::asio::streambuf data;
00089 auto nameTemp(name);
00090 std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
00091 std::ostream out(&data);
00092 out << namespace_ << nameTemp << " "
00093 << value << " "
00094 << result << std::endl;
00095
00096 boost::system::error_code error;
00097 boost::asio::write(socket_, data, error);
00098 if (error)
00099 {
00100 errorCount_++;
00101 reconnect_();
00102 }
00103 }
00104 }
00105
00112 void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
00113 {
00114 sendMetric(name, std::to_string(value), unit);
00115 }
00116
00123 void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
00124 {
00125 sendMetric(name, std::to_string(value), unit);
00126 }
00127
00134 void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
00135 {
00136 sendMetric(name, std::to_string(value), unit);
00137 }
00138
00145 void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
00146 {
00147 sendMetric(name, std::to_string(value), unit);
00148 }
00149
00153 void startMetrics_() override
00154 {
00155 if (stopped_)
00156 {
00157 reconnect_();
00158 stopped_ = false;
00159 }
00160 }
00161
00165 void stopMetrics_() override
00166 {
00167 if (!stopped_)
00168 {
00169 socket_.shutdown(boost::asio::socket_base::shutdown_send);
00170 socket_.close();
00171 stopped_ = true;
00172 }
00173 }
00174
00175 private:
00179 void reconnect_()
00180 {
00181 if (errorCount_ < 5)
00182 {
00183 boost::system::error_code error;
00184 tcp::resolver resolver(io_service_);
00185 tcp::resolver::query query(host_, std::to_string(port_));
00186 boost::asio::connect(socket_, resolver.resolve(query), error);
00187 if (!error) { errorCount_ = 0; }
00188 else { mf::LogWarning("GraphiteMetric") << "Error reconnecting socket, attempt #" << errorCount_; }
00189 waitStart_ = std::chrono::steady_clock::now();
00190 }
00191 else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5)
00192 {
00193 errorCount_ = 0;
00194 }
00195 }
00196 };
00197 }
00198
00199 DEFINE_ARTDAQ_METRIC(artdaq::GraphiteMetric)