- Aldebaran documentation |
- C++ Libraries |
- index

libqi-api 2.8.7.4

- Main Page
- Related Pages
- Namespaces
- Classes
- Files
- Examples

- File List
- File Members

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