artdaq_utilities  v1_06_00
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 #define TRACE_NAME "FileMetric"
8 #include "tracemf.h"
9 
10 #include "artdaq-utilities/Plugins/MetricMacros.hh"
11 #include "fhiclcpp/ParameterSet.h"
12 
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <boost/filesystem.hpp>
16 #include <ctime>
17 #include <fstream>
18 #include <iomanip>
19 #include <string>
20 namespace BFS = boost::filesystem;
21 
22 namespace artdaq {
26 class FileMetric final : public MetricPlugin
27 {
28 private:
29  std::string outputFile_;
30  bool file_name_is_absolute_path_;
31  std::string relative_env_var_;
32  bool uniquify_file_name_;
33  std::ofstream outputStream_;
34  std::ios_base::openmode mode_;
35  std::string timeformat_;
36  bool stopped_;
37 
38  std::ostream& getTime_(std::ostream& stream, const std::chrono::system_clock::time_point& time)
39  {
40  std::time_t tt = std::chrono::system_clock::to_time_t(time);
41 
42  struct std::tm* ptm = std::localtime(&tt);
43  if (!timeformat_.empty())
44  {
45  return stream << std::put_time(ptm, timeformat_.c_str()) << ": ";
46  }
47 
48  return stream;
49  }
50 
51  FileMetric(const FileMetric&) = delete;
52  FileMetric(FileMetric&&) = delete;
53  FileMetric& operator=(const FileMetric&) = delete;
54  FileMetric& operator=(FileMetric&&) = delete;
55 
56 public:
71  explicit FileMetric(fhicl::ParameterSet const& config, std::string const& app_name)
72  : MetricPlugin(config, app_name)
73  , outputFile_(pset.get<std::string>("fileName", "FileMetric.out"))
74  , file_name_is_absolute_path_(pset.get<bool>("absolute_file_path", true))
75  , relative_env_var_(pset.get<std::string>("relative_directory_env_var", "ARTDAQ_LOG_ROOT"))
76  , uniquify_file_name_(pset.get<bool>("uniquify", false))
77  , timeformat_(pset.get<std::string>("time_format", "%c"))
78  , stopped_(true)
79  {
80  auto modeString = pset.get<std::string>("fileMode", "append");
81 
82  mode_ = std::ofstream::out | std::ofstream::app;
83  if (modeString == "Overwrite" || modeString == "Create" || modeString == "Write")
84  {
85  mode_ = std::ofstream::out | std::ofstream::trunc;
86  }
87 
88  if (uniquify_file_name_)
89  {
90  std::string unique_id = std::to_string(getpid());
91  if (outputFile_.find("%UID%") != std::string::npos)
92  {
93  outputFile_ = outputFile_.replace(outputFile_.find("%UID%"), 5, unique_id);
94  }
95  else
96  {
97  if (outputFile_.rfind('.') != std::string::npos)
98  {
99  outputFile_ = outputFile_.insert(outputFile_.rfind('.'), "_" + unique_id);
100  }
101  else
102  {
103  outputFile_ = outputFile_.append("_" + unique_id);
104  }
105  }
106  }
107  openFile_();
108  startMetrics();
109  }
110 
114  ~FileMetric() override
115  {
116  stopMetrics();
117  closeFile_();
118  }
119 
124  std::string getLibName() const override { return "file"; }
125 
133  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
134  {
135  if (!stopped_ && !inhibit_)
136  {
137  getTime_(outputStream_, time) << "FileMetric: " << name << ": " << value << " " << unit << "." << std::endl;
138  }
139  }
140 
148  void sendMetric_(const std::string& name, const int& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
149  {
150  sendMetric_(name, std::to_string(value), unit, time);
151  }
152 
160  void sendMetric_(const std::string& name, const double& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
161  {
162  sendMetric_(name, std::to_string(value), unit, time);
163  }
164 
172  void sendMetric_(const std::string& name, const float& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
173  {
174  sendMetric_(name, std::to_string(value), unit, time);
175  }
176 
184  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit, const std::chrono::system_clock::time_point& time) override
185  {
186  sendMetric_(name, std::to_string(value), unit, time);
187  }
188 
192  void startMetrics_() override
193  {
194  stopped_ = false;
195  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin started." << std::endl;
196  }
197 
201  void stopMetrics_() override
202  {
203  stopped_ = true;
204  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin has been stopped!" << std::endl;
205  }
206 
207 private:
208  void openFile_()
209  {
210  if (!file_name_is_absolute_path_)
211  {
212  TLOG(TLVL_DEBUG) << "Reading relative directory evironment variable " << relative_env_var_;
213  std::string logPathProblem;
214  std::string logfileName;
215  char* logRootString = getenv(relative_env_var_.c_str());
216 
217  std::string logfileDir;
218  if (logRootString != nullptr)
219  {
220  if (!BFS::exists(logRootString))
221  {
222  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " points to a non-existant directory! Using /tmp/!";
223  outputFile_ = "/tmp/" + outputFile_;
224  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
225  outputStream_.open(outputFile_, mode_);
226  }
227  else
228  {
229  logfileDir = logRootString;
230  logfileDir.append("/metrics/");
231 
232  while (outputFile_.find('/') != std::string::npos)
233  {
234  TLOG(TLVL_DEBUG) << "Extracting subdirectories from relative file path " << outputFile_ << " (logfileDir = " << logfileDir << ")";
235  logfileDir.append(outputFile_.substr(0, outputFile_.find('/') + 1));
236  outputFile_.erase(0, outputFile_.find('/') + 1);
237  }
238 
239  // As long as the top-level directory exists, I don't think we
240  // really care if we have to create application directories...
241  TLOG(TLVL_DEBUG) << "Creating log file directory " << logfileDir;
242  if (!BFS::exists(logfileDir))
243  {
244  BFS::create_directories(logfileDir);
245  }
246 
247  logfileName.append(logfileDir);
248  logfileName.append(outputFile_);
249 
250  TLOG(TLVL_INFO) << "FileMetric Opening file " << logfileName;
251  outputStream_.open(logfileName, mode_);
252  }
253  }
254  else
255  {
256  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " is null! Using /tmp/!";
257  outputFile_ = "/tmp/" + outputFile_;
258  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
259  outputStream_.open(outputFile_, mode_);
260  }
261  }
262  else
263  {
264  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
265  outputStream_.open(outputFile_, mode_);
266  }
267  if (outputStream_.is_open())
268  {
269  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric plugin file opened." << std::endl;
270  }
271  else
272  {
273  TLOG(TLVL_ERROR) << "Error opening metric file " << outputFile_;
274  }
275  }
276 
277  void closeFile_()
278  {
279  getTime_(outputStream_, std::chrono::system_clock::now()) << "FileMetric closing file stream." << std::endl;
280 
281  try
282  {
283  outputStream_.flush();
284  outputStream_.close();
285  }
286  catch (...)
287  {
288  // IGNORED
289  }
290  }
291 }; // namespace artdaq
292 } // End namespace artdaq
293 
294 DEFINE_ARTDAQ_METRIC(artdaq::FileMetric)
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:37
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:114
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:201
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:148
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:172
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:133
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:160
void startMetrics_() override
Perform startup actions. Writes start message to output file.
Definition: file_metric.cc:192
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:184
FileMetric writes metric data to a file on disk.
Definition: file_metric.cc:26
FileMetric(fhicl::ParameterSet const &config, std::string const &app_name)
FileMetric Constructor. Opens the file and starts the metric.
Definition: file_metric.cc:71
std::string getLibName() const override
Get the library name for the File metric.
Definition: file_metric.cc:124
bool inhibit_
Flag to indicate that the MetricPlugin is being stopped, and any metric back-ends which do not have a...