artdaq_utilities  v1_07_01
file_metric.cc
1 // FileMetric.h: File Metric Plugin
2 // Author: Eric Flumerfelt
3 // Last Modified: 11/06/2014
4 //
5 // An implementation of the MetricPlugin for Log Files
6 
7 #include "TRACE/tracemf.h" // order matters -- trace.h (no "mf") is nested from MetricMacros.hh
8 #define TRACE_NAME (app_name_ + "_file_metric").c_str()
9 
10 #include "artdaq-utilities/Plugins/MetricMacros.hh"
11 #include "fhiclcpp/ParameterSet.h"
12 #include "trace.h"
13 
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <boost/filesystem.hpp>
17 #include <ctime>
18 #include <fstream>
19 #include <iomanip>
20 #include <string>
21 namespace BFS = boost::filesystem;
22 
23 namespace artdaq {
27 class FileMetric final : public MetricPlugin
28 {
29 private:
30  std::string outputFile_;
31  bool file_name_is_absolute_path_;
32  std::string relative_env_var_;
33  bool uniquify_file_name_;
34  std::ofstream outputStream_;
35  std::ios_base::openmode mode_;
36  std::string timeformat_;
37  bool stopped_;
38 
39  std::ostream& getTime_(std::ostream& stream, const std::chrono::system_clock::time_point& time)
40  {
41  std::time_t tt = std::chrono::system_clock::to_time_t(time);
42 
43  struct std::tm* ptm = std::localtime(&tt);
44  if (!timeformat_.empty())
45  {
46  return stream << std::put_time(ptm, timeformat_.c_str()) << ": ";
47  }
48 
49  return stream;
50  }
51 
52  FileMetric(const FileMetric&) = delete;
53  FileMetric(FileMetric&&) = delete;
54  FileMetric& operator=(const FileMetric&) = delete;
55  FileMetric& operator=(FileMetric&&) = delete;
56 
57 public:
73  explicit FileMetric(fhicl::ParameterSet const& config, std::string const& app_name, std::string const& metric_name)
74  : MetricPlugin(config, app_name, metric_name)
75  , outputFile_(pset.get<std::string>("fileName", "FileMetric.out"))
76  , file_name_is_absolute_path_(pset.get<bool>("absolute_file_path", true))
77  , relative_env_var_(pset.get<std::string>("relative_directory_env_var", "ARTDAQ_LOG_ROOT"))
78  , uniquify_file_name_(pset.get<bool>("uniquify", false))
79  , timeformat_(pset.get<std::string>("time_format", "%c"))
80  , stopped_(true)
81  {
82  auto modeString = pset.get<std::string>("fileMode", "append");
83 
84  mode_ = std::ofstream::out | std::ofstream::app;
85  if (modeString == "Overwrite" || modeString == "Create" || modeString == "Write")
86  {
87  mode_ = std::ofstream::out | std::ofstream::trunc;
88  }
89 
90  METLOG(TLVL_TRACE) << "FileMetric ctor";
91 
92  if (uniquify_file_name_)
93  {
94  struct timespec ts;
95  clock_gettime(CLOCK_REALTIME, &ts);
96  std::string unique_id = std::to_string(ts.tv_sec) + "_" + std::to_string(getpid());
97  if (outputFile_.find("%UID%") != std::string::npos)
98  {
99  outputFile_ = outputFile_.replace(outputFile_.find("%UID%"), 5, unique_id);
100  }
101  else
102  {
103  if (outputFile_.rfind('.') != std::string::npos)
104  {
105  outputFile_ = outputFile_.insert(outputFile_.rfind('.'), "_" + unique_id);
106  }
107  else
108  {
109  outputFile_ = outputFile_.append("_" + unique_id);
110  }
111  }
112  }
113 
114  openFile_();
115  startMetrics();
116  }
117 
121  ~FileMetric() override
122  {
123  stopMetrics();
124  closeFile_();
125  }
126 
131  std::string getLibName() const override { return "file"; }
132 
140  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
141  {
142  if (!stopped_ && !inhibit_)
143  {
144  getTime_(outputStream_, time) << "FileMetric: " << name << ": " << value << " " << unit << "." << std::endl;
145  }
146  }
147 
155  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
156  {
157  sendMetric_(name, std::to_string(value), unit, time);
158  }
159 
167  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
168  {
169  sendMetric_(name, std::to_string(value), unit, time);
170  }
171 
179  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
180  {
181  sendMetric_(name, std::to_string(value), unit, time);
182  }
183 
191  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
192  {
193  sendMetric_(name, std::to_string(value), unit, time);
194  }
195 
199  void startMetrics_() override
200  {
201  stopped_ = false;
202  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin started." << std::endl;
203  }
204 
208  void stopMetrics_() override
209  {
210  stopped_ = true;
211  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin has been stopped!" << std::endl;
212  }
213 
214 private:
215  void openFile_()
216  {
217  if (!file_name_is_absolute_path_)
218  {
219  METLOG(TLVL_DEBUG) << "Reading relative directory evironment variable " << relative_env_var_;
220  std::string logPathProblem;
221  std::string logfileName;
222  char* logRootString = getenv(relative_env_var_.c_str());
223 
224  std::string logfileDir;
225  if (logRootString != nullptr)
226  {
227  if (!BFS::exists(logRootString))
228  {
229  METLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " points to a non-existant directory! Using /tmp/!";
230  outputFile_ = "/tmp/" + outputFile_;
231  METLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
232  outputStream_.open(outputFile_, mode_);
233  }
234  else
235  {
236  logfileDir = logRootString;
237  logfileDir.append("/metrics/");
238 
239  while (outputFile_.find('/') != std::string::npos)
240  {
241  METLOG(TLVL_DEBUG) << "Extracting subdirectories from relative file path " << outputFile_ << " (logfileDir = " << logfileDir << ")";
242  logfileDir.append(outputFile_.substr(0, outputFile_.find('/') + 1));
243  outputFile_.erase(0, outputFile_.find('/') + 1);
244  }
245 
246  // As long as the top-level directory exists, I don't think we
247  // really care if we have to create application directories...
248  METLOG(TLVL_DEBUG) << "Creating log file directory " << logfileDir;
249  if (!BFS::exists(logfileDir))
250  {
251  BFS::create_directories(logfileDir);
252  }
253 
254  logfileName.append(logfileDir);
255  logfileName.append(outputFile_);
256 
257  METLOG(TLVL_INFO) << "FileMetric Opening file " << logfileName;
258  outputStream_.open(logfileName, mode_);
259  }
260  }
261  else
262  {
263  METLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " is null! Using /tmp/!";
264  outputFile_ = "/tmp/" + outputFile_;
265  METLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
266  outputStream_.open(outputFile_, mode_);
267  }
268  }
269  else
270  {
271  METLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
272  outputStream_.open(outputFile_, mode_);
273  }
274  if (outputStream_.is_open())
275  {
276  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin file opened." << std::endl;
277  }
278  else
279  {
280  METLOG(TLVL_ERROR) << "Error opening metric file " << outputFile_;
281  }
282  }
283 
284  void closeFile_()
285  {
286  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric closing file stream." << std::endl;
287 
288  try
289  {
290  outputStream_.flush();
291  outputStream_.close();
292  }
293  catch (...)
294  {
295  // IGNORED
296  }
297  }
298 }; // namespace artdaq
299 } // End namespace artdaq
300 
301 DEFINE_ARTDAQ_METRIC(artdaq::FileMetric)
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:41
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
~FileMetric() override
FileMetric Destructor. Calls stopMetrics and then closes the file.
Definition: file_metric.cc:121
fhicl::ParameterSet pset
The ParameterSet used to configure the MetricPlugin.
void stopMetrics_() override
Perform shutdown actions. Writes stop message to output file.
Definition: file_metric.cc:208
void sendMetric_(const std::string &name, const int &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Write metric data to a file.
Definition: file_metric.cc:155
void stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
void sendMetric_(const std::string &name, const float &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Write metric data to a file.
Definition: file_metric.cc:179
void sendMetric_(const std::string &name, const std::string &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Write metric data to a file.
Definition: file_metric.cc:140
void sendMetric_(const std::string &name, const double &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Write metric data to a file.
Definition: file_metric.cc:167
void startMetrics_() override
Perform startup actions. Writes start message to output file.
Definition: file_metric.cc:199
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit, const std::chrono::system_clock::time_point &time) override
Write metric data to a file.
Definition: file_metric.cc:191
FileMetric writes metric data to a file on disk.
Definition: file_metric.cc:27
FileMetric(fhicl::ParameterSet const &config, std::string const &app_name, std::string const &metric_name)
FileMetric Constructor. Opens the file and starts the metric.
Definition: file_metric.cc:73
std::string getLibName() const override
Get the library name for the File metric.
Definition: file_metric.cc:131
bool inhibit_
Flag to indicate that the MetricPlugin is being stopped, and any metric back-ends which do not have a...