artdaq_epics_plugin  v1_05_01
epics_metric.cc
1 // epics_metric.cc: Epics Metric Plugin
2 // Author: Eric Flumerfelt
3 // Last Modified: 09/25/2015
4 //
5 // An implementation of the MetricPlugin interface for Epics/ChannelAccess
6 
7 #ifndef __EPICS_METRIC__
8 #define __EPICS_METRIC__ 1
9 
10 #include "TRACE/tracemf.h" // order matters -- trace.h (no "mf") is nested from MetricMacros.hh
11 #define TRACE_NAME (app_name_ + "_epics_metric").c_str()
12 
13 #include <unordered_map>
14 #include <utility>
15 #include "artdaq-utilities/Plugins/MetricMacros.hh"
16 #include "messagefacility/MessageLogger/MessageLogger.h"
17 #undef STATIC_ASSERT
18 
19 #ifdef __clang__
20 #pragma clang diagnostic push
21 #pragma clang diagnostic ignored "-Wunused-parameter"
22 #elif __GNUC__ > 9
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wdeprecated-copy"
25 #endif
26 #include <cadef.h>
27 #ifdef __clang__
28 #pragma clang diagnostic pop
29 #elif __GNUC__ > 9
30 #pragma GCC diagnostic pop
31 #endif
32 
36 namespace artdaq {
40 class EpicsMetric : public MetricPlugin
41 {
42 private:
43  std::string prefix_;
44  std::unordered_map<std::string, chid> channels_;
45 
46  bool checkChannel_(const std::string& name)
47  {
48  if (channels_.count(name) == 0u)
49  {
50  chid channel;
51  ca_search(name.c_str(), &channel);
52  auto sts = ca_pend_io(5.0);
53  if (sts != ECA_NORMAL)
54  {
55  SEVCHK(ca_clear_channel(channel), NULL);
56  METLOG(TLVL_WARNING) << "Channel \"" << name << "\" not found!";
57  channels_[name] = nullptr;
58  return false;
59  }
60  channels_[name] = channel;
61  return true;
62  }
63  return channels_[name] != nullptr;
64  }
65 
66  std::string parseChannelName_(std::string prefix_, std::string name)
67  {
68  std::string caName = std::move(name);
69  const std::string& caPrefix_ = std::move(prefix_);
70 
71  while (caName.find(' ') != std::string::npos)
72  {
73  caName = caName.replace(caName.find(' '), 1, "_");
74  }
75  while (caName.find('.') != std::string::npos)
76  {
77  caName = caName.replace(caName.find('.'), 1, ":");
78  }
79  while (caName.find('/') != std::string::npos)
80  {
81  caName = caName.replace(caName.find('/'), 1, "_");
82  }
83  while (caName.find("_%") != std::string::npos)
84  {
85  caName = caName.replace(caName.find("_%"), 2, "");
86  }
87  caName = caPrefix_ + ":" + caName;
88 
89  TLOG(TLVL_DEBUG + 32) << "Channel name is: \"" << caName << "\"";
90  return caName;
91  }
92 
93  EpicsMetric(EpicsMetric const&) = delete;
94  EpicsMetric(EpicsMetric&&) = delete;
95  EpicsMetric& operator=(EpicsMetric const&) = delete;
96  EpicsMetric& operator=(EpicsMetric&&) = delete;
97 
98 public:
105  explicit EpicsMetric(fhicl::ParameterSet const& pset, std::string const& app_name, std::string const& metric_name)
106  : MetricPlugin(pset, app_name, metric_name), prefix_(pset.get<std::string>("channel_name_prefix", "artdaq")), channels_() {}
107 
108  ~EpicsMetric() override { MetricPlugin::stopMetrics(); }
109 
114  std::string getLibName() const override { return "epics"; }
115 
119  void stopMetrics_() override
120  {
121  for (const auto& channel : channels_)
122  {
123  if (channel.second != 0)
124  {
125  SEVCHK(ca_clear_channel(channel.second), NULL);
126  }
127  }
128  channels_.clear();
129  }
130 
134  void startMetrics_() override {}
135 
146  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit, const std::chrono::system_clock::time_point&) override
147  {
148  //std::string caName = prefix_ + ":" + name;
149  std::string caName = parseChannelName_(prefix_, name);
150 
151  std::string tmpValue = value + " " + unit;
152 
153  if (checkChannel_(caName))
154  {
155  // DBR_STRING, 40 characters
156  if (tmpValue.size() > 40)
157  {
158  tmpValue = tmpValue.erase(40);
159  }
160  SEVCHK(ca_put(DBR_STRING, channels_[caName], tmpValue.c_str()), NULL);
161  SEVCHK(ca_flush_io(), NULL);
162  }
163  }
164 
175  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point&) override
176  {
177  // DBR_LONG
178  //std::string caName = prefix_ + ":" + name;
179  std::string caName = parseChannelName_(prefix_, name);
180 
181  if (!unit.empty())
182  {
183  METLOG(TLVL_DEBUG + 32) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
184  }
185 
186  if (checkChannel_(caName))
187  {
188  auto val = static_cast<dbr_long_t>(value);
189  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
190  SEVCHK(ca_flush_io(), NULL);
191  }
192  }
193 
204  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point&) override
205  {
206  // DBR_DOUBLE
207  //std::string caName = prefix_ + ":" + name;
208  std::string caName = parseChannelName_(prefix_, name);
209 
210  if (!unit.empty())
211  {
212  METLOG(TLVL_DEBUG + 32) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
213  }
214 
215  if (checkChannel_(caName))
216  {
217  auto val = static_cast<dbr_double_t>(value);
218  SEVCHK(ca_put(DBR_DOUBLE, channels_[caName], &val), NULL);
219  SEVCHK(ca_flush_io(), NULL);
220  }
221  }
222 
233  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point&) override
234  {
235  // DBR_FLOAT
236  //std::string caName = prefix_ + ":" + name;
237  std::string caName = parseChannelName_(prefix_, name);
238 
239  if (!unit.empty())
240  {
241  METLOG(TLVL_DEBUG + 32) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
242  }
243 
244  if (checkChannel_(caName))
245  {
246  auto val = static_cast<dbr_float_t>(value);
247  SEVCHK(ca_put(DBR_FLOAT, channels_[caName], &val), NULL);
248  SEVCHK(ca_flush_io(), NULL);
249  }
250  }
251 
262  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point&) override
263  {
264  // DBR_LONG, only unsigned type is only 16 bits, use widest integral field
265  //std::string caName = prefix_ + ":" + name;
266  std::string caName = parseChannelName_(prefix_, name);
267 
268  if (!unit.empty())
269  {
270  METLOG(TLVL_DEBUG + 32) << "Not sure if I can send ChannelAccess Units...configure in db instead.";
271  }
272 
273  if (checkChannel_(caName))
274  {
275  auto val = static_cast<dbr_ulong_t>(value);
276  SEVCHK(ca_put(DBR_LONG, channels_[caName], &val), NULL);
277  SEVCHK(ca_flush_io(), NULL);
278  }
279  }
280 };
281 } // End namespace artdaq
282 
283 DEFINE_ARTDAQ_METRIC(artdaq::EpicsMetric)
284 
285 #endif // End ifndef __EPICS_METRIC__
An instance of the MetricPlugin class that sends metric data using the Channel Access protocol from E...
Definition: epics_metric.cc:40
void stopMetrics_() override
Clears the registered ChannelAccess channels.
void startMetrics_() override
No initialization is needed to start sending metrics.
std::string getLibName() const override
Gets the unique library name of this plugin.
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a string metric data point to ChannelAccess.
void sendMetric_(const std::string &name, const float &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a float metric data point to ChannelAccess.
EpicsMetric(fhicl::ParameterSet const &pset, std::string const &app_name, std::string const &metric_name)
Construct an instance of the EpicsMetric plugin.
void sendMetric_(const std::string &name, const double &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send a double metric data point to ChannelAccess.
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send an unsigned integer metric data point to ChannelAccess.
void sendMetric_(const std::string &name, const int &value, const std::string &unit, const std::chrono::system_clock::time_point &) override
Send an integer metric data point to ChannelAccess.