From 79af081f84a7ebc8ddd9b741e25bab5df770adbd Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 28 Apr 2019 02:27:12 +0200 Subject: [PATCH] Introduce RetroShare logging helpers Support for chaining like std::cerr Support for compile-time optimization without #ifdef around Support for Android native logging without depending on AndroidStdIOCatcher workaround Support for automatic timestamp (on Android it's provided by Android native log) Standardized messages categories --- libretroshare/src/util/rsdebug.h | 225 +++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 14 deletions(-) diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index dd054822c..227d5f8b7 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -1,9 +1,8 @@ /******************************************************************************* - * libretroshare/src/util: rsdebug.h * + * RetroShare debugging utilities * * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2008 by Robert Fernie * + * Copyright (C) 2004-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,16 +18,211 @@ * along with this program. If not, see . * * * *******************************************************************************/ -/* Moved from pqi/ to util/ so it can be used more generally. - */ +#pragma once -#ifndef RS_LOG_DEBUG_H -#define RS_LOG_DEBUG_H +#include + +#ifdef __ANDROID__ +# include +# include +# include + +enum class RsLoggerCategories +{ + DEBUG = ANDROID_LOG_DEBUG, + INFO = ANDROID_LOG_INFO, + WARNING = ANDROID_LOG_WARN, + ERROR = ANDROID_LOG_ERROR, + FATAL = ANDROID_LOG_FATAL +}; + +template +struct t_RsLogger +{ + inline t_RsLogger() = default; + + template + inline t_RsLogger& operator<<(const T& val) + { ostr << val; return *this; } + + /// needed for manipulators and things like std::endl + t_RsLogger& operator<<(std::ostream& (*pf)(std::ostream&)) + { + if(pf == static_cast( + &std::endl< char, std::char_traits > )) + { + __android_log_write( + static_cast(CATEGORY), + "RetroShare", ostr.str().c_str() ); + ostr.str() = ""; + } + else ostr << pf; + + return *this; + } + +private: + std::ostringstream ostr; +}; + +#else // def __ANDROID__ + +#include +#include + +enum class RsLoggerCategories +{ + DEBUG = 'D', + INFO = 'I', + WARNING = 'W', + ERROR = 'E', + FATAL = 'F' +}; + +template +struct t_RsLogger +{ + inline t_RsLogger() = default; + + template + inline std::ostream& operator<<(const T& val) + { + return std::cerr << static_cast(CATEGORY) << " " << time(nullptr) + << " " << val; + } +}; +#endif // def __ANDROID__ + + +/** + * Comfortable debug message loggin, supports chaining like std::cerr but can + * be easly and selectively disabled at compile time to reduce generated binary + * size and performance impact without too many #ifdef around. + * + * To selectively debug your context you can just add something like this in + * in that context, as an example for a class you can just add a line like this + * inside class declaration: +@code{.cpp} +RS_SET_CONTEXT_DEBUG_LEVEL(2) +@endcode + * And the you can write debug messages around the code of the class like this: +@code{.cpp} +Dbg1() << "Level 1 debug message example, this will be compiled and " + << "printed" << std::endl; +Dbg2() << "Level 2 debug message example, this will be compiled and " + << "printed" << std::endl; +Dbg3() << "Level 3 debug message example, this will not be compiled and " + << "printed, and without #ifdef around!!" << std::endl; +Dbg4() << "Level 4 debug message example, this will not be compiled and " + << "printed, and without #ifdef around!!" << std::endl; +@endcode + * To change the debugging level, for example to completely disable debug + * messages you can change it to 0 +@code{.cpp} +RS_SET_CONTEXT_DEBUG_LEVEL(0) +@endcode + * While to set it to maximim level you have to pass 4. + */ +using RsDbg = t_RsLogger; + + +/** + * Comfortable log information reporting helper, supports chaining like + * std::cerr. + * To report an information message you can just write: +@code{.cpp} +RsInfo() << __PRETTY_FUNCTION__ << "My information message" << std::cerr; +@endcode + */ +using RsInfo = t_RsLogger; + +/// Similar to @see RsInfo but for warning messages +using RsWarn = t_RsLogger; + +/// Similar to @see RsInfo but for error messages +using RsErr = t_RsLogger; + +/** Similar to @see RsInfo but for fatal errors (the ones which cause RetroShare + * to terminate) messages */ +using RsFatal = t_RsLogger; + +/** + * Keeps compatible syntax with RsDbg but explicitely do nothing in a way that + * any modern compiler should be smart enough to optimize out all the function + * calls. + */ +struct RsNoDbg +{ + inline RsNoDbg() = default; + + /** + * This match most of the types, but might be not enough for templated + * types + */ + template + inline RsNoDbg& operator<<(const T&) { return *this; } + + /// needed for manipulators and things like std::endl + inline RsNoDbg& operator<<(std::ostream& (*/*pf*/)(std::ostream&)) + { return *this; } +}; + +/** + * Concatenate preprocessor tokens A and B without expanding macro definitions + * (however, if invoked from a macro, macro arguments are expanded). + */ +#define RS_CONCAT_MACRO_NX(A, B) A ## B + +/// Concatenate preprocessor tokens A and B after macro-expanding them. +#define RS_CONCAT_MACRO(A, B) RS_CONCAT_MACRO_NX(A, B) + +/** + * Set local context debug level. + * Avoid copy pasting boilerplate code around @see RsDbg for usage details + */ +#define RS_SET_CONTEXT_DEBUG_LEVEL(level) \ + RS_CONCAT_MACRO(RS_SET_CONTEXT_DEBUG_LEVEL, level) + +// A bunch of boilerplate, but just in one place +#define RS_SET_CONTEXT_DEBUG_LEVEL0 \ + using Dbg1 = RsNoDbg; \ + using Dbg2 = RsNoDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL1 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsNoDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL2 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL3 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL4 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsDbg; \ + using Dbg4 = RsDbg; + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// All the following lines are DEPRECATED!! #include +#include "util/rsdeprecate.h" + namespace RsLog { - enum logLvl { + enum RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logLvl { None = -1, Default = 0, Alert = 1, @@ -40,7 +234,7 @@ namespace RsLog { }; // this struct must be provided by the caller (to rslog()) - struct logInfo { + struct RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logInfo { // module specific log lvl logLvl lvl; // module name (displayed in log) @@ -48,9 +242,16 @@ namespace RsLog { }; } +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setDebugCrashMode(const char *cfile); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setDebugFile(const char *fname); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setOutputLevel(RsLog::logLvl lvl); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg); @@ -76,7 +277,3 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg #define PQL_DEBUG_ALERT RSL_DEBUG_ALERT #define PQL_DEBUG_BASIC RSL_DEBUG_BASIC #define PQL_DEBUG_ALL RSL_DEBUG_ALL - - - -#endif