artdaq_utilities  v1_05_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 : 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  static std::mutex timeMutex;
41  std::unique_lock<std::mutex> lk(timeMutex);
42  using std::chrono::system_clock;
43  std::time_t tt = system_clock::to_time_t(system_clock::now());
44 
45  struct std::tm* ptm = std::localtime(&tt);
46  if (timeformat_.size())
47  {
48  return stream << std::put_time(ptm, timeformat_.c_str()) << ": ";
49  }
50 
51  return stream;
52  }
53 
54 public:
69  explicit FileMetric(fhicl::ParameterSet const& config, std::string const& app_name)
70  : MetricPlugin(config, app_name)
71  , outputFile_(pset.get<std::string>("fileName", "FileMetric.out"))
72  , file_name_is_absolute_path_(pset.get<bool>("absolute_file_path", true))
73  , relative_env_var_(pset.get<std::string>("relative_directory_env_var", "ARTDAQ_LOG_ROOT"))
74  , uniquify_file_name_(pset.get<bool>("uniquify", false))
75  , timeformat_(pset.get<std::string>("time_format", "%c"))
76  , stopped_(true)
77  {
78  std::string modeString = pset.get<std::string>("fileMode", "append");
79 
80  mode_ = std::ofstream::out | std::ofstream::app;
81  if (modeString == "Overwrite" || modeString == "Create" || modeString == "Write")
82  {
83  mode_ = std::ofstream::out | std::ofstream::trunc;
84  }
85 
86  if (uniquify_file_name_)
87  {
88  std::string unique_id = std::to_string(getpid());
89  if (outputFile_.find("%UID%") != std::string::npos)
90  {
91  outputFile_ = outputFile_.replace(outputFile_.find("%UID%"), 5, unique_id);
92  }
93  else
94  {
95  if (outputFile_.rfind(".") != std::string::npos)
96  {
97  outputFile_ = outputFile_.insert(outputFile_.rfind("."), "_" + unique_id);
98  }
99  else
100  {
101  outputFile_ = outputFile_.append("_" + unique_id);
102  }
103  }
104  }
105  openFile_();
106  startMetrics();
107  }
108 
112  virtual ~FileMetric()
113  {
114  stopMetrics();
115  closeFile_();
116  }
117 
122  std::string getLibName() const override { return "file"; }
123 
130  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
131  {
132  if (!stopped_ && !inhibit_)
133  {
134  getTime_(outputStream_) << "FileMetric: " << name << ": " << value << " " << unit << "." << std::endl;
135  }
136  }
137 
144  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
145  {
146  sendMetric_(name, std::to_string(value), unit);
147  }
148 
155  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
156  {
157  sendMetric_(name, std::to_string(value), unit);
158  }
159 
166  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
167  {
168  sendMetric_(name, std::to_string(value), unit);
169  }
170 
177  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
178  {
179  sendMetric_(name, std::to_string(value), unit);
180  }
181 
185  void startMetrics_() override
186  {
187  stopped_ = false;
188  getTime_(outputStream_) << "FileMetric plugin started." << std::endl;
189  }
190 
194  void stopMetrics_() override
195  {
196  stopped_ = true;
197  getTime_(outputStream_) << "FileMetric plugin has been stopped!" << std::endl;
198  }
199 
200 private:
201  void openFile_()
202  {
203  if (!file_name_is_absolute_path_)
204  {
205  TLOG(TLVL_DEBUG) << "Reading relative directory evironment variable " << relative_env_var_;
206  std::string logPathProblem = "";
207  std::string logfileName = "";
208  char* logRootString = getenv(relative_env_var_.c_str());
209 
210  std::string logfileDir = "";
211  if (logRootString != nullptr)
212  {
213  if (!BFS::exists(logRootString))
214  {
215  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " points to a non-existant directory! Using /tmp/!";
216  outputFile_ = "/tmp/" + outputFile_;
217  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
218  outputStream_.open(outputFile_, mode_);
219  }
220  else
221  {
222  logfileDir = logRootString;
223  logfileDir.append("/metrics/");
224 
225  while (outputFile_.find('/') != std::string::npos)
226  {
227  TLOG(TLVL_DEBUG) << "Extracting subdirectories from relative file path " << outputFile_ << " (logfileDir = " << logfileDir << ")";
228  logfileDir.append(outputFile_.substr(0, outputFile_.find('/') + 1));
229  outputFile_.erase(0, outputFile_.find('/') + 1);
230  }
231 
232  // As long as the top-level directory exists, I don't think we
233  // really care if we have to create application directories...
234  TLOG(TLVL_DEBUG) << "Creating log file directory " << logfileDir;
235  if (!BFS::exists(logfileDir))
236  BFS::create_directories(logfileDir);
237 
238  logfileName.append(logfileDir);
239  logfileName.append(outputFile_);
240 
241  TLOG(TLVL_INFO) << "FileMetric Opening file " << logfileName;
242  outputStream_.open(logfileName, mode_);
243  }
244  }
245  else
246  {
247  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " is null! Using /tmp/!";
248  outputFile_ = "/tmp/" + outputFile_;
249  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
250  outputStream_.open(outputFile_, mode_);
251  }
252  }
253  else
254  {
255  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
256  outputStream_.open(outputFile_, mode_);
257  }
258  if (outputStream_.is_open())
259  {
260  getTime_(outputStream_) << "FileMetric plugin file opened." << std::endl;
261  }
262  else
263  {
264  TLOG(TLVL_ERROR) << "Error opening metric file " << outputFile_;
265  }
266  }
267 
268  void closeFile_()
269  {
270  getTime_(outputStream_) << "FileMetric closing file stream." << std::endl;
271  outputStream_.close();
272  }
273 };
274 } // End namespace artdaq
275 
276 DEFINE_ARTDAQ_METRIC(artdaq::FileMetric)
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:130
void sendMetric_(const std::string &name, const unsigned long int &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:177
The MetricPlugin class defines the interface that MetricManager uses to send metric data to the vario...
Definition: MetricPlugin.hh:29
void sendMetric_(const std::string &name, const double &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:155
void startMetrics()
Perform startup actions. Simply calls the virtual startMetrics_ function.
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:144
void stopMetrics_() override
Perform shutdown actions. Writes stop message to output file.
Definition: file_metric.cc:194
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:185
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:166
FileMetric writes metric data to a file on disk.
Definition: file_metric.cc:26
virtual ~FileMetric()
FileMetric Destructor. Calls stopMetrics and then closes the file.
Definition: file_metric.cc:112
FileMetric(fhicl::ParameterSet const &config, std::string const &app_name)
FileMetric Constructor. Opens the file and starts the metric.
Definition: file_metric.cc:69
std::string getLibName() const override
Get the library name for the File metric.
Definition: file_metric.cc:122
bool inhibit_
Flag to indicate that the MetricPlugin is being stopped, and any metric back-ends which do not have a...