libqi-api  2.0.6.8
/home/opennao/work/master/sdk/libqi/qi/details/log.hxx
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines