artdaq_utilities  v1_05_05
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  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_.size())
44  {
45  return stream << std::put_time(ptm, timeformat_.c_str()) << ": ";
46  }
47 
48  return stream;
49  }
50 
51 public:
66  explicit FileMetric(fhicl::ParameterSet const& config, std::string const& app_name)
67  : MetricPlugin(config, app_name)
68  , outputFile_(pset.get<std::string>("fileName", "FileMetric.out"))
69  , file_name_is_absolute_path_(pset.get<bool>("absolute_file_path", true))
70  , relative_env_var_(pset.get<std::string>("relative_directory_env_var", "ARTDAQ_LOG_ROOT"))
71  , uniquify_file_name_(pset.get<bool>("uniquify", false))
72  , timeformat_(pset.get<std::string>("time_format", "%c"))
73  , stopped_(true)
74  {
75  std::string modeString = pset.get<std::string>("fileMode", "append");
76 
77  mode_ = std::ofstream::out | std::ofstream::app;
78  if (modeString == "Overwrite" || modeString == "Create" || modeString == "Write")
79  {
80  mode_ = std::ofstream::out | std::ofstream::trunc;
81  }
82 
83  if (uniquify_file_name_)
84  {
85  std::string unique_id = std::to_string(getpid());
86  if (outputFile_.find("%UID%") != std::string::npos)
87  {
88  outputFile_ = outputFile_.replace(outputFile_.find("%UID%"), 5, unique_id);
89  }
90  else
91  {
92  if (outputFile_.rfind(".") != std::string::npos)
93  {
94  outputFile_ = outputFile_.insert(outputFile_.rfind("."), "_" + unique_id);
95  }
96  else
97  {
98  outputFile_ = outputFile_.append("_" + unique_id);
99  }
100  }
101  }
102  openFile_();
103  startMetrics();
104  }
105 
109  virtual ~FileMetric()
110  {
111  stopMetrics();
112  closeFile_();
113  }
114 
119  std::string getLibName() const override { return "file"; }
120 
127  void sendMetric_(const std::string& name, const std::string& value, const std::string& unit) override
128  {
129  if (!stopped_ && !inhibit_)
130  {
131  getTime_(outputStream_) << "FileMetric: " << name << ": " << value << " " << unit << "." << std::endl;
132  }
133  }
134 
141  void sendMetric_(const std::string& name, const int& value, const std::string& unit) override
142  {
143  sendMetric_(name, std::to_string(value), unit);
144  }
145 
152  void sendMetric_(const std::string& name, const double& value, const std::string& unit) override
153  {
154  sendMetric_(name, std::to_string(value), unit);
155  }
156 
163  void sendMetric_(const std::string& name, const float& value, const std::string& unit) override
164  {
165  sendMetric_(name, std::to_string(value), unit);
166  }
167 
174  void sendMetric_(const std::string& name, const unsigned long int& value, const std::string& unit) override
175  {
176  sendMetric_(name, std::to_string(value), unit);
177  }
178 
182  void startMetrics_() override
183  {
184  stopped_ = false;
185  getTime_(outputStream_) << "FileMetric plugin started." << std::endl;
186  }
187 
191  void stopMetrics_() override
192  {
193  stopped_ = true;
194  getTime_(outputStream_) << "FileMetric plugin has been stopped!" << std::endl;
195  }
196 
197 private:
198  void openFile_()
199  {
200  if (!file_name_is_absolute_path_)
201  {
202  TLOG(TLVL_DEBUG) << "Reading relative directory evironment variable " << relative_env_var_;
203  std::string logPathProblem = "";
204  std::string logfileName = "";
205  char* logRootString = getenv(relative_env_var_.c_str());
206 
207  std::string logfileDir = "";
208  if (logRootString != nullptr)
209  {
210  if (!BFS::exists(logRootString))
211  {
212  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " points to a non-existant directory! Using /tmp/!";
213  outputFile_ = "/tmp/" + outputFile_;
214  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
215  outputStream_.open(outputFile_, mode_);
216  }
217  else
218  {
219  logfileDir = logRootString;
220  logfileDir.append("/metrics/");
221 
222  while (outputFile_.find('/') != std::string::npos)
223  {
224  TLOG(TLVL_DEBUG) << "Extracting subdirectories from relative file path " << outputFile_ << " (logfileDir = " << logfileDir << ")";
225  logfileDir.append(outputFile_.substr(0, outputFile_.find('/') + 1));
226  outputFile_.erase(0, outputFile_.find('/') + 1);
227  }
228 
229  // As long as the top-level directory exists, I don't think we
230  // really care if we have to create application directories...
231  TLOG(TLVL_DEBUG) << "Creating log file directory " << logfileDir;
232  if (!BFS::exists(logfileDir))
233  BFS::create_directories(logfileDir);
234 
235  logfileName.append(logfileDir);
236  logfileName.append(outputFile_);
237 
238  TLOG(TLVL_INFO) << "FileMetric Opening file " << logfileName;
239  outputStream_.open(logfileName, mode_);
240  }
241  }
242  else
243  {
244  TLOG(TLVL_WARNING) << "Relative directory environment variable " << relative_env_var_ << " is null! Using /tmp/!";
245  outputFile_ = "/tmp/" + outputFile_;
246  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
247  outputStream_.open(outputFile_, mode_);
248  }
249  }
250  else
251  {
252  TLOG(TLVL_INFO) << "FileMetric Opening file " << outputFile_;
253  outputStream_.open(outputFile_, mode_);
254  }
255  if (outputStream_.is_open())
256  {
257  getTime_(outputStream_) << "FileMetric plugin file opened." << std::endl;
258  }
259  else
260  {
261  TLOG(TLVL_ERROR) << "Error opening metric file " << outputFile_;
262  }
263  }
264 
265  void closeFile_()
266  {
267  getTime_(outputStream_) << "FileMetric closing file stream." << std::endl;
268  outputStream_.close();
269  }
270 };
271 } // End namespace artdaq
272 
273 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:127
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:174
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:152
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:141
void stopMetrics_() override
Perform shutdown actions. Writes stop message to output file.
Definition: file_metric.cc:191
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:182
void sendMetric_(const std::string &name, const float &value, const std::string &unit) override
Write metric data to a file.
Definition: file_metric.cc:163
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:109
FileMetric(fhicl::ParameterSet const &config, std::string const &app_name)
FileMetric Constructor. Opens the file and starts the metric.
Definition: file_metric.cc:66
std::string getLibName() const override
Get the library name for the File metric.
Definition: file_metric.cc:119
bool inhibit_
Flag to indicate that the MetricPlugin is being stopped, and any metric back-ends which do not have a...