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 {
00022 class GraphiteMetric : public MetricPlugin
00023 {
00024 private:
00025 std::string host_;
00026 int port_;
00027 std::string namespace_;
00028 boost::asio::io_service io_service_;
00029 tcp::socket socket_;
00030 bool stopped_;
00031 int errorCount_;
00032 std::chrono::steady_clock::time_point waitStart_;
00033 public:
00034 GraphiteMetric(fhicl::ParameterSet config) : MetricPlugin(config)
00035 , host_(pset.get<std::string>("host", "localhost"))
00036 , port_(pset.get<int>("port", 2003))
00037 , namespace_(pset.get<std::string>("namespace", "artdaq."))
00038 , io_service_()
00039 , socket_(io_service_)
00040 , stopped_(true)
00041 , errorCount_(0)
00042 {
00043 startMetrics();
00044 }
00045
00046 ~GraphiteMetric() { stopMetrics(); }
00047 virtual std::string getLibName() const { return "graphite"; }
00048
00049 virtual void sendMetric_(const std::string& name, const std::string& value, const std::string& unit)
00050 {
00051 if (!stopped_)
00052 {
00053 std::string unitWarn = unit;
00054 const std::time_t result = std::time(0);
00055 boost::asio::streambuf data;
00056 std::string nameTemp(name);
00057 std::replace(nameTemp.begin(), nameTemp.end(), ' ', '_');
00058 std::ostream out(&data);
00059 out << namespace_ << nameTemp << " "
00060 << value << " "
00061 << result << std::endl;
00062
00063 boost::system::error_code error;
00064 boost::asio::write(socket_, data, error);
00065 if (error)
00066 {
00067 errorCount_++;
00068 reconnect_();
00069 }
00070 }
00071 }
00072
00073 virtual void sendMetric_(const std::string& name, const int& value, const std::string& unit)
00074 {
00075 sendMetric(name, std::to_string(value), unit);
00076 }
00077
00078 virtual void sendMetric_(const std::string& name, const double& value, const std::string& unit)
00079 {
00080 sendMetric(name, std::to_string(value), unit);
00081 }
00082
00083 virtual void sendMetric_(const std::string& name, const float& value, const std::string& unit)
00084 {
00085 sendMetric(name, std::to_string(value), unit);
00086 }
00087
00088 virtual void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit)
00089 {
00090 sendMetric(name, std::to_string(value), unit);
00091 }
00092
00093 virtual void startMetrics_()
00094 {
00095 if (stopped_)
00096 {
00097 reconnect_();
00098 stopped_ = false;
00099 }
00100 }
00101
00102 virtual void stopMetrics_()
00103 {
00104 if (!stopped_)
00105 {
00106 socket_.shutdown(boost::asio::socket_base::shutdown_send);
00107 socket_.close();
00108 stopped_ = true;
00109 }
00110 }
00111
00112 void reconnect_()
00113 {
00114 if (errorCount_ < 5)
00115 {
00116 boost::system::error_code error;
00117 tcp::resolver resolver(io_service_);
00118 tcp::resolver::query query(host_, std::to_string(port_));
00119 boost::asio::connect(socket_, resolver.resolve(query), error);
00120 if (!error) { errorCount_ = 0; }
00121 else { mf::LogWarning("GraphiteMetric") << "Error reconnecting socket, attempt #" << errorCount_; }
00122 waitStart_ = std::chrono::steady_clock::now();
00123 }
00124 else if (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - waitStart_).count() >= 5)
00125 {
00126 errorCount_ = 0;
00127 }
00128 }
00129 };
00130 }
00131
00132 DEFINE_ARTDAQ_METRIC(artdaq::GraphiteMetric)