libqi-api  2.1.4.13
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
log.hxx
Go to the documentation of this file.
1 #pragma once
2 /*
3  * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the COPYING file.
6  */
7 
8 #ifndef _QI_DETAILS_LOG_HXX_
9 #define _QI_DETAILS_LOG_HXX_
10 
11 
12 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
13 # define _qiLogDebug(...) qi::log::LogStream(qi::LogLevel_Debug, "", __FUNCTION__, 0, __VA_ARGS__).self()
14 #else
15 # define _qiLogDebug(...) qi::log::LogStream(qi::LogLevel_Debug, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
16 #endif
17 
18 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
19 # define _qiLogVerbose(...) qi::log::LogStream(qi::LogLevel_Verbose, "", __FUNCTION__, 0, __VA_ARGS__).self()
20 #else
21 # define _qiLogVerbose(...) qi::log::LogStream(qi::LogLevel_Verbose, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
22 #endif
23 
24 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
25 # define _qiLogInfo(...) qi::log::LogStream(qi::LogLevel_Info, "", __FUNCTION__, 0, __VA_ARGS__).self()
26 #else
27 # define _qiLogInfo(...) qi::log::LogStream(qi::LogLevel_Info, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
28 #endif
29 
30 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
31 # define _qiLogWarning(...) qi::log::LogStream(qi::LogLevel_Warning, "", __FUNCTION__, 0, __VA_ARGS__).self()
32 #else
33 # define _qiLogWarning(...) qi::log::LogStream(qi::LogLevel_Warning, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
34 #endif
35 
36 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
37 # define _qiLogError(...) qi::log::LogStream(qi::LogLevel_Error, "", __FUNCTION__, 0, __VA_ARGS__).self()
38 #else
39 # define _qiLogError(...) qi::log::LogStream(qi::LogLevel_Error, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
40 #endif
41 
42 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
43 # define _qiLogFatal(...) qi::log::LogStream(qi::LogLevel_Fatal, "", __FUNCTION__, 0, __VA_ARGS__).self()
44 #else
45 # define _qiLogFatal(...) qi::log::LogStream(qi::LogLevel_Fatal, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self()
46 #endif
47 
48 
49 # define _QI_FORMAT_ELEM(_, a, elem) % (elem)
50 
51 # define _QI_LOG_FORMAT(Msg, ...) \
52  QI_CAT(_QI_LOG_FORMAT_HASARG_, _QI_LOG_ISEMPTY(__VA_ARGS__))(Msg, __VA_ARGS__)
53 
54 #define _QI_LOG_FORMAT_HASARG_0(Msg, ...) \
55  boost::str(::qi::log::detail::getFormat(Msg) QI_VAARGS_APPLY(_QI_FORMAT_ELEM, _, __VA_ARGS__ ))
56 
57 #define _QI_LOG_FORMAT_HASARG_1(Msg, ...) Msg
58 
59 #define _QI_SECOND(a, ...) __VA_ARGS__
60 
61 /* For fast category access, we use lookup to a fixed name symbol.
62  * The user is required to call qiLogCategory somewhere in scope.
63  */
64 
65 # define _QI_LOG_CATEGORY_GET() _qi_log_category
66 
67 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG)
68 # define _QI_LOG_MESSAGE(Type, Message) \
69  do \
70  { \
71  if (::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type)) \
72  ::qi::log::log(::qi::Type, \
73  _QI_LOG_CATEGORY_GET(), \
74  Message, \
75  "", __FUNCTION__, 0); \
76  } \
77  while (false)
78 #else
79 # define _QI_LOG_MESSAGE(Type, Message) \
80  do \
81  { \
82  if (::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type)) \
83  ::qi::log::log(::qi::Type, \
84  _QI_LOG_CATEGORY_GET(), \
85  Message, \
86  __FILE__, __FUNCTION__, __LINE__); \
87  } \
88  while (false)
89 #endif
90 
91 /* Tricky, we do not want to hit category_get if a category is specified
92 * Usual glitch of off-by-one list size: put argument 'TypeCased' in the vaargs
93 * Basically we want variadic macro, but it does not exist, so emulate it using _QI_LOG_EMPTY.
94 */
95 # define _QI_LOG_MESSAGE_STREAM(Type, TypeCased, ...) \
96  QI_CAT(_QI_LOG_MESSAGE_STREAM_HASCAT_, _QI_LOG_ISEMPTY( __VA_ARGS__))(Type, TypeCased, __VA_ARGS__)
97 
98 // no extra argument
99 #define _QI_LOG_MESSAGE_STREAM_HASCAT_1(Type, TypeCased, ...) \
100  ::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type) \
101  && BOOST_PP_CAT(_qiLog, TypeCased)(_QI_LOG_CATEGORY_GET())
102 
103 // Visual bouncer for macro evalution order glitch.
104 #ifdef _MSC_VER
105 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0(...) QI_DELAY(_QI_LOG_MESSAGE_STREAM_HASCAT_0) ## _BOUNCE(__VA_ARGS__)
106 #else
107 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0(...) _QI_LOG_MESSAGE_STREAM_HASCAT_0_BOUNCE(__VA_ARGS__)
108 #endif
109 
110 // At leas one argument: category. Check for a format argument
111 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0_BOUNCE(Type, TypeCased, cat, ...) \
112  QI_CAT(_QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_, _QI_LOG_ISEMPTY( __VA_ARGS__))(Type, TypeCased, cat, __VA_ARGS__)
113 
114 
115 // No format argument
116 #define _QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_1(Type, TypeCased, cat, ...) \
117  BOOST_PP_CAT(_qiLog,TypeCased)(cat)
118 
119 // Format argument
120 #define _QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_0(Type, TypeCased, cat, ...) \
121  BOOST_PP_CAT(_qiLog, TypeCased)(cat, _QI_LOG_FORMAT(__VA_ARGS__))
122 
123 
124 /* Detecting empty arg is tricky.
125  * Trick 1 below does not work with gcc, because x ## "foo" produces a preprocessor error.
126  * Trick 2 rely on ##__VA_ARGS__
127 */
128 #ifdef _MSC_VER
129 
130 #define _WQI_IS_EMPTY_HELPER___ a,b
131 #define WQI_IS_EMPTY(a,...) QI_CAT_20(QI_LIST_VASIZE,((QI_CAT_22(_WQI_IS_EMPTY_HELPER, QI_CAT_24(QI_CAT_26(_, a), _)))))
132 
133 #define _QI_FIRST_ARG(a, ...) a
134 #define _QI_LOG_ISEMPTY(...) WQI_IS_EMPTY(QI_CAT_18(_, _QI_FIRST_ARG(__VA_ARGS__, 12)))
135 
136 #else
137 
138 #define _QI_LOG_REVERSE 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0
139 #define _QI_LOG_REVERSEEMPTY 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1
140 #define _QI_LOG_ARGN(a, b, c, d, e, f, g, h, i, N, ...) N
141 #define _QI_LOG_NARG_(dummy, ...) _QI_LOG_ARGN(__VA_ARGS__)
142 #define _QI_LOG_NARG(...) _QI_LOG_NARG_(dummy, ##__VA_ARGS__, _QI_LOG_REVERSE)
143 #define _QI_LOG_ISEMPTY(...) _QI_LOG_NARG_(dummy, ##__VA_ARGS__, _QI_LOG_REVERSEEMPTY)
144 
145 #endif
146 
147 namespace qi {
148  namespace log{
149  namespace detail {
150 
151  // Used to remove warning "statement has no effect"
152  inline bool qiFalse() {return false;}
153 
154  class NullStream {
155  public:
156  NullStream(...)
157  {
158  }
159 
160  NullStream &self()
161  {
162  return *this;
163  }
164  template <typename T>
165  NullStream& operator<<(const T &QI_UNUSED(val))
166  {
167  return self();
168  }
169 
170  NullStream& operator<<(std::ostream& (*QI_UNUSED(f))(std::ostream&))
171  {
172  return self();
173  }
174  };
175 
176  // Hack required to silence spurious warning in compile-time disabled macros
177  // We need an operator with priority below << and above &&
178  inline bool operator<(bool b, const NullStream& ns)
179  {
180  return false;
181  }
182 
183  struct Category
184  {
185  Category()
186  : maxLevel(qi::LogLevel_Silent)
187  {}
188 
189  Category(const std::string &name)
190  : name(name)
191  , maxLevel(qi::LogLevel_Silent)
192  {}
193 
194  std::string name;
195  qi::LogLevel maxLevel; //max level among all subscribers
196  std::vector<qi::LogLevel> levels; //level by subscribers
197 
198  void setLevel(SubscriberId sub, qi::LogLevel level);
199  };
200 
201  QI_API boost::format getFormat(const std::string& s);
202 
203  //inlined for perf
204  inline bool isVisible(Category* category, qi::LogLevel level)
205  {
206  return category && level <= category->maxLevel;
207  }
208  }
209 
210  typedef detail::Category* CategoryType;
211  class LogStream: public std::stringstream
212  {
213  public:
214  LogStream(const qi::LogLevel level,
215  const char *file,
216  const char *function,
217  const int line,
218  const char *category)
219  : _logLevel(level)
220  , _category(category)
221  , _categoryType(0)
222  , _file(file)
223  , _function(function)
224  , _line(line)
225  {
226  }
227  LogStream(const qi::LogLevel level,
228  const char *file,
229  const char *function,
230  const int line,
231  CategoryType category)
232  : _logLevel(level)
233  , _category(0)
234  , _categoryType(category)
235  , _file(file)
236  , _function(function)
237  , _line(line)
238  {
239  }
240  LogStream(const qi::LogLevel level,
241  const char *file,
242  const char *function,
243  const int line,
244  const char *category,
245  const std::string& message)
246  : _logLevel(level)
247  , _category(category)
248  , _categoryType(0)
249  , _file(file)
250  , _function(function)
251  , _line(line)
252  {
253  *this << message;
254  }
255 
257  {
258  if (_category)
259  qi::log::log(_logLevel, _category, this->str().c_str(), _file, _function, _line);
260  else
261  qi::log::log(_logLevel, _categoryType, this->str(), _file, _function, _line);
262  }
263 
264  LogStream& self() {
265  return *this;
266  }
267 
268  private:
269  qi::LogLevel _logLevel;
270  const char *_category;
271  CategoryType _categoryType;
272  const char *_file;
273  const char *_function;
274  int _line;
275 
276  //avoid copy
277  LogStream(const LogStream &rhs);
278  LogStream &operator=(const LogStream &rhs);
279  };
280  }
281 }
282 
283 #endif // _QI_DETAILS_LOG_HXX_
void log(const qi::LogLevel verb, const char *category, const char *msg, const char *file="", const char *fct="", const int line=0)
Log function. You should call qiLog* macros instead.
boost::format getFormat(const std::string &s)
LogStream(const qi::LogLevel level, const char *file, const char *function, const int line, CategoryType category)
Definition: log.hxx:227
silent log level
Definition: log.hpp:85
detail::Category * CategoryType
Definition: log.hxx:210
unsigned int SubscriberId
Definition: log.hpp:136
bool isVisible(Category *category, qi::LogLevel level)
Definition: log.hxx:204
bool qiFalse()
Definition: log.hxx:152
Each log macro creates a LogStream object.
Definition: log.hxx:211
LogStream(const qi::LogLevel level, const char *file, const char *function, const int line, const char *category)
LogStream. Will log at object destruction.
Definition: log.hxx:214
LogLevel
Log level verbosity.
Definition: log.hpp:84
~LogStream()
LogStream destructor.
Definition: log.hxx:256
bool operator<(bool b, const NullStream &ns)
Definition: log.hxx:178
#define QI_UNUSED(x)
This macro tags a parameter as unused.
Definition: macro.hpp:158
LogStream(const qi::LogLevel level, const char *file, const char *function, const int line, const char *category, const std::string &message)
Definition: log.hxx:240
#define QI_API
Definition: api.hpp:24
std::ostream & operator<<(std::ostream &os, qi::StreamColor col)