pEpLog: Add class and macros to support runtime switching on a class and instance basis.

LIB-12
heck 2 years ago
parent 591b5c0fc2
commit 9dddab4388

@ -8,19 +8,20 @@
#include <atomic>
#ifdef ANDROID
#include <android/log.h>
#include <android/log.h>
#endif
using namespace std;
namespace pEp {
namespace Adapter {
namespace pEpLog {
std::mutex mtx;
// NON CLASS
mutex mtx;
atomic_bool is_enabled{false};
std::atomic_bool is_enabled{ false };
void set_enabled(bool enabled)
void set_enabled(const bool& enabled)
{
is_enabled.store(enabled);
}
@ -30,18 +31,82 @@ namespace pEp {
return is_enabled.load();
}
void log(std::string msg)
// Common "print" function implementing the actual "backends"
void _log(const string& msg)
{
if (is_enabled.load()) {
std::lock_guard<std::mutex> l(mtx);
lock_guard<mutex> l(mtx);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str());
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str());
#else
std::cerr << msg << std::endl; //std::endl also flushes
cerr << msg << endl; //endl also flushes, but cerr is unbuffered anyways
#endif
}
void log(const string& msg)
{
if (is_enabled.load()) {
_log(msg);
}
}
}
}
}
namespace pEp {
namespace Adapter {
namespace pEpLog {
// Class pEpLogger
int pEpLogger::auto_instance_nr = 0;
pEpLogger::pEpLogger(const string& classname, const bool& enabled)
: classname(classname),
is_enabled(enabled)
{
auto_instance_nr++;
this->set_instancename(to_string(auto_instance_nr));
}
void pEpLogger::log(const string& msg)
{
std::stringstream msg_;
msg_ << std::this_thread::get_id();
msg_ << " - ";
msg_ << this->get_classname() << "[" << this->get_instancename() << "]";
msg_ << " - " << msg;
this->logRaw(msg_.str());
}
void pEpLogger::logRaw(const string& msg)
{
if (this->is_enabled) {
_log(msg);
}
}
void pEpLogger::set_enabled(const bool& is_enabled)
{
this->is_enabled = is_enabled;
}
bool pEpLogger::get_enabled()
{
return this->is_enabled;
}
string pEpLogger::get_classname()
{
return this->classname;
}
void pEpLogger::set_instancename(const string& instancename)
{
this->instancename = instancename;
}
string pEpLogger::get_instancename()
{
return this->instancename;
}
} // namespace pEpLog
} // namespace Adapter
} // namespace Adapter
} // namespace pEp

@ -10,49 +10,133 @@
// ======
// a "to be kept ultra small and simple" logging unit.
// featuring:
// * pEpLog macro that will be eliminated in release-builds (-DNDEBUG=1)
// * thread safe (no interleave when logging from diff threads)
// * Logging macros that completely eliminate any logging calls in release-builds (NDEBUG)
// * thread safe (no interleave when logging from diff threads) TODO: pEpLogger: REALLY?
// * OS dependent backend switches:
// * android: __android_log_print
// * all other OS: cout
// * runtime enabled/disabled switch (global)
// * all other OS: cerr
// * Logging without any class/object (pEpLog / pEpLogRaw macros)
// * runtime switchable only on a global level
// * Class backed Logging macros (pEpLogClass / pEpLogRawClass)
// * * runtime switchable logging on a class and object level
//
// You might want more and more features, but the feature-policy is very restrictive, and there is a
// primary design goal to keep it simple, maintainable and portable.
// There are already too mnay features and you might want even more and more,
// but the feature-policy of this logging unit is very restrictive, and there is a
// primary design goal to keep it very simple, maintainable and portable.
//
// How to use:
// include <pEpLog.hh>
// use the macro pEpLog(msg) to do logging
// use NDEBUG=1 to turn logging on/off at compile-time
// use set_enabled(bool) to turn logging on/off at runtime
// use set_enabled_<backend>(bool) to turn logging on/off per backend
// pEpLog is to be used in a non-class/object context
#ifdef NDEBUG
#define pEpLog(msg) \
#define pEpLog(msg) \
do { \
} while (0)
#else
#define pEpLog(msg) \
#define pEpLog(msg) \
do { \
std::stringstream msg_ss; \
msg_ss << std::this_thread::get_id() << " - " << __FILE__ << "::" << __FUNCTION__ \
<< " - " << msg; \
pEp::Adapter::pEpLog::log(msg_ss.str()); \
std::stringstream msg_; \
msg_ << std::this_thread::get_id(); \
msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \
msg_ << " - " << msg; \
pEp::Adapter::pEpLog::log(msg_.str()); \
} while (0)
#endif // NDEBUG
// pEpLogRaw the same as pEpLog, but does not print anything except the supplied msg
#ifdef NDEBUG
#define pEpLogRaw(msg) \
do { \
} while (0)
#else
#define pEpLogRaw(msg) \
do { \
pEp::Adapter::pEpLog::log(msg_.str()); \
} while (0)
#endif // NDEBUG
namespace pEp {
namespace Adapter {
namespace pEpLog {
// Logging functions to control pEpLog() macro
void log(const std::string& msg);
void set_enabled(const bool& is_enabled);
bool get_enabled();
} // pEp
} // Adapter
} // pEpLog
void log(std::string msg);
// --------------------------------------------------------------------------------------------------
void set_enabled(bool is_enabled);
bool get_enabled();
// pEpLogClass is to be used in a class
// pEpLogger can only print the "thread - file::class::function - <message>" format using this macro
// WARNING: Some magic is needed
// Usage:
// Just create your logger member in your class (public)
// Adapter::pEpLog::pEpLogger logger{"<CLASSNAME>", enabled: true|false};
// then, create an alias for your logger called "m4gic_logger_n4ame"
// Adapter::pEpLog::pEpLogger& m4gic_logger_n4ame = logger;
// Thats all.
// Now in your implementation, to log a message you just write:
// pEpLogClass("my great logging message");
#ifdef NDEBUG
#define pEpLogClass(msg) \
do { \
} while (0)
#else
#define pEpLogClass(msg) \
do { \
std::stringstream msg_; \
msg_ << std::this_thread::get_id(); \
msg_ << " - " << __FILE__; \
msg_ << "::" << this->m4gic_logger_n4ame.get_classname(); \
msg_ << "[" << this->m4gic_logger_n4ame.get_instancename() << "]"; \
msg_ << "::" << __FUNCTION__; \
msg_ << " - " << msg; \
this->m4gic_logger_n4ame.logRaw(msg_.str()); \
} while (0)
#endif // NDEBUG
// pEpLogRawClass is the same as pEpLogClass, but does not print anything except the supplied msg
// This can also be achieved without this macro, just use the log method of pEpLogger
// You also need to set up the logger in your class as for pEpLogClass
// The only advantage of this macro is that is compiled away to nothing with NDEBUG
#ifdef NDEBUG
#define pEpLogRawClass(msg) \
do { \
} while (0)
#else
#define pEpLogRawClass(msg) \
do { \
this->m4gic_logger_n4ame.logRaw(msg_.str()); \
} while (0)
#endif // NDEBUG
namespace pEp {
namespace Adapter {
namespace pEpLog {
class pEpLogger {
public:
pEpLogger() = delete;
pEpLogger(const std::string& classname, const bool& enabled);
// Print a logging message in the format "thread - classname[instancename] - <msg>"
void log(const std::string& msg);
// Prints just "<msg>"
void logRaw(const std::string& msg);
void set_enabled(const bool& is_enabled);
bool get_enabled();
std::string get_classname();
// If never set, the default instancename is a unique number
void set_instancename(const std::string& instancename);
std::string get_instancename();
private:
static int auto_instance_nr;
bool is_enabled;
std::string classname;
std::string instancename;
};
} // namespace pEpLog
} // namespace Adapter
} // namespace Adapter
} // namespace pEp

Loading…
Cancel
Save