artdaq_utilities  v1_05_07b
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)
39  {
40  std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
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 
132  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
133  {
134  if (!stopped_ && !inhibit_)
135  {
136  getTime_(outputStream_) << "FileMetric: " << name << ": " << value << " " << unit << "." << std::endl;
137  }
138  }
139 
146  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
147  {
148  sendMetric_(name, std::to_string(value), unit);
149  }
150 
157  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
158  {
159  sendMetric_(name, std::to_string(value), unit);
160  }
161 
168  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
169  {
170  sendMetric_(name, std::to_string(value), unit);
171  }
172 
179  void sendMetric_(const std::string& name, const uint64_t& value, const std::string& unit) override
180  {
181  sendMetric_(name, std::to_string(value), unit);
182  }
183 
187  void startMetrics_() override
188  {
189  stopped_ = false;
190  getTime_(outputStream_) << "FileMetric plugin started." << std::endl;
191  }
192 
196  void stopMetrics_() override
197  {
198  stopped_ = true;
199  getTime_(outputStream_) << "FileMetric plugin has been stopped!" << std::endl;
200  }
201 
202 private:
203  void openFile_()
204  {
205  if (!file_name_is_absolute_path_)
206  {
207  TLOG(TLVL_DEBUG) << "Reading relative directory evironment variable " << relative_env_var_;
208  std::string logPathProblem;
209  std::string logfileName;
210  char* logRootString = getenv(relative_env_var_.c_str());
211 
212  std::string logfileDir;
213  if (logRootString != nullptr)
214  {
215  if (!BFS::exists(logRootString))
216  {
217  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " points to a non-existant directory! Using /tmp/!";
218  outputFile_ = "/tmp/" + outputFile_;
219  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
220  outputStream_.open(outputFile_, mode_);
221  }
222  else
223  {
224  logfileDir = logRootString;
225  logfileDir.append("/metrics/");
226 
227  while (outputFile_.find('/') != std::string::npos)
228  {
229  TLOG(TLVL_DEBUG) << "Extracting subdirectories from relative file path " << outputFile_ << " (logfileDir = " << logfileDir << ")";
230  logfileDir.append(outputFile_.substr(0, outputFile_.find('/') + 1));
231  outputFile_.erase(0, outputFile_.find('/') + 1);
232  }
233 
234  // As long as the top-level directory exists, I don't think we
235  // really care if we have to create application directories...
236  TLOG(TLVL_DEBUG) << "Creating log file directory " << logfileDir;
237  if (!BFS::exists(logfileDir))
238  {
239  BFS::create_directories(logfileDir);
240  }
241 
242  logfileName.append(logfileDir);
243  logfileName.append(outputFile_);
244 
245  TLOG(TLVL_INFO) << "FileMetric Opening file " << logfileName;
246  outputStream_.open(logfileName, mode_);
247  }
248  }
249  else
250  {
251  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " is null! Using /tmp/!";
252  outputFile_ = "/tmp/" + outputFile_;
253  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
254  outputStream_.open(outputFile_, mode_);
255  }
256  }
257  else
258  {
259  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
260  outputStream_.open(outputFile_, mode_);
261  }
262  if (outputStream_.is_open())
263  {
264  getTime_(outputStream_) << "FileMetric plugin file opened." << std::endl;
265  }
266  else
267  {
268  TLOG(TLVL_ERROR) << "Error opening metric file " << outputFile_;
269  }
270  }
271 
272  void closeFile_()
273  {
274  getTime_(outputStream_) << "FileMetric closing file stream." << std::endl;
275  try
276  {
277  outputStream_.flush();
278  outputStream_.close();
279  }
280  catch (...)
281  {
282  // IGNORED
283  }
284  }
285 };
286 } // End namespace artdaq
287 
288 DEFINE_ARTDAQ_METRIC(artdaq::FileMetric)
void sendMetric_(const std::string &name, const uint64_t &value, const std::string &unit) 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) override
Write metric data to a file.
Definition: file_metric.cc:132
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:37
void sendMetric_(const std::string &name, const double &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:157
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 sendMetric_(const std::string &name, const int &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:146
void stopMetrics_() override
Perform shutdown actions. Writes stop message to output file.
Definition: file_metric.cc:196
void stopMetrics()
Perform shutdown actions. Zeroes out all accumulators, and sends zeros for each metric. Calls stopMetrics_() for any plugin-defined shutdown actions.
void startMetrics_() override
Perform startup actions. Writes start message to output file.
Definition: file_metric.cc:187
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:168
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...