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:
00056 explicit GraphiteMetric(fhicl::ParameterSet const& config, std::string const& app_name) : MetricPlugin(config, app_name)
00057 , host_(pset.get<std::string>("host", "localhost"))
00058 , port_(pset.get<int>("port", 2003))
00059 , namespace_(pset.get<std::string>("namespace", "artdaq."))
00060 , io_service_()
00061 , socket_(io_service_)
00062 , stopped_(true)
00063 , errorCount_(0)
00064 {
00065 startMetrics();
00066 }
00067
00071 virtual ~GraphiteMetric() { stopMetrics(); }
00072
00077 std::string getLibName() const override { return "graphite"; }
00078
00084 void sendMetric_(const std::string& name, const std::string& value, const std::string&) override
00085 {
00086 if (!stopped_)
00087 {
00088 const auto result = std::time(0);
00089 boost::asio::streambuf data;
00090 auto nameTemp(name);
00091 std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
00092 std::ostream out(&data);
00093 out << namespace_ << nameTemp << " "
00094 << value << " "
00095 << result << std::endl;
00096
00097 boost::system::error_code error;
00098 boost::asio::write(socket_, data, error);
00099 if (error)
00100 {
00101 errorCount_++;
00102 reconnect_();
00103 }
00104 }
00105 }
00106
00113 void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
00114 {
00115 sendMetric_(name, std::to_string(value), unit);
00116 }
00117
00124 void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
00125 {
00126 sendMetric_(name, std::to_string(value), unit);
00127 }
00128
00135 void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
00136 {
00137 sendMetric_(name, std::to_string(value), unit);
00138 }
00139
00146 void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
00147 {
00148 sendMetric_(name, std::to_string(value), unit);
00149 }
00150
00154 void startMetrics_() override
00155 {
00156 if (stopped_)
00157 {
00158 reconnect_();
00159 stopped_ = false;
00160 }
00161 }
00162
00166 void stopMetrics_() override
00167 {
00168 if (!stopped_)
00169 {
00170 socket_.shutdown(boost::asio::socket_base::shutdown_send);
00171 socket_.close();
00172 stopped_ = true;
00173 }
00174 }
00175
00176 private:
00180 void reconnect_()
00181 {
00182 if (errorCount_ < 5)
00183 {
00184 boost::system::error_code error;
00185 tcp::resolver resolver(io_service_);
00186 tcp::resolver::query query(host_, std::to_string(port_));
00187 boost::asio::connect(socket_, resolver.resolve(query), error);
00188 if (!error) { errorCount_ = 0; }
00189 else { mf::LogWarning("GraphiteMetric") << "Error reconnecting socket, attempt #" << errorCount_; }
00190 waitStart_ = std::chrono::steady_clock::now();
00191 }
00192 else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5)
00193 {
00194 errorCount_ = 0;
00195 }
00196 }
00197 };
00198 }
00199
00200 DEFINE_ARTDAQ_METRIC(artdaq::GraphiteMetric)