rosconsole_log4cxx.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 // Author: Josh Faust
31 
32 #if defined(__APPLE__) && defined(__GNUC__) && defined(__llvm__) && !defined(__clang__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
33 #error This code is known to provoke a compiler crash with llvm-gcc 4.2. You will have better luck with clang++. See code.ros.org/trac/ros/ticket/3626
34 #endif
35 
36 #include "ros/console.h"
37 #include "ros/assert.h"
38 #include <ros/time.h>
39 #include "log4cxx/appenderskeleton.h"
40 #include "log4cxx/spi/loggingevent.h"
41 #include "log4cxx/level.h"
42 #include "log4cxx/propertyconfigurator.h"
43 #ifdef _MSC_VER
44  // Have to be able to encode wchar LogStrings on windows.
45  #include "log4cxx/helpers/transcoder.h"
46 #endif
47 
48 #include <boost/thread.hpp>
49 #include <boost/shared_array.hpp>
50 #include <boost/regex.hpp>
51 
52 #include <cstdarg>
53 #include <cstdlib>
54 #include <cstdio>
55 #include <memory>
56 #include <cstring>
57 #include <stdexcept>
58 
59 namespace ros
60 {
61 namespace console
62 {
63 namespace impl
64 {
65 
66 log4cxx::LevelPtr g_level_lookup[ levels::Count ] =
67 {
68  log4cxx::Level::getDebug(),
69  log4cxx::Level::getInfo(),
70  log4cxx::Level::getWarn(),
71  log4cxx::Level::getError(),
72  log4cxx::Level::getFatal(),
73 };
74 
75 
76 class ROSConsoleStdioAppender : public log4cxx::AppenderSkeleton
77 {
78 public:
80  {
81  }
82 
83 protected:
84  virtual void append(const log4cxx::spi::LoggingEventPtr& event,
85  log4cxx::helpers::Pool&)
86  {
88  if (event->getLevel() == log4cxx::Level::getDebug())
89  {
90  level = levels::Debug;
91  }
92  else if (event->getLevel() == log4cxx::Level::getInfo())
93  {
94  level = levels::Info;
95  }
96  else if (event->getLevel() == log4cxx::Level::getWarn())
97  {
98  level = levels::Warn;
99  }
100  else if (event->getLevel() == log4cxx::Level::getError())
101  {
102  level = levels::Error;
103  }
104  else if (event->getLevel() == log4cxx::Level::getFatal())
105  {
106  level = levels::Fatal;
107  }
108 #ifdef _MSC_VER
109  LOG4CXX_ENCODE_CHAR(tmpstr, event->getMessage()); // has to handle LogString with wchar types.
110  std::string msg = tmpstr // tmpstr gets instantiated inside the LOG4CXX_ENCODE_CHAR macro
111 #else
112  std::string msg = event->getMessage();
113 #endif
114  const log4cxx::spi::LocationInfo& location_info = event->getLocationInformation();
115  ::ros::console::backend::print(event.operator->(), level, msg.c_str(), location_info.getFileName(), location_info.getMethodName().c_str(), location_info.getLineNumber());
116  }
117 
118  virtual void close()
119  {
120  }
121  virtual bool requiresLayout() const
122  {
123  return false;
124  }
125 };
126 
127 void initialize()
128 {
129  // First set up some sane defaults programmatically.
130  log4cxx::LoggerPtr ros_logger = log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME);
131  ros_logger->setLevel(log4cxx::Level::getInfo());
132 
133  log4cxx::LoggerPtr roscpp_superdebug = log4cxx::Logger::getLogger("ros.roscpp.superdebug");
134  roscpp_superdebug->setLevel(log4cxx::Level::getWarn());
135 
136  // Next try to load the default config file from ROS_ROOT/config/rosconsole.config
137  char* ros_root_cstr = NULL;
138 #ifdef _MSC_VER
139  _dupenv_s(&ros_root_cstr, NULL, "ROS_ROOT");
140 #else
141  ros_root_cstr = getenv("ROS_ROOT");
142 #endif
143  if (ros_root_cstr)
144  {
145  std::string config_file = std::string(ros_root_cstr) + "/config/rosconsole.config";
146  FILE* config_file_ptr = fopen( config_file.c_str(), "r" );
147  if( config_file_ptr ) // only load it if the file exists, to avoid a warning message getting printed.
148  {
149  fclose( config_file_ptr );
150  log4cxx::PropertyConfigurator::configure(config_file);
151  }
152  }
153  char* config_file_cstr = NULL;
154 #ifdef _MSC_VER
155  _dupenv_s(&config_file_cstr, NULL, "ROSCONSOLE_CONFIG_FILE");
156 #else
157  config_file_cstr = getenv("ROSCONSOLE_CONFIG_FILE");
158 #endif
159  if ( config_file_cstr )
160  {
161  std::string config_file = config_file_cstr;
162  log4cxx::PropertyConfigurator::configure(config_file);
163  }
164 
165  log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME);
166  logger->addAppender(new ROSConsoleStdioAppender);
167 #ifdef _MSC_VER
168  if ( ros_root_cstr != NULL ) {
169  free(ros_root_cstr);
170  }
171  if ( config_file_cstr != NULL ) {
172  free(config_file_cstr);
173  }
174  if ( format_string != NULL ) {
175  free(format_string);
176  }
177  // getenv implementations don't need free'ing.
178 #endif
179 }
180 
181 
182 void print(void* handle, ::ros::console::Level level, const char* str, const char* file, const char* function, int line)
183 {
184  log4cxx::Logger* logger = (log4cxx::Logger*)handle;
185  try
186  {
187  logger->forcedLog(g_level_lookup[level], str, log4cxx::spi::LocationInfo(file, function, line));
188  }
189  catch (std::exception& e)
190  {
191  fprintf(stderr, "Caught exception while logging: [%s]\n", e.what());
192  }
193 }
194 
195 bool isEnabledFor(void* handle, ::ros::console::Level level)
196 {
197  log4cxx::Logger* logger = (log4cxx::Logger*)handle;
198  return logger->isEnabledFor(g_level_lookup[level]);
199 }
200 
201 void* getHandle(const std::string& name)
202 {
203  return log4cxx::Logger::getLogger(name);
204 }
205 
206 std::string getName(void* handle)
207 {
208  const log4cxx::spi::LoggingEvent* event = (const log4cxx::spi::LoggingEvent*)handle;
209 #ifdef _MSC_VER
210  LOG4CXX_ENCODE_CHAR(tmpstr, event->getLoggerName()); // has to handle LogString with wchar types.
211  return tmpstr // tmpstr gets instantiated inside the LOG4CXX_ENCODE_CHAR macro
212 #else
213  return event->getLoggerName();
214 #endif
215 }
216 
217 bool get_loggers(std::map<std::string, levels::Level>& loggers)
218 {
219  log4cxx::spi::LoggerRepositoryPtr repo = log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME)->getLoggerRepository();
220 
221  log4cxx::LoggerList current_loggers = repo->getCurrentLoggers();
222  log4cxx::LoggerList::iterator it = current_loggers.begin();
223  log4cxx::LoggerList::iterator end = current_loggers.end();
224  for (; it != end; ++it)
225  {
226  std::string name;
227  #ifdef _MSC_VER
228  LOG4CXX_ENCODE_CHAR(name, (*it)->getName()); // has to handle LogString with wchar types.
229  #else
230  name = (*it)->getName();
231  #endif
232 
233  const log4cxx::LevelPtr& log4cxx_level = (*it)->getEffectiveLevel();
234  levels::Level level;
235  if (log4cxx_level == log4cxx::Level::getDebug())
236  {
237  level = levels::Debug;
238  }
239  else if (log4cxx_level == log4cxx::Level::getInfo())
240  {
241  level = levels::Info;
242  }
243  else if (log4cxx_level == log4cxx::Level::getWarn())
244  {
245  level = levels::Warn;
246  }
247  else if (log4cxx_level == log4cxx::Level::getError())
248  {
249  level = levels::Error;
250  }
251  else if (log4cxx_level == log4cxx::Level::getFatal())
252  {
253  level = levels::Fatal;
254  }
255  else
256  {
257  return false;
258  }
259  loggers[name] = level;
260  }
261 
262  return true;
263 }
264 
265 bool set_logger_level(const std::string& name, levels::Level level)
266 {
267  log4cxx::LevelPtr log4cxx_level;
268  if (level == levels::Debug)
269  {
270  log4cxx_level = log4cxx::Level::getDebug();
271  }
272  else if (level == levels::Info)
273  {
274  log4cxx_level = log4cxx::Level::getInfo();
275  }
276  else if (level == levels::Warn)
277  {
278  log4cxx_level = log4cxx::Level::getWarn();
279  }
280  else if (level == levels::Error)
281  {
282  log4cxx_level = log4cxx::Level::getError();
283  }
284  else if (level == levels::Fatal)
285  {
286  log4cxx_level = log4cxx::Level::getFatal();
287  }
288  else
289  {
290  return false;
291  }
292 
293  log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(name);
294  logger->setLevel(log4cxx_level);
296  return true;
297 }
298 
299 class Log4cxxAppender : public log4cxx::AppenderSkeleton
300 {
301 public:
302  Log4cxxAppender(ros::console::LogAppender* appender) : appender_(appender) {}
304 
305 protected:
306  virtual void append(const log4cxx::spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool)
307  {
308  (void)pool;
309  levels::Level level;
310  if (event->getLevel() == log4cxx::Level::getFatal())
311  {
312  level = levels::Fatal;
313  }
314  else if (event->getLevel() == log4cxx::Level::getError())
315  {
316  level = levels::Error;
317  }
318  else if (event->getLevel() == log4cxx::Level::getWarn())
319  {
320  level = levels::Warn;
321  }
322  else if (event->getLevel() == log4cxx::Level::getInfo())
323  {
324  level = levels::Info;
325  }
326  else if (event->getLevel() == log4cxx::Level::getDebug())
327  {
328  level = levels::Debug;
329  }
330  else
331  {
332  return;
333  }
334 
335  #ifdef _MSC_VER
336  LOG4CXX_ENCODE_CHAR(tmpstr, event->getMessage()); // has to handle LogString with wchar types.
337  std::string msg = tmpstr // tmpstr gets instantiated inside the LOG4CXX_ENCODE_CHAR macro
338  #else
339  std::string msg = event->getMessage();
340  #endif
341 
342  const log4cxx::spi::LocationInfo& info = event->getLocationInformation();
343  appender_->log(level, msg.c_str(), info.getFileName(), info.getMethodName().c_str(), info.getLineNumber());
344  }
345 
346  virtual void close() {}
347  virtual bool requiresLayout() const { return false; }
349 };
350 
352 
353 void register_appender(LogAppender* appender)
354 {
355  g_log4cxx_appender = new Log4cxxAppender(appender);
356  const log4cxx::LoggerPtr& logger = log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME);
357  logger->addAppender(g_log4cxx_appender);
358 }
359 
360 void shutdown()
361 {
362  const log4cxx::LoggerPtr& logger = log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME);
363  logger->removeAppender(g_log4cxx_appender);
364  g_log4cxx_appender = 0;
365  // reset this so that the logger doesn't get crashily destroyed
366  // again during global destruction.
367  //
368  // See https://code.ros.org/trac/ros/ticket/3271
369  //
370  log4cxx::Logger::getRootLogger()->getLoggerRepository()->shutdown();
371 }
372 
373 } // namespace impl
374 } // namespace console
375 } // namespace ros
log4cxx::LevelPtr g_level_lookup[levels::Count]
void print(void *handle,::ros::console::Level level, const char *str, const char *file, const char *function, int line)
ROSCONSOLE_DECL void notifyLoggerLevelsChanged()
Tells the system that a logger&#39;s level has changed.
Definition: rosconsole.cpp:661
virtual void append(const log4cxx::spi::LoggingEventPtr &event, log4cxx::helpers::Pool &)
std::string getName(void *handle)
ros::console::LogAppender * appender_
#define ROSCONSOLE_ROOT_LOGGER_NAME
Definition: console.h:297
void register_appender(LogAppender *appender)
bool get_loggers(std::map< std::string, levels::Level > &loggers)
bool set_logger_level(const std::string &name, levels::Level level)
virtual void append(const log4cxx::spi::LoggingEventPtr &event, log4cxx::helpers::Pool &pool)
Log4cxxAppender(ros::console::LogAppender *appender)
bool isEnabledFor(void *handle,::ros::console::Level level)
Log4cxxAppender * g_log4cxx_appender
void * getHandle(const std::string &name)
void print(ros::console::Level level, const std::string &s)
Definition: example.cpp:38


rosconsole
Author(s): Josh Faust
autogenerated on Mon Nov 2 2020 03:52:16