
2 changed files with 386 additions and 0 deletions
@ -0,0 +1,158 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#include "pEpLog.hh" |
||||
|
#include <iostream> |
||||
|
#include <sstream> |
||||
|
#include <mutex> |
||||
|
#include <atomic> |
||||
|
#include <cmath> |
||||
|
#include "std_utils.hh" |
||||
|
|
||||
|
#ifdef ANDROID |
||||
|
#include <android/log.h> |
||||
|
#endif |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
namespace pEpLog { |
||||
|
int line_width = 120; |
||||
|
|
||||
|
// NON CLASS
|
||||
|
mutex mtx; |
||||
|
atomic_bool is_enabled{ false }; |
||||
|
|
||||
|
void set_enabled(const bool& enabled) |
||||
|
{ |
||||
|
is_enabled.store(enabled); |
||||
|
} |
||||
|
|
||||
|
bool get_enabled() |
||||
|
{ |
||||
|
return is_enabled.load(); |
||||
|
} |
||||
|
|
||||
|
// Common "print" function implementing the actual "backends"
|
||||
|
void _log(const string& msg, Utils::Color col = Utils::Color::WHITE) |
||||
|
{ |
||||
|
lock_guard<mutex> l(mtx); |
||||
|
#ifdef ANDROID |
||||
|
__android_log_print(ANDROID_LOG_DEBUG, "pEpDebugLog", "%s", msg.c_str()); |
||||
|
#else |
||||
|
cerr << Utils::to_termcol(col) << msg << Utils::to_termcol(Utils::Color::RESET) |
||||
|
<< endl; //endl also flushes, but cerr is unbuffered anyways
|
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
void log(const string& msg, Utils::Color col) |
||||
|
{ |
||||
|
_log(msg, col); |
||||
|
} |
||||
|
|
||||
|
void logH1(const string& msg, Utils::Color col) |
||||
|
{ |
||||
|
log(decorate_three_lines(msg, '='), col); |
||||
|
} |
||||
|
|
||||
|
void logH2(const string& msg, Utils::Color col) |
||||
|
{ |
||||
|
log("\n" + decorate_centered(msg, '='), col); |
||||
|
} |
||||
|
|
||||
|
void logH3(const string& msg, Utils::Color col) |
||||
|
{ |
||||
|
log(decorate_centered(msg, '-'), col); |
||||
|
} |
||||
|
|
||||
|
string decorate_three_lines(const string& msg, char decoration) |
||||
|
{ |
||||
|
stringstream tmp; |
||||
|
tmp << std::string(line_width, decoration) << endl |
||||
|
<< msg << endl |
||||
|
<< std::string(line_width, decoration); |
||||
|
return tmp.str(); |
||||
|
} |
||||
|
|
||||
|
string decorate_centered(const string& msg, char decoration) |
||||
|
{ |
||||
|
stringstream tmp; |
||||
|
size_t max_len = line_width - 10; |
||||
|
// truncate msg
|
||||
|
string msg_truncated = msg; |
||||
|
if (msg.length() >= max_len) { |
||||
|
msg_truncated = msg.substr(0, max_len); |
||||
|
msg_truncated += "..."; |
||||
|
} |
||||
|
|
||||
|
// define decolen
|
||||
|
int decolen = static_cast<int>( |
||||
|
floor((double(line_width - msg_truncated.length()))) / 2.0); |
||||
|
|
||||
|
tmp << std::string(decolen, decoration) << ' ' << msg_truncated << ' ' |
||||
|
<< std::string(decolen, decoration); |
||||
|
return tmp.str(); |
||||
|
} |
||||
|
|
||||
|
} // namespace pEpLog
|
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
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, Utils::Color col) const |
||||
|
{ |
||||
|
std::stringstream msg_; |
||||
|
msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; |
||||
|
msg_ << " - "; |
||||
|
msg_ << this->get_classname() << "[" << this->get_instancename() << "]"; |
||||
|
msg_ << " - " << msg; |
||||
|
this->logRaw(msg_.str(), col); |
||||
|
} |
||||
|
|
||||
|
void pEpLogger::logRaw(const string& msg, Utils::Color col) const |
||||
|
{ |
||||
|
if (this->is_enabled) { |
||||
|
_log(msg, col); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void pEpLogger::set_enabled(const bool& enabled) |
||||
|
{ |
||||
|
this->is_enabled = enabled; |
||||
|
} |
||||
|
|
||||
|
bool pEpLogger::get_enabled() const |
||||
|
{ |
||||
|
return this->is_enabled; |
||||
|
} |
||||
|
|
||||
|
string pEpLogger::get_classname() const |
||||
|
{ |
||||
|
return this->classname; |
||||
|
} |
||||
|
|
||||
|
void pEpLogger::set_instancename(const string& name) |
||||
|
{ |
||||
|
this->instancename = name; |
||||
|
} |
||||
|
|
||||
|
string pEpLogger::get_instancename() const |
||||
|
{ |
||||
|
return this->instancename; |
||||
|
} |
||||
|
} // namespace pEpLog
|
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
@ -0,0 +1,228 @@ |
|||||
|
// This file is under GNU General Public License 3.0
|
||||
|
// see LICENSE.txt
|
||||
|
|
||||
|
#ifndef LIBPEPADAPTER_PEPLOG_HH |
||||
|
#define LIBPEPADAPTER_PEPLOG_HH |
||||
|
|
||||
|
// getpid
|
||||
|
// Linux - unistd.h
|
||||
|
// macOS - unistd.h
|
||||
|
// Android - unistd.h
|
||||
|
// Win - process.h
|
||||
|
#ifdef WIN32 |
||||
|
#include <process.h> |
||||
|
// TODO: once this works, move this to pEpEngine platform_windows.h and file a PR
|
||||
|
#ifndef getpid |
||||
|
#define getpid() _getpid() |
||||
|
#endif |
||||
|
|
||||
|
#else |
||||
|
#include <unistd.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <sstream> |
||||
|
#include <thread> |
||||
|
#include "std_utils.hh" |
||||
|
|
||||
|
// pEpLog
|
||||
|
// ======
|
||||
|
// a "to be kept ultra small and simple" logging unit.
|
||||
|
// featuring:
|
||||
|
// * 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: cerr
|
||||
|
// * Logging without any class/object (pEpLog / pEpLogRaw macros)
|
||||
|
// * runtime switchable (on/off) only on a global level
|
||||
|
// * Class backed Logging macros (pEpLogClass / pEpLogClassRaw)
|
||||
|
// * * runtime switchable (on/off) on a class and object level
|
||||
|
//
|
||||
|
// There are already too many 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.
|
||||
|
//
|
||||
|
|
||||
|
// pEpLog - logformat "thread - __FILE__::__FUNTION__ - <message>"
|
||||
|
// To be used in a non-class/object context
|
||||
|
#ifdef NDEBUG |
||||
|
#define pEpLog(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLog(msg) \ |
||||
|
do { \ |
||||
|
if (pEp::Adapter::pEpLog::get_enabled()) { \ |
||||
|
std::stringstream msg_; \ |
||||
|
msg_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \ |
||||
|
msg_ << " - " << __FILE__ << "::" << __FUNCTION__; \ |
||||
|
msg_ << " - " << msg; \ |
||||
|
pEp::Adapter::pEpLog::log(msg_.str()); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
|
||||
|
// RAW == without prefix of thread, file, function
|
||||
|
// pEpLogRaw - logformat "<message>"
|
||||
|
#ifdef NDEBUG |
||||
|
#define pEpLogRaw(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLogRaw(msg) \ |
||||
|
do { \ |
||||
|
if (pEp::Adapter::pEpLog::get_enabled()) { \ |
||||
|
std::stringstream ss_msg{}; \ |
||||
|
ss_msg << msg; \ |
||||
|
pEp::Adapter::pEpLog::log(ss_msg.str()); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
|
||||
|
// pEpLogH1 - logformat "<==============================>"
|
||||
|
// pEpLogH1 - logformat message"
|
||||
|
// pEpLogH1 - logformat "<==============================>"
|
||||
|
#ifdef NDEBUG |
||||
|
#define pEpLogH1(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLogH1(msg) \ |
||||
|
do { \ |
||||
|
if (pEp::Adapter::pEpLog::get_enabled()) { \ |
||||
|
std::stringstream ss_msg{}; \ |
||||
|
ss_msg << msg; \ |
||||
|
pEp::Adapter::pEpLog::logH1(ss_msg.str()); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
|
||||
|
// pEpLogH2 - logformat <=============== message ==============>"
|
||||
|
#ifdef NDEBUG |
||||
|
#define pEpLogH2(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLogH2(msg) \ |
||||
|
do { \ |
||||
|
if (pEp::Adapter::pEpLog::get_enabled()) { \ |
||||
|
std::stringstream ss_msg{}; \ |
||||
|
ss_msg << msg; \ |
||||
|
pEp::Adapter::pEpLog::logH2(ss_msg.str()); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
|
||||
|
// pEpLogH2 - logformat <---------------- message ----------------"
|
||||
|
#ifdef NDEBUG |
||||
|
#define pEpLogH3(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLogH3(msg) \ |
||||
|
do { \ |
||||
|
if (pEp::Adapter::pEpLog::get_enabled()) { \ |
||||
|
std::stringstream ss_msg{}; \ |
||||
|
ss_msg << msg; \ |
||||
|
pEp::Adapter::pEpLog::logH3(ss_msg.str()); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
|
||||
|
namespace pEp { |
||||
|
namespace Adapter { |
||||
|
namespace pEpLog { |
||||
|
// Logging functions to control pEpLog() macro
|
||||
|
void set_enabled(const bool& is_enabled); |
||||
|
bool get_enabled(); |
||||
|
void log(const std::string& msg, Utils::Color col = Utils::Color::WHITE); |
||||
|
void logH1(const std::string& msg, Utils::Color col = Utils::Color::WHITE); |
||||
|
void logH2(const std::string& msg, Utils::Color col = Utils::Color::WHITE); |
||||
|
void logH3(const std::string& msg, Utils::Color col = Utils::Color::WHITE); |
||||
|
std::string decorate_three_lines(const std::string& msg, char decoration = '-'); |
||||
|
std::string decorate_centered(const std::string& msg, char decoration = '-'); |
||||
|
} // namespace pEpLog
|
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
// --------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
|
||||
|
// 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:
|
||||
|
// create your logger obj in your class as a public member (usually)
|
||||
|
// Adapter::pEpLog::pEpLogger logger{"<CLASSNAME>", enabled: true|false};
|
||||
|
// then, create an alias for your logger called "m4gic_logger_n4me" as a private member
|
||||
|
// Adapter::pEpLog::pEpLogger& m4gic_logger_n4me = 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_ << "[" << getpid() << " " << std::this_thread::get_id() << "]"; \ |
||||
|
msg_ << " - " << this->m4gic_logger_n4me.get_classname(); \ |
||||
|
msg_ << "[" << this->m4gic_logger_n4me.get_instancename() << "]"; \ |
||||
|
msg_ << "::" << __FUNCTION__; \ |
||||
|
msg_ << " - " << (msg); \ |
||||
|
this->m4gic_logger_n4me.logRaw(msg_.str()); \ |
||||
|
} while (0) |
||||
|
#endif // NDEBUG
|
||||
|
|
||||
|
// pEpLogClassRaw 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 pEpLogClassRaw(msg) \ |
||||
|
do { \ |
||||
|
} while (0) |
||||
|
#else |
||||
|
#define pEpLogClassRaw(msg) \ |
||||
|
do { \ |
||||
|
this->m4gic_logger_n4me.logRaw(msg); \ |
||||
|
} 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, Utils::Color col = Utils::Color::WHITE) const; |
||||
|
// Prints just "<msg>"
|
||||
|
void logRaw(const std::string& msg, Utils::Color col = Utils::Color::WHITE) const; |
||||
|
void set_enabled(const bool& enabled); |
||||
|
bool get_enabled() const; |
||||
|
std::string get_classname() const; |
||||
|
// If never set, the default instancename is a unique number
|
||||
|
void set_instancename(const std::string& name); |
||||
|
std::string get_instancename() const; |
||||
|
|
||||
|
private: |
||||
|
static int auto_instance_nr; |
||||
|
bool is_enabled; |
||||
|
std::string classname; |
||||
|
std::string instancename; |
||||
|
}; |
||||
|
} // namespace pEpLog
|
||||
|
} // namespace Adapter
|
||||
|
} // namespace pEp
|
||||
|
|
||||
|
|
||||
|
#endif // LIBPEPADAPTER_PEPLOG_HH
|
Loading…
Reference in new issue