00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef XAPIAN_INCLUDED_DEBUGLOG_H
00022 #define XAPIAN_INCLUDED_DEBUGLOG_H
00023
00024 #ifdef XAPIAN_DEBUG_LOG
00025
00026 #include "output.h"
00027 #include "pretty.h"
00028
00029 #include <cstring>
00030 #include <ostream>
00031 #include <sstream>
00032 #include <string>
00033
00035 enum debuglog_categories {
00036
00037 DEBUGLOG_CATEGORY_NEVER = 0,
00038
00040 DEBUGLOG_CATEGORY_API = ('A' - '@'),
00041
00043 DEBUGLOG_CATEGORY_DB = ('D' - '@'),
00044
00046 DEBUGLOG_CATEGORY_EXCEPTION = ('X' - '@'),
00047
00049 DEBUGLOG_CATEGORY_EXPAND = ('E' - '@'),
00050
00052 DEBUGLOG_CATEGORY_MATCH = ('M' - '@'),
00053
00055 DEBUGLOG_CATEGORY_QUERYPARSER = ('Q' - '@'),
00056
00058 DEBUGLOG_CATEGORY_REMOTE = ('R' - '@'),
00059
00061 DEBUGLOG_CATEGORY_REPLICA = ('C' - '@'),
00062
00064 DEBUGLOG_CATEGORY_SPELLING = ('S' - '@'),
00065
00067 DEBUGLOG_CATEGORY_UNKNOWN = ('U' - '@'),
00068
00070 DEBUGLOG_CATEGORY_WTCALC = ('W' - '@'),
00071
00073 DEBUGLOG_CATEGORY_ALWAYS = 31
00074 };
00075
00076
00077
00079 class DebugLogger {
00081 void operator=(const DebugLogger &);
00082
00084 DebugLogger(const DebugLogger &);
00085
00087 unsigned int categories_mask;
00088
00090 int fd;
00091
00093 int indent_level;
00094
00096 void initialise_categories_mask();
00097
00098 public:
00100 DebugLogger()
00101 : categories_mask(1 << DEBUGLOG_CATEGORY_API), fd(-1), indent_level(0)
00102 { }
00103
00105 ~DebugLogger();
00106
00108 bool is_category_wanted(debuglog_categories category) {
00109
00110
00111
00112 if (category == DEBUGLOG_CATEGORY_ALWAYS) return true;
00113 if (category == DEBUGLOG_CATEGORY_NEVER) return false;
00114 if (fd == -1) initialise_categories_mask();
00115 return (categories_mask >> category) & 1;
00116 }
00117
00119 void log_line(debuglog_categories category, const std::string & msg);
00120
00121 void indent() { ++indent_level; }
00122
00123 void outdent() {
00124 if (indent_level) --indent_level;
00125 }
00126 };
00127
00128 namespace Xapian {
00134 typedef enum { NO_ARGS } NoArguments_;
00135 }
00136
00137 inline std::ostream & operator<<(std::ostream &o, Xapian::NoArguments_) {
00138 return o;
00139 }
00140
00141 using Xapian::NO_ARGS;
00142
00143 extern DebugLogger xapian_debuglogger_;
00144
00146
00147 #define LOGLINE_ALWAYS_(CATEGORY, MSG) do { \
00148 std::ostringstream xapian_debuglog_ostream_; \
00149 xapian_debuglog_ostream_ << MSG; \
00150 xapian_debuglogger_.log_line(CATEGORY, xapian_debuglog_ostream_.str()); \
00151 } while (false)
00152
00154
00155 #define LOGLINE_(CATEGORY, MSG) do { \
00156 debuglog_categories xapian_debuglog_category_ = (CATEGORY); \
00157 if (xapian_debuglogger_.is_category_wanted(xapian_debuglog_category_)) { \
00158 LOGLINE_ALWAYS_(xapian_debuglog_category_, MSG); \
00159 } \
00160 } while (false)
00161
00171 class DebugLogFunc {
00173 const void * this_ptr;
00174
00176 debuglog_categories category;
00177
00179 std::string func;
00180
00182 bool uncaught_exception;
00183
00184 public:
00186 DebugLogFunc(const void * this_ptr_, debuglog_categories category_,
00187 const char * return_type, const char * func_name,
00188 const std::string & params)
00189 : this_ptr(this_ptr_), category(category_),
00190 uncaught_exception(std::uncaught_exception())
00191 {
00192 if (is_category_wanted()) {
00193 func.assign(return_type);
00194 func += ' ';
00195 func += func_name;
00196 func += '(';
00197 func += params;
00198 func += ')';
00199 LOGLINE_ALWAYS_(category, '[' << this_ptr << "] " << func);
00200 xapian_debuglogger_.indent();
00201 }
00202 }
00203
00205 void log_return_value(const std::string & return_value) {
00206 xapian_debuglogger_.outdent();
00207 LOGLINE_(category, '[' << this_ptr << "] " << func << " returned: " <<
00208 return_value);
00209
00210
00211 category = DEBUGLOG_CATEGORY_NEVER;
00212 }
00213
00215 bool is_category_wanted() const {
00216 return xapian_debuglogger_.is_category_wanted(category);
00217 }
00218
00224 ~DebugLogFunc() {
00225 if (!is_category_wanted()) return;
00226 xapian_debuglogger_.outdent();
00227 if (!uncaught_exception && std::uncaught_exception()) {
00228
00229 LOGLINE_(category, '[' << this_ptr << "] " << func <<
00230 " exited due to exception");
00231 } else {
00232 LOGLINE_(category, '[' << this_ptr << "] " << func <<
00233 " returned (not marked up for return logging)");
00234 }
00235 }
00236 };
00237
00247 class DebugLogFuncVoid {
00249 const void * this_ptr;
00250
00252 debuglog_categories category;
00253
00255 std::string func;
00256
00258 bool uncaught_exception;
00259
00260 public:
00262 DebugLogFuncVoid(const void * this_ptr_, debuglog_categories category_,
00263 const char * func_name,
00264 const std::string & params)
00265 : this_ptr(this_ptr_), category(category_),
00266 uncaught_exception(std::uncaught_exception())
00267 {
00268 if (is_category_wanted()) {
00269 func.assign("void ");
00270 func += func_name;
00271 func += '(';
00272 func += params;
00273 func += ')';
00274 LOGLINE_ALWAYS_(category, '[' << this_ptr << "] " << func);
00275 xapian_debuglogger_.indent();
00276 }
00277 }
00278
00280 DebugLogFuncVoid(const void * this_ptr_, debuglog_categories category_,
00281 const std::string & params,
00282 const char * class_name)
00283 : this_ptr(this_ptr_), category(category_),
00284 uncaught_exception(std::uncaught_exception())
00285 {
00286 if (is_category_wanted()) {
00287 func.assign(class_name);
00288 func += "::";
00289
00290
00291 const char * ctor_name = std::strrchr(class_name, ':');
00292 if (ctor_name)
00293 ++ctor_name;
00294 else
00295 ctor_name = class_name;
00296 func += ctor_name;
00297 func += '(';
00298 func += params;
00299 func += ')';
00300 LOGLINE_ALWAYS_(category, '[' << this_ptr << "] " << func);
00301 xapian_debuglogger_.indent();
00302 }
00303 }
00304
00306 DebugLogFuncVoid(const void * this_ptr_, debuglog_categories category_,
00307 const char * class_name)
00308 : this_ptr(this_ptr_), category(category_),
00309 uncaught_exception(std::uncaught_exception())
00310 {
00311 if (is_category_wanted()) {
00312 func.assign(class_name);
00313 func += "::~";
00314
00315 const char * dtor_name = std::strrchr(class_name, ':');
00316 if (dtor_name)
00317 ++dtor_name;
00318 else
00319 dtor_name = class_name;
00320 func += dtor_name;
00321 func += "()";
00322 LOGLINE_(category, '[' << this_ptr << "] " << func);
00323 xapian_debuglogger_.indent();
00324 }
00325 }
00326
00328 bool is_category_wanted() const {
00329 return xapian_debuglogger_.is_category_wanted(category);
00330 }
00331
00337 ~DebugLogFuncVoid() {
00338 if (!is_category_wanted()) return;
00339 xapian_debuglogger_.outdent();
00340 const char * reason;
00341 if (!uncaught_exception && std::uncaught_exception()) {
00342
00343 reason = " exited due to exception";
00344 } else {
00345 reason = " returned";
00346 }
00347 LOGLINE_ALWAYS_(category, '[' << this_ptr << "] " << func << reason);
00348 }
00349 };
00350
00352 #define LOGCALL(CATEGORY, TYPE, FUNC, PARAMS) \
00353 typedef TYPE xapian_logcall_return_type_; \
00354 std::string xapian_logcall_parameters_; \
00355 if (xapian_debuglogger_.is_category_wanted(DEBUGLOG_CATEGORY_##CATEGORY)) { \
00356 std::ostringstream xapian_logcall_ostream_; \
00357 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00358 xapian_logcall_stream_ << PARAMS; \
00359 xapian_logcall_parameters_ = xapian_logcall_ostream_.str(); \
00360 } \
00361 DebugLogFunc xapian_logcall_(static_cast<const void *>(this), DEBUGLOG_CATEGORY_##CATEGORY, #TYPE, FUNC, xapian_logcall_parameters_)
00362
00364 #define LOGCALL_VOID(CATEGORY, FUNC, PARAMS) \
00365 std::string xapian_logcall_parameters_; \
00366 if (xapian_debuglogger_.is_category_wanted(DEBUGLOG_CATEGORY_##CATEGORY)) { \
00367 std::ostringstream xapian_logcall_ostream_; \
00368 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00369 xapian_logcall_stream_ << PARAMS; \
00370 xapian_logcall_parameters_ = xapian_logcall_ostream_.str(); \
00371 } \
00372 DebugLogFuncVoid xapian_logcall_(static_cast<const void *>(this), DEBUGLOG_CATEGORY_##CATEGORY, FUNC, xapian_logcall_parameters_)
00373
00375 #define LOGCALL_CTOR(CATEGORY, CLASS, PARAMS) \
00376 std::string xapian_logcall_parameters_; \
00377 if (xapian_debuglogger_.is_category_wanted(DEBUGLOG_CATEGORY_##CATEGORY)) { \
00378 std::ostringstream xapian_logcall_ostream_; \
00379 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00380 xapian_logcall_stream_ << PARAMS; \
00381 xapian_logcall_parameters_ = xapian_logcall_ostream_.str(); \
00382 } \
00383 DebugLogFuncVoid xapian_logcall_(static_cast<const void *>(this), DEBUGLOG_CATEGORY_##CATEGORY, xapian_logcall_parameters_, CLASS)
00384
00386 #define LOGCALL_DTOR(CATEGORY, CLASS) \
00387 DebugLogFuncVoid xapian_logcall_(static_cast<const void *>(this), DEBUGLOG_CATEGORY_##CATEGORY, CLASS)
00388
00390 #define LOGCALL_STATIC(CATEGORY, TYPE, FUNC, PARAMS) \
00391 typedef TYPE xapian_logcall_return_type_; \
00392 std::string xapian_logcall_parameters_; \
00393 if (xapian_debuglogger_.is_category_wanted(DEBUGLOG_CATEGORY_##CATEGORY)) { \
00394 std::ostringstream xapian_logcall_ostream_; \
00395 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00396 xapian_logcall_stream_ << PARAMS; \
00397 xapian_logcall_parameters_ = xapian_logcall_ostream_.str(); \
00398 } \
00399 DebugLogFunc xapian_logcall_(0, DEBUGLOG_CATEGORY_##CATEGORY, #TYPE, FUNC, xapian_logcall_parameters_)
00400
00402 #define LOGCALL_STATIC_VOID(CATEGORY, FUNC, PARAMS) \
00403 std::string xapian_logcall_parameters_; \
00404 if (xapian_debuglogger_.is_category_wanted(DEBUGLOG_CATEGORY_##CATEGORY)) { \
00405 std::ostringstream xapian_logcall_ostream_; \
00406 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00407 xapian_logcall_stream_ << PARAMS; \
00408 xapian_logcall_parameters_ = xapian_logcall_ostream_.str(); \
00409 } \
00410 DebugLogFuncVoid xapian_logcall_(0, DEBUGLOG_CATEGORY_##CATEGORY, FUNC, xapian_logcall_parameters_)
00411
00413 #define RETURN(A) do { \
00414 xapian_logcall_return_type_ xapian_logcall_return_ = A; \
00415 if (xapian_logcall_.is_category_wanted()) { \
00416 std::ostringstream xapian_logcall_ostream_; \
00417 PrettyOStream<std::ostringstream> xapian_logcall_stream_(xapian_logcall_ostream_); \
00418 xapian_logcall_stream_ << xapian_logcall_return_; \
00419 xapian_logcall_.log_return_value(xapian_logcall_ostream_.str()); \
00420 } \
00421 return xapian_logcall_return_; \
00422 } while (false)
00423
00429 #define LOGLINE(a,b) LOGLINE_(DEBUGLOG_CATEGORY_##a, b)
00430
00432 #define LOGVALUE(a,b) LOGLINE_(DEBUGLOG_CATEGORY_##a, #b" = " << b)
00433
00434 #else
00435
00436 #define LOGCALL(CATEGORY, TYPE, FUNC, PARAMS) (void)0
00437 #define LOGCALL_VOID(CATEGORY, FUNC, PARAMS) (void)0
00438 #define LOGCALL_CTOR(CATEGORY, CLASS, PARAMS) (void)0
00439 #define LOGCALL_DTOR(CATEGORY, CLASS) (void)0
00440 #define LOGCALL_STATIC(CATEGORY, TYPE, FUNC, PARAMS) (void)0
00441 #define LOGCALL_STATIC_VOID(CATEGORY, FUNC, PARAMS) (void)0
00442 #define RETURN(A) return A
00443 #define LOGLINE(a,b) (void)0
00444 #define LOGVALUE(a,b) (void)0
00445
00446 #endif
00447
00448 #endif // XAPIAN_INCLUDED_DEBUGLOG_H