AnCH Framework  0.1
Another C++ Hack Framework
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
loggerFactory.hpp
1 /*
2  ANCH Framework: ANother C++ Hack is a C++ framework based on C++11 standard
3  Copyright (C) 2012 Vincent Lachenal
4 
5  This file is part of ANCH Framework.
6 
7  ANCH Framework is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  ANCH Framework is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with ANCH Framework. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #ifndef _ANCH_LOGGER_LOGGER_FACTORY_H_
21 #define _ANCH_LOGGER_LOGGER_FACTORY_H_
22 
23 // Add default logger configuration file to anch-logger.conf +
24 #ifndef _ANCH_LOGGER_CONFIG_FILE_
25 #define _ANCH_LOGGER_CONFIG_FILE_ "anch-logger.conf"
26 #endif // _ANCH_LOGGER_CONFIG_FILE_
27 // Add default logger configuration file to anch-logger.conf -
28 
29 #include <iostream>
30 #include <map>
31 #include <vector>
32 #include <set>
33 
34 #ifdef ANCH_BOOST_REGEX
35 #include <boost/regex.hpp>
36 #else
37 #include <regex>
38 #endif
39 
40 #include "logger/levels.hpp"
41 #include "logger/loggerConfiguration.hpp"
42 #include "logger/logger.hpp"
43 #include "logger/writer.hpp"
44 #include "logger/threadSafeWriter.hpp"
45 #include "logger/lowPriorityWriter.hpp"
46 #include "resource/resource.hpp"
47 #include "singleton.hpp"
48 
49 
50 namespace anch {
51  namespace logger {
52 
62  class LoggerFactory: public anch::Singleton<LoggerFactory> {
63  friend class anch::Singleton<LoggerFactory>;
64 
65  private:
66  // Attributes +
68  std::vector<LoggerConfiguration> _loggersConfig;
69 
71  std::vector<anch::logger::Logger*> _loggers;
72  // Attributes -
73 
74  private:
75  // Constructor +
79  LoggerFactory(): _loggersConfig() {
80  //std::atexit(LoggerFactory::cleanWriters);
81  try {
82  const anch::resource::Resource& resource = anch::resource::Resource::getResource(_ANCH_LOGGER_CONFIG_FILE_);
83  std::map<std::string,anch::logger::Writer*> writers;
84  initializeWriters(writers, resource);
85  initializeLoggersConfiguration(writers, resource);
86 
87  } catch(...) {
88  loadDefaultConfiguration();
89  }
90  }
91  // Constructor -
92 
93  // Destructor +
98  virtual ~LoggerFactory() {
99  std::set<anch::logger::Writer*> writers;
100  for(size_t i = 0 ; i < _loggersConfig.size() ; i++) {
101  const std::vector<anch::logger::Writer*>& confWriters = _loggersConfig[i].getWriters();
102  for(anch::logger::Writer* writer : confWriters) {
103  writers.insert(writer);
104  }
105  }
106  for(anch::logger::Writer* writer : writers) {
107  delete writer;
108  }
109  for(anch::logger::Logger* logger : _loggers) {
110  delete logger;
111  }
112  };
113  // Destructor -
114 
115  public:
116  // Methods +
125  static const anch::logger::Logger& getLogger(const std::string& loggerName) {
126  LoggerFactory& self = LoggerFactory::getInstance();
127 
128  const anch::logger::LoggerConfiguration* loggerConfig = NULL;
129  for(size_t i = 0 ; i < self._loggersConfig.size() ; i++) {
130  const anch::logger::LoggerConfiguration& config = self._loggersConfig[i];
131  const std::string& confName = config.getCategory();
132  // First check on size +
133  if((loggerConfig != NULL
134  && loggerConfig->getCategory().size() > confName.size())
135  || (confName.size() > loggerName.size()
136  && confName != "default")) {
137  continue;
138  }
139  // First check on size -
140 
141  // Compare category name and logger name +
142  if(loggerName.substr(0,confName.size()) == confName) {
143  loggerConfig = &config;
144  continue;
145  }
146  // Compare category name and logger name -
147 
148  // Check if default +
149  if(loggerConfig == NULL && confName == "default") {
150  loggerConfig = &config;
151  }
152  // Check if default -
153  }
154 
155  // Instanciate a new logger from configuration +
156  anch::logger::Logger* logger = NULL;
157  if(loggerConfig != NULL) {
158  logger = new anch::logger::Logger(loggerName,
159  loggerConfig->getLevel(),
160  loggerConfig->getWriters());
161  self._loggers.push_back(logger);
162  }
163  // Instanciate a new logger from configuration -
164 
165  return *logger;
166  }
167 
168  private:
177  anch::logger::Writer* createWriterInstance(bool threadSafe,
178  bool lowPriority,
179  std::ostream* out,
180  const std::string& pattern) {
181  anch::logger::Writer* writer = NULL;
182  if(lowPriority) {
183  writer = new anch::logger::LowPriorityWriter(out,pattern);
184  static_cast<anch::logger::LowPriorityWriter*>(writer)->startTreatment();
185  } else if(threadSafe) {
186  writer = new anch::logger::ThreadSafeWriter(out,pattern);
187  } else {
188  writer = new anch::logger::Writer(out,pattern);
189  }
190  return writer;
191  }
192 
203  anch::logger::Writer* createWriterInstance(bool threadSafe,
204  bool lowPriority,
205  const std::string& path,
206  const std::string& pattern,
207  unsigned int maxSize,
208  int maxIndex) {
209  anch::logger::Writer* writer = NULL;
210  if(lowPriority) {
211  writer = new anch::logger::LowPriorityWriter(path,pattern,maxSize,maxIndex);
212  static_cast<anch::logger::LowPriorityWriter*>(writer)->startTreatment();
213  } else if(threadSafe) {
214  writer = new anch::logger::ThreadSafeWriter(path,pattern,maxSize,maxIndex);
215  } else {
216  writer = new anch::logger::Writer(path,pattern,maxSize,maxIndex);
217  }
218  return writer;
219  }
220 
227  void initializeWriters(std::map<std::string,anch::logger::Writer*>& writers,
228  const anch::resource::Resource& resource) {
229  std::map<std::string,unsigned int> sizeMap = std::map<std::string,unsigned int>({
230  {"K",1024},
231  {"M",1024*1024},
232  {"G",1024*1024*1024}
233  });
234 #ifdef ANCH_BOOST_REGEX
235  const boost::regex sizeRegex = boost::regex("^([0-9]+)(K|M|G)?$");
236 #else
237  const std::regex sizeRegex = std::regex("^([0-9]+)(K|M|G)?$");
238 #endif
239 
240  // Writer QoS configuration +
241  bool globalThreadSafe = true;
242  std::string paramValue;
243  if(resource.getParameter(paramValue, "thread.safe")) {
244  globalThreadSafe = (paramValue == "1");
245  }
246  paramValue = "";
247  bool globalLowPriority = false;
248  if(resource.getParameter(paramValue, "low.priority")) {
249  globalLowPriority = (paramValue == "1");
250  }
251  paramValue = "";
252  // Writer QoS configuration -
253 
254 #ifdef ANCH_BOOST_REGEX
255  boost::smatch match;
256 #else
257  std::smatch match;
258 #endif
259  const std::map<std::string,anch::resource::Section>& config = resource.getConfiguration();
260  for(auto iter = config.cbegin() ; iter != config.cend() ; iter++) {
261  if(iter->first.substr(0,8) == "WRITER::") {
262  std::string writer = iter->first;
263  std::string name = writer.substr(8);
264  // Retrieve log pattern +
265  std::string pattern;
266  bool found = resource.getParameter(pattern,
267  "writer.pattern",
268  writer);
269  if(!found) {
270  pattern = "%m";
271  }
272  // Retrieve log pattern -
273 
274  // Writer QoS configuration +
275  bool threadSafe = globalThreadSafe;
276  if(resource.getParameter(paramValue, "writer.thread.safe", writer)) {
277  threadSafe = (paramValue == "1");
278  }
279  paramValue = "";
280  bool lowPriority = globalLowPriority;
281  if(resource.getParameter(paramValue, "writer.low.priority", writer)) {
282  lowPriority = (paramValue == "1");
283  }
284  // Writer QoS configuration -
285 
286  if(name == "console") { // Console writer will put logs on standard output
287  writers[name] = createWriterInstance(threadSafe,
288  lowPriority,
289  (std::ostream*)(&std::cout),
290  pattern);
291 
292  } else { // File writer
293  // File path +
294  std::string path;
295  found = resource.getParameter(path, "writer.filepath", writer);
296  // File path -
297  if(found) {
298  // Max file size +
299  std::string maxSizeStr;
300  unsigned int maxSize = 0;
301  resource.getParameter(maxSizeStr, "writer.max.size", writer);
302  if(regex_search(maxSizeStr, match, sizeRegex)) {
303  const std::string multStr = std::string(match[2].first,
304  match[2].second);
305  maxSize = std::stoi(std::string(match[1].first,
306  match[1].second).data());
307  if(multStr != "") {
308  maxSize *= sizeMap[multStr];
309  }
310  }
311  // Max file size -
312 
313  // Max file index on rotate +
314  int maxIndex = 0;
315  std::string maxIdxStr;
316  resource.getParameter(maxIdxStr,
317  "writer.max.rotate.index",
318  writer);
319  if(found) {
320  maxIndex = std::stoi(maxIdxStr);
321  }
322  // Max file index on rotate -
323  writers[name] = createWriterInstance(threadSafe,
324  lowPriority,
325  path,
326  pattern,
327  maxSize,
328  maxIndex);
329  }
330  }
331  }
332  }
333  }
334 
341  void initializeLoggersConfiguration(const std::map<std::string,anch::logger::Writer*>& writers,
342  const anch::resource::Resource& resource) {
343 #ifdef ANCH_BOOST_REGEX
344  boost::regex upperRegex = boost::regex("[a-z]");
345  boost::smatch match;
346 #else
347  std::regex upperRegex = std::regex("[a-z]");
348  std::smatch match;
349 #endif
350  std::string upperRep = "[A-Z]";
351 
352  const std::map<std::string,anch::resource::Section>& config = resource.getConfiguration();
353  for(auto iter = config.cbegin() ; iter != config.cend() ; iter++) {
354  if(iter->first.substr(0,10) == "CATEGORY::") {
355  std::string category = iter->first;
356  std::string name = iter->first.substr(10);
357  std::string writerStr;
358  bool found = resource.getParameter(writerStr,
359  "logger.writers",
360  category);
361  if(found) {
362  // Retrieve writers +
363  size_t pos = 0;
364  std::vector<anch::logger::Writer*> loggerWriters;
365  size_t nextPos = writerStr.find(',',pos);
366  while(nextPos != std::string::npos && nextPos != pos) {
367  const std::string writerName = writerStr.substr(pos,
368  nextPos - pos);
369  auto iter = writers.find(writerName);
370  if(iter != writers.cend()) {
371  loggerWriters.push_back(iter->second);
372  }
373  pos = nextPos + 1;
374  nextPos = writerStr.find(',',pos);
375  }
376  const std::string writerName = writerStr.substr(pos);
377  auto iter = writers.find(writerName);
378  if(iter != writers.cend()) {
379  loggerWriters.push_back(iter->second);
380  }
381  // Retrieve writers -
382 
383  // Retrieve level +
384  if(loggerWriters.empty()) {
385  std::cerr << "No writers has been found for " << name << ": "
386  << writerStr << std::endl;
387 
388  } else {
389  std::string levelLbl;
390  resource.getParameter(levelLbl, "logger.level", category);
391  std::transform(levelLbl.begin(),
392  levelLbl.end(),
393  levelLbl.begin(),
394  ::toupper);
395  anch::logger::Level level = anch::logger::Level::FATAL;
396  auto iterLvl = anch::logger::LABEL_LEVEL.find(levelLbl);
397  if(iterLvl == anch::logger::LABEL_LEVEL.cend()) {
398  std::cerr << "Invalid level: " << levelLbl << std::endl;
399  } else {
400  level = iterLvl->second;
401  }
402  _loggersConfig.push_back(LoggerConfiguration(name,
403  level,
404  loggerWriters));
405  }
406  // Retrieve level -
407  }
408  }
409  }
410  }
411 
415  void loadDefaultConfiguration() {
416  _loggersConfig.clear();
417  std::cerr << "Logger configuration file " << _ANCH_LOGGER_CONFIG_FILE_ << " has not been found or is not readable." << std::endl;
418  std::cerr << "Default configuration is loading." << std::endl;
419  std::cerr << "Everything will be logged in console." << std::endl;
420  ThreadSafeWriter* console = new ThreadSafeWriter((std::ostream*)(&std::cout), "$d{%Y-%m-%d %H:%M:%S} - $m");
421  std::vector<anch::logger::Writer*> loggerWriters;
422  loggerWriters.push_back(console);
423  loggerWriters.shrink_to_fit();
424  _loggersConfig.push_back(LoggerConfiguration("default",
425  anch::logger::Level::TRACE,
426  loggerWriters));
427  }
428  // Methods -
429 
430  };
431 
432  }
433 }
434 
435 #endif // _ANCH_LOGGER_LOGGER_FACTORY_H_
const std::map< const std::string, const Level > LABEL_LEVEL
Definition: levels.hpp:73
bool getParameter(std::string &value, const std::string &param, const std::string &section="") const
Definition: resource.cpp:80
Definition: logger.hpp:47
const std::map< std::string, anch::resource::Section > & getConfiguration() const
Definition: resource.hpp:94
AnCH framework base namespace.
Definition: base64.hpp:28
static const Resource & getResource(const std::string &filePath)
Definition: resource.cpp:58
Definition: loggerConfiguration.hpp:37
Definition: resource.hpp:37
const anch::logger::Level & getLevel() const
Definition: loggerConfiguration.hpp:85
const std::vector< anch::logger::Writer * > & getWriters() const
Definition: loggerConfiguration.hpp:94
Definition: lowPriorityWriter.hpp:40
static LoggerFactory & getInstance()
Definition: singleton.hpp:42
Definition: threadSafeWriter.hpp:36
Level
Definition: levels.hpp:34
const std::string & getCategory() const
Definition: loggerConfiguration.hpp:76
static const anch::logger::Logger & getLogger(const std::string &loggerName)
Definition: loggerFactory.hpp:125
Definition: writer.hpp:37
Logger factory.
Definition: loggerFactory.hpp:62
Meyers&#39; singleton implemtation.
Definition: singleton.hpp:35