libqi-api
2.0.6.8
|
00001 #pragma once 00002 /* 00003 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved. 00004 * Use of this source code is governed by a BSD-style license that can be 00005 * found in the COPYING file. 00006 */ 00007 00008 #ifndef _QI_DETAILS_LOG_HXX_ 00009 #define _QI_DETAILS_LOG_HXX_ 00010 00011 00012 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00013 # define _qiLogDebug(...) qi::log::LogStream(qi::LogLevel_Debug, "", __FUNCTION__, 0, __VA_ARGS__).self() 00014 #else 00015 # define _qiLogDebug(...) qi::log::LogStream(qi::LogLevel_Debug, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00016 #endif 00017 00018 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00019 # define _qiLogVerbose(...) qi::log::LogStream(qi::LogLevel_Verbose, "", __FUNCTION__, 0, __VA_ARGS__).self() 00020 #else 00021 # define _qiLogVerbose(...) qi::log::LogStream(qi::LogLevel_Verbose, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00022 #endif 00023 00024 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00025 # define _qiLogInfo(...) qi::log::LogStream(qi::LogLevel_Info, "", __FUNCTION__, 0, __VA_ARGS__).self() 00026 #else 00027 # define _qiLogInfo(...) qi::log::LogStream(qi::LogLevel_Info, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00028 #endif 00029 00030 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00031 # define _qiLogWarning(...) qi::log::LogStream(qi::LogLevel_Warning, "", __FUNCTION__, 0, __VA_ARGS__).self() 00032 #else 00033 # define _qiLogWarning(...) qi::log::LogStream(qi::LogLevel_Warning, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00034 #endif 00035 00036 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00037 # define _qiLogError(...) qi::log::LogStream(qi::LogLevel_Error, "", __FUNCTION__, 0, __VA_ARGS__).self() 00038 #else 00039 # define _qiLogError(...) qi::log::LogStream(qi::LogLevel_Error, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00040 #endif 00041 00042 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00043 # define _qiLogFatal(...) qi::log::LogStream(qi::LogLevel_Fatal, "", __FUNCTION__, 0, __VA_ARGS__).self() 00044 #else 00045 # define _qiLogFatal(...) qi::log::LogStream(qi::LogLevel_Fatal, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__).self() 00046 #endif 00047 00048 00049 # define _QI_FORMAT_ELEM(_, a, elem) % (elem) 00050 00051 # define _QI_LOG_FORMAT(Msg, ...) \ 00052 QI_CAT(_QI_LOG_FORMAT_HASARG_, _QI_LOG_ISEMPTY(__VA_ARGS__))(Msg, __VA_ARGS__) 00053 00054 #define _QI_LOG_FORMAT_HASARG_0(Msg, ...) \ 00055 boost::str(::qi::log::detail::getFormat(Msg) QI_VAARGS_APPLY(_QI_FORMAT_ELEM, _, __VA_ARGS__ )) 00056 00057 #define _QI_LOG_FORMAT_HASARG_1(Msg, ...) Msg 00058 00059 #define _QI_SECOND(a, ...) __VA_ARGS__ 00060 00061 /* For fast category access, we use lookup to a fixed name symbol. 00062 * The user is required to call qiLogCategory somewhere in scope. 00063 */ 00064 00065 # define _QI_LOG_CATEGORY_GET() _qi_log_category 00066 00067 #if defined(NO_QI_LOG_DETAILED_CONTEXT) || defined(NDEBUG) 00068 # define _QI_LOG_MESSAGE(Type, Message) \ 00069 do \ 00070 { \ 00071 if (::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type)) \ 00072 ::qi::log::log(::qi::Type, \ 00073 _QI_LOG_CATEGORY_GET(), \ 00074 Message, \ 00075 "", __FUNCTION__, 0); \ 00076 } \ 00077 while (false) 00078 #else 00079 # define _QI_LOG_MESSAGE(Type, Message) \ 00080 do \ 00081 { \ 00082 if (::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type)) \ 00083 ::qi::log::log(::qi::Type, \ 00084 _QI_LOG_CATEGORY_GET(), \ 00085 Message, \ 00086 __FILE__, __FUNCTION__, __LINE__); \ 00087 } \ 00088 while (false) 00089 #endif 00090 00091 /* Tricky, we do not want to hit category_get if a category is specified 00092 * Usual glitch of off-by-one list size: put argument 'TypeCased' in the vaargs 00093 * Basically we want variadic macro, but it does not exist, so emulate it using _QI_LOG_EMPTY. 00094 */ 00095 # define _QI_LOG_MESSAGE_STREAM(Type, TypeCased, ...) \ 00096 QI_CAT(_QI_LOG_MESSAGE_STREAM_HASCAT_, _QI_LOG_ISEMPTY( __VA_ARGS__))(Type, TypeCased, __VA_ARGS__) 00097 00098 // no extra argument 00099 #define _QI_LOG_MESSAGE_STREAM_HASCAT_1(Type, TypeCased, ...) \ 00100 ::qi::log::detail::isVisible(_QI_LOG_CATEGORY_GET(), ::qi::Type) \ 00101 && BOOST_PP_CAT(_qiLog, TypeCased)(_QI_LOG_CATEGORY_GET()) 00102 00103 // Visual bouncer for macro evalution order glitch. 00104 #ifdef _MSC_VER 00105 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0(...) QI_DELAY(_QI_LOG_MESSAGE_STREAM_HASCAT_0) ## _BOUNCE(__VA_ARGS__) 00106 #else 00107 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0(...) _QI_LOG_MESSAGE_STREAM_HASCAT_0_BOUNCE(__VA_ARGS__) 00108 #endif 00109 00110 // At leas one argument: category. Check for a format argument 00111 #define _QI_LOG_MESSAGE_STREAM_HASCAT_0_BOUNCE(Type, TypeCased, cat, ...) \ 00112 QI_CAT(_QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_, _QI_LOG_ISEMPTY( __VA_ARGS__))(Type, TypeCased, cat, __VA_ARGS__) 00113 00114 00115 // No format argument 00116 #define _QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_1(Type, TypeCased, cat, ...) \ 00117 BOOST_PP_CAT(_qiLog,TypeCased)(cat) 00118 00119 // Format argument 00120 #define _QI_LOG_MESSAGE_STREAM_HASCAT_HASFORMAT_0(Type, TypeCased, cat, ...) \ 00121 BOOST_PP_CAT(_qiLog, TypeCased)(cat, _QI_LOG_FORMAT(__VA_ARGS__)) 00122 00123 00124 /* Detecting empty arg is tricky. 00125 * Trick 1 below does not work with gcc, because x ## "foo" produces a preprocessor error. 00126 * Trick 2 rely on ##__VA_ARGS__ 00127 */ 00128 #ifdef _MSC_VER 00129 00130 #define _WQI_IS_EMPTY_HELPER___ a,b 00131 #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), _))))) 00132 00133 #define _QI_FIRST_ARG(a, ...) a 00134 #define _QI_LOG_ISEMPTY(...) WQI_IS_EMPTY(QI_CAT_18(_, _QI_FIRST_ARG(__VA_ARGS__, 12))) 00135 00136 #else 00137 00138 #define _QI_LOG_REVERSE 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 00139 #define _QI_LOG_REVERSEEMPTY 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 00140 #define _QI_LOG_ARGN(a, b, c, d, e, f, g, h, i, N, ...) N 00141 #define _QI_LOG_NARG_(dummy, ...) _QI_LOG_ARGN(__VA_ARGS__) 00142 #define _QI_LOG_NARG(...) _QI_LOG_NARG_(dummy, ##__VA_ARGS__, _QI_LOG_REVERSE) 00143 #define _QI_LOG_ISEMPTY(...) _QI_LOG_NARG_(dummy, ##__VA_ARGS__, _QI_LOG_REVERSEEMPTY) 00144 00145 #endif 00146 00147 namespace qi { 00148 namespace log{ 00149 namespace detail { 00150 00151 // Used to remove warning "statement has no effect" 00152 inline bool qiFalse() {return false;} 00153 00154 class NullStream { 00155 public: 00156 NullStream(...) 00157 { 00158 } 00159 00160 NullStream &self() 00161 { 00162 return *this; 00163 } 00164 template <typename T> 00165 NullStream& operator<<(const T &QI_UNUSED(val)) 00166 { 00167 return self(); 00168 } 00169 00170 NullStream& operator<<(std::ostream& (*QI_UNUSED(f))(std::ostream&)) 00171 { 00172 return self(); 00173 } 00174 }; 00175 00176 // Hack required to silence spurious warning in compile-time disabled macros 00177 // We need an operator with priority below << and above && 00178 inline bool operator<(bool b, const NullStream& ns) 00179 { 00180 return false; 00181 } 00182 00183 struct Category 00184 { 00185 Category() 00186 : maxLevel(qi::LogLevel_Silent) 00187 {} 00188 00189 Category(const std::string &name) 00190 : name(name) 00191 , maxLevel(qi::LogLevel_Silent) 00192 {} 00193 00194 std::string name; 00195 qi::LogLevel maxLevel; //max level among all subscribers 00196 std::vector<qi::LogLevel> levels; //level by subscribers 00197 00198 void setLevel(SubscriberId sub, qi::LogLevel level); 00199 }; 00200 00201 QI_API boost::format getFormat(const std::string& s); 00202 00203 //inlined for perf 00204 inline bool isVisible(Category* category, qi::LogLevel level) 00205 { 00206 return category && level <= category->maxLevel; 00207 } 00208 } 00209 00210 typedef detail::Category* CategoryType; 00211 class LogStream: public std::stringstream 00212 { 00213 public: 00214 LogStream(const qi::LogLevel level, 00215 const char *file, 00216 const char *function, 00217 const int line, 00218 const char *category) 00219 : _logLevel(level) 00220 , _category(category) 00221 , _categoryType(0) 00222 , _file(file) 00223 , _function(function) 00224 , _line(line) 00225 { 00226 } 00227 LogStream(const qi::LogLevel level, 00228 const char *file, 00229 const char *function, 00230 const int line, 00231 CategoryType category) 00232 : _logLevel(level) 00233 , _category(0) 00234 , _categoryType(category) 00235 , _file(file) 00236 , _function(function) 00237 , _line(line) 00238 { 00239 } 00240 LogStream(const qi::LogLevel level, 00241 const char *file, 00242 const char *function, 00243 const int line, 00244 const char *category, 00245 const std::string& message) 00246 : _logLevel(level) 00247 , _category(category) 00248 , _categoryType(0) 00249 , _file(file) 00250 , _function(function) 00251 , _line(line) 00252 { 00253 *this << message; 00254 } 00255 00256 ~LogStream() 00257 { 00258 if (_category) 00259 qi::log::log(_logLevel, _category, this->str().c_str(), _file, _function, _line); 00260 else 00261 qi::log::log(_logLevel, _categoryType, this->str(), _file, _function, _line); 00262 } 00263 00264 LogStream& self() { 00265 return *this; 00266 } 00267 00268 private: 00269 qi::LogLevel _logLevel; 00270 const char *_category; 00271 CategoryType _categoryType; 00272 const char *_file; 00273 const char *_function; 00274 int _line; 00275 00276 //avoid copy 00277 LogStream(const LogStream &rhs); 00278 LogStream &operator=(const LogStream &rhs); 00279 }; 00280 } 00281 } 00282 00283 #endif // _QI_DETAILS_LOG_HXX_