RSC  0.17.1
LoggerFactory.cpp
Go to the documentation of this file.
1 /* ============================================================
2  *
3  * This file is a part of RSC project
4  *
5  * Copyright (C) 2010 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
6  *
7  * This file may be licensed under the terms of the
8  * GNU Lesser General Public License Version 3 (the ``LGPL''),
9  * or (at your option) any later version.
10  *
11  * Software distributed under the License is distributed
12  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13  * express or implied. See the LGPL for the specific language
14  * governing rights and limitations.
15  *
16  * You should have received a copy of the LGPL along with this
17  * program. If not, go to http://www.gnu.org/licenses/lgpl.html
18  * or write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The development of this software was supported by:
22  * CoR-Lab, Research Institute for Cognition and Robotics
23  * Bielefeld University
24  *
25  * ============================================================ */
26 
27 #include "LoggerFactory.h"
28 
29 #include <vector>
30 
31 #include <boost/bind.hpp>
32 #include <boost/enable_shared_from_this.hpp>
33 #include <boost/filesystem/fstream.hpp>
34 #include <boost/format.hpp>
35 #include <boost/function.hpp>
36 #include <boost/algorithm/string.hpp>
37 
38 #include "ConsoleLoggingSystem.h"
39 #include "LoggerProxy.h"
41 #include "../config/ConfigFileSource.h"
42 #include "../runtime/ContainerIO.h"
43 
44 using namespace std;
45 using namespace rsc::misc;
46 
47 namespace rsc {
48 namespace logging {
49 
50 const string LoggerFactory::DEFAULT_LOGGING_SYSTEM =
51  ConsoleLoggingSystem::getName();
52 const Logger::Level LoggerFactory::DEFAULT_LEVEL = Logger::LEVEL_WARN;
53 
58 public:
59 
67  public:
68 
69  LevelSetter(const Logger::Level& level) :
70  level(level) {
71  }
72 
73  virtual ~LevelSetter() {
74  }
75 
76  bool visit(const LoggerTreeNode::NamePath& /*path*/,
77  LoggerTreeNodePtr node, const Logger::Level& /*parentLevel*/) {
78 
79  if (node->getAssignedLevel()) {
80  return false;
81  }
82 
83  node->getLoggerProxy()->getLogger()->setLevel(level);
84 
85  return true;
86 
87  }
88 
89  private:
91  };
92 
94  boost::recursive_mutex& mutex) :
95  treeNode(treeNode), mutex(mutex) {
96  }
97 
98  virtual ~TreeLevelUpdater() {
99  }
100 
101  // TODO jwienke: maybe it would be better to make this signature contain the node instead of the proxy? Can this work?
102  void call(LoggerProxyPtr /*proxy*/, const Logger::Level& level) {
103  boost::recursive_mutex::scoped_lock lock(mutex);
104  LoggerTreeNodePtr node = treeNode.lock();
105  node->getLoggerProxy()->getLogger()->setLevel(level);
106  node->setAssignedLevel(level);
107  // TODO we ignore the path anyways... Can this be done by the tree itself?
108  node->visit(LoggerTreeNode::VisitorPtr(new LevelSetter(level)),
110  }
111 
112 private:
114  boost::recursive_mutex& mutex;
115 
116 };
117 
118 LoggerFactory::LoggerFactory() {
119  reselectLoggingSystem();
120  loggerTree.reset(new LoggerTreeNode("", LoggerTreeNodePtr()));
121  LoggerPtr logger(loggingSystem->createLogger(""));
122  LoggerProxyPtr proxy(
123  new LoggerProxy(
124  logger,
126  new TreeLevelUpdater(
127  LoggerTreeNodeWeakPtr(loggerTree),
128  mutex))));
129  loggerTree->setLoggerProxy(proxy);
130  // assign the initial level to the only logger available, which is the root logger
131  // by directly assigning the level to the proxied logger we prevent the
132  // callback mechanism from working uselessly
133  logger->setLevel(DEFAULT_LEVEL);
134  loggerTree->setAssignedLevel(DEFAULT_LEVEL);
135 }
136 
137 LoggerFactory::~LoggerFactory() {
138 }
139 
141 public:
142 
143  ReselectVisitor(boost::shared_ptr<LoggingSystem> newSystem) :
144  newSystem(newSystem) {
145  }
146 
148  const Logger::Level& /*parentLevel*/) {
149  const Logger::Level oldLevel =
150  node->getLoggerProxy()->getLogger()->getLevel();
151  node->getLoggerProxy()->setLogger(
152  newSystem->createLogger(LoggerTreeNode::pathToName(path)));
153  node->getLoggerProxy()->getLogger()->setLevel(oldLevel);
154  return true;
155  }
156 private:
157  boost::shared_ptr<LoggingSystem> newSystem;
158 };
159 
160 void LoggerFactory::reselectLoggingSystem(const std::string& nameHint) {
161 
162  set<string> keys = loggingSystemRegistry()->getKnownRegistryKeys();
163  assert(keys.count(DEFAULT_LOGGING_SYSTEM));
164 
165  string systemName;
166  if (nameHint == DEFAULT_LOGGING_SYSTEM) {
167  // use default if explicitly requested
168 
169  systemName = DEFAULT_LOGGING_SYSTEM;
170 
171  } else if (!nameHint.empty() && keys.count(nameHint)) {
172  // use hint if available
173 
174  systemName = nameHint;
175 
176  } else {
177  // auto-select fallback
178 
179  if (keys.size() > 1) {
180  // do not use default if other options are available
181  keys.erase(DEFAULT_LOGGING_SYSTEM);
182  }
183  systemName = *(keys.begin());
184 
185  }
186 
187  boost::recursive_mutex::scoped_lock lock(mutex);
188 
189  loggingSystem = loggingSystemRegistry()->getRegistree(systemName);
190 
191  // update existing loggers to use the new logging system
192  if (loggerTree) {
193  const Logger::Level oldLevel = loggerTree->getLoggerProxy()->getLevel();
194  loggerTree->getLoggerProxy()->setLogger(
195  loggingSystem->createLogger(""));
196  loggerTree->getLoggerProxy()->getLogger()->setLevel(oldLevel);
197  loggerTree->visit(
198  LoggerTreeNode::VisitorPtr(new ReselectVisitor(loggingSystem)));
199  }
200 
201 }
202 
203 LoggerProxyPtr LoggerFactory::createLogger(const LoggerTreeNode::NamePath& path,
204  LoggerTreeNodePtr node) {
205  LoggerPtr logger(
206  loggingSystem->createLogger(LoggerTreeNode::pathToName(path)));
207  LoggerProxyPtr proxy(
208  new LoggerProxy(
209  logger,
212  mutex))));
213  // new level can be derived from parent logger
214  logger->setLevel(
215  node->getParent()->getLoggerProxy()->getLogger()->getLevel());
216  return proxy;
217 }
218 
219 LoggerPtr LoggerFactory::getLogger(const string& name) {
220  boost::recursive_mutex::scoped_lock lock(mutex);
221  LoggerTreeNode::NamePath path = LoggerTreeNode::nameToPath(name);
222  if (path.empty()) {
223  return loggerTree->getLoggerProxy();
224  }
225  LoggerTreeNodePtr node = loggerTree->addChildren(path,
226  boost::bind(&LoggerFactory::createLogger, this, _1, _2));
227  return node->getLoggerProxy();
228 }
229 
231 public:
232 
234  newLevel(newLevel) {
235  }
236 
238  const Logger::Level& /*parentLevel*/) {
239  if (node->hasAssignedLevel()) {
240  node->setAssignedLevel(newLevel);
241  }
242  node->getLoggerProxy()->getLogger()->setLevel(newLevel);
243  return true;
244 
245  }
246 private:
248 };
249 
250 void LoggerFactory::reconfigure(const Logger::Level& level) {
251  boost::recursive_mutex::scoped_lock lock(mutex);
252  loggerTree->getLoggerProxy()->getLogger()->setLevel(level);
253  loggerTree->setAssignedLevel(level);
254  loggerTree->visit(
256 }
257 
258 string LoggerFactory::getLoggingSystemName() {
259  boost::recursive_mutex::scoped_lock lock(mutex);
260  return loggingSystem->getRegistryKey();
261 }
262 
263 void LoggerFactory::clearKnownLoggers() {
264  boost::recursive_mutex::scoped_lock lock(mutex);
265  loggerTree->clearChildren();
266 }
267 
268 void LoggerFactory::reconfigureFromFile(const string& fileName) {
269  OptionBasedConfigurator configurator;
270  boost::filesystem::ifstream stream(fileName);
271  if (!stream) {
272  throw invalid_argument("Unable to open file " + fileName);
273  }
274  config::ConfigFileSource(stream).provideOptions(configurator);
275 }
276 
277 }
278 }
boost::recursive_mutex & mutex
boost::shared_ptr< LoggerProxy > LoggerProxyPtr
Definition: LoggerProxy.h:112
Objects of this class parse streams that contain configuration information in "ini-file" syntax...
bool visit(const LoggerTreeNode::NamePath &path, LoggerTreeNodePtr node, const Logger::Level &)
Called for each node in the tree.
Visitor interface to operate on the tree.
bool visit(const LoggerTreeNode::NamePath &, LoggerTreeNodePtr node, const Logger::Level &)
Called for each node in the tree.
A simple tree representation for loggers.
void provideOptions(OptionHandler &handler)
Implementations should pass all configuration options to handler.
ReconfigurationVisitor(const Logger::Level &newLevel)
STL namespace.
A Visitor that propagates a logging level down the logger tree but stops if a logger already as a lev...
std::vector< std::string > NamePath
A unique representation of a name.
Level
Possible logging levels.
Definition: Logger.h:63
void call(LoggerProxyPtr, const Logger::Level &level)
boost::shared_ptr< LoggingSystem > newSystem
A proxy to an instance of Logger, which provides the same interface but allows to exchange the underl...
Definition: LoggerProxy.h:43
rsc::misc::Registry< LoggingSystem > * loggingSystemRegistry()
ReselectVisitor(boost::shared_ptr< LoggingSystem > newSystem)
LoggerPtr getLogger()
bool visit(const LoggerTreeNode::NamePath &, LoggerTreeNodePtr node, const Logger::Level &)
Called for each node in the tree.
boost::shared_ptr< SetLevelCallback > SetLevelCallbackPtr
Definition: LoggerProxy.h:63
LoggerTreeNodeWeakPtr treeNode
boost::shared_ptr< LoggerTreeNode > LoggerTreeNodePtr
LevelSetter(const Logger::Level &level)
boost::shared_ptr< Visitor > VisitorPtr
TreeLevelUpdater(LoggerTreeNodeWeakPtr treeNode, boost::recursive_mutex &mutex)
Interface for callbacks which are invoked when someone calls setLevel on this proxy.
Definition: LoggerProxy.h:57
A class which configures the logging tree using configuration subsystem of RSC.
boost::weak_ptr< LoggerTreeNode > LoggerTreeNodeWeakPtr
boost::shared_ptr< Logger > LoggerPtr
Definition: Logger.h:41