diff --git a/src/valog.cc b/src/valog.cc new file mode 100644 index 0000000..7177033 --- /dev/null +++ b/src/valog.cc @@ -0,0 +1,170 @@ +#include "valog.h" +#include "valog.hh" +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level) + { + switch (*level) { + case ORCA_LOG_LEVEL_ERROR: + return "ERROR"; + case ORCA_LOG_LEVEL_WARNING: + return "WARN"; + case ORCA_LOG_LEVEL_TRACE: + return "TRACE"; + default: + return "invalid log level"; + } + } + + void _orca_log( + ORCA_LOG_LEVEL level, + const char* file, + int line, + const char* funcname, + const char* fmt, + ...) + { + std::string msg{ "orca log subsystem error" }; + va_list var_args; + va_start(var_args, fmt); + + char* msg_fmtd = nullptr; + int size = vasprintf(&msg_fmtd, fmt, var_args); + if (size >= 0) { + std::stringstream header{}; + header << _orca_log_level_to_string(&level) << " "; + header << getpid() << " "; + header << std::this_thread::get_id() << " "; + header << file << ":"; + header << line << " "; + header << funcname << " "; + msg = header.str() + " - " + std::string(msg_fmtd); + } + free(msg_fmtd); + Orca::Log::log(msg); + va_end(var_args); + } + +#ifdef __cplusplus +} +#endif + +std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level) +{ + return o << std::string(_orca_log_level_to_string(level)); +} + +namespace Orca { + namespace Utils { + std::string to_termcol(const Color& col) + { + switch (col) { + case Color::RESET: + return "\033[0m"; + case Color::BLACK: + return "\033[30m"; + case Color::RED: + return "\033[31m"; + case Color::GREEN: + return "\033[32m"; + case Color::YELLOW: + return "\033[33m"; + case Color::BLUE: + return "\033[34m"; + case Color::MAGENTA: + return "\033[35m"; + case Color::CYAN: + return "\033[36m"; + case Color::WHITE: + return "\033[37m"; + default: + return "\033[0m"; + } + } + } // namespace Utils +} // namespace Orca + +namespace Orca { + namespace Log { + int line_width = 120; + + // NON CLASS + std::mutex mtx; + std::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 std::string& msg, Utils::Color col = Utils::Color::WHITE) + { + std::lock_guard l(mtx); + std::cerr << Utils::to_termcol(col) << msg << Utils::to_termcol(Utils::Color::RESET) + << std::endl; //endl also flushes, but cerr is unbuffered anyways + } + + void log(const std::string& msg, Utils::Color col) + { + _log(msg, col); + } + + void logH1(const std::string& msg, Utils::Color col) + { + log(decorate_three_lines(msg, '='), col); + } + + void logH2(const std::string& msg, Utils::Color col) + { + log("\n" + decorate_centered(msg, '='), col); + } + + void logH3(const std::string& msg, Utils::Color col) + { + log(decorate_centered(msg, '-'), col); + } + + std::string decorate_three_lines(const std::string& msg, char decoration) + { + std::stringstream tmp; + tmp << std::string(line_width, decoration) << std::endl + << msg << std::endl + << std::string(line_width, decoration); + return tmp.str(); + } + + std::string decorate_centered(const std::string& msg, char decoration) + { + std::stringstream tmp; + size_t max_len = line_width - 10; + // truncate msg + std::string msg_truncated = msg; + if (msg.length() >= max_len) { + msg_truncated = msg.substr(0, max_len); + msg_truncated += "..."; + } + + // define decolen + int decolen = static_cast(floor((double(line_width - msg_truncated.length()))) / 2.0); + + tmp << std::string(decolen, decoration) << ' ' << msg_truncated << ' ' + << std::string(decolen, decoration); + return tmp.str(); + } + } // namespace Log +} // namespace Orca diff --git a/src/valog.h b/src/valog.h new file mode 100644 index 0000000..cb923cd --- /dev/null +++ b/src/valog.h @@ -0,0 +1,17 @@ +#ifndef _ORCA_VALOG_H +#define _ORCA_VALOG_H + +#include "valog_internal.h" + +#define ORCA_LOG_ERR(...) ORCA_LOG(ORCA_LOG_LEVEL_ERROR, __VA_ARGS__) + +#define ORCA_LOG_WARN(...) ORCA_LOG(ORCA_LOG_LEVEL_WARN, __VA_ARGS__) + +#define ORCA_LOG_TRACE(...) ORCA_LOG(ORCA_LOG_LEVEL_TRACE, __VA_ARGS__) + +#define ORCA_LOG(level, ...) \ + do { \ + _orca_log(level, __FILE__, __LINE__, ORCA_MACRO_FUNCNAME, "" __VA_ARGS__); \ + } while (0) + +#endif diff --git a/src/valog.hh b/src/valog.hh new file mode 100644 index 0000000..524ddb1 --- /dev/null +++ b/src/valog.hh @@ -0,0 +1,49 @@ +#ifndef _ORCA_VALOG_HH +#define _ORCA_VALOG_HH + +#include +#include "valog_internal.h" + +#define ORCA_LOG_ERR(...) ORCA_LOG(ORCA_LOG_LEVEL_ERROR, __VA_ARGS__) + +#define ORCA_LOG_WARN(...) ORCA_LOG(ORCA_LOG_LEVEL_WARN, __VA_ARGS__) + +#define ORCA_LOG_TRACE(...) ORCA_LOG(ORCA_LOG_LEVEL_TRACE, __VA_ARGS__) + +#define ORCA_LOG(level, ...) \ + do { \ + _orca_log(level, __FILE__, __LINE__, ORCA_MACRO_FUNCNAME, "" __VA_ARGS__); \ + } while (0) + + +namespace Orca { + namespace Utils { + enum class Color { + RESET, + BLACK, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + WHITE, + }; + std::string to_termcol(const Color& col); + } // namespace Utils + + namespace Log { + 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 Log +} // namespace Orca + +std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level); + +#endif diff --git a/src/valog_internal.h b/src/valog_internal.h new file mode 100644 index 0000000..113db1b --- /dev/null +++ b/src/valog_internal.h @@ -0,0 +1,35 @@ +#ifndef _ORCA_VALOG_INTERNAL_H +#define _ORCA_VALOG_INTERNAL_H + +#define ORCA_HAVE_PRETTY_FUNCTION 1 +#ifdef ORCA_HAVE_PRETTY_FUNCTION + #define ORCA_MACRO_FUNCNAME __PRETTY_FUNCTION__ +#else + #define ORCA_func_OR_PRETTY_FUNCTION __func__ +#endif + +typedef enum { + ORCA_LOG_LEVEL_ERROR = 100, + ORCA_LOG_LEVEL_WARNING = 200, + ORCA_LOG_LEVEL_TRACE = 300, +} ORCA_LOG_LEVEL; + + +#ifdef __cplusplus +extern "C" { +#endif + + void _orca_log( + ORCA_LOG_LEVEL level, + const char* file, + int line, + const char* funcname, + const char* fmt, + ...); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/test/test_log.c b/test/test_log.c new file mode 100644 index 0000000..a7bca23 --- /dev/null +++ b/test/test_log.c @@ -0,0 +1,17 @@ +//#include +#include +#include +#include +#include "../src/valog.h" + + +int main() +{ + // C usage + ORCA_LOG_ERR(); + ORCA_LOG_ERR("HELLO"); + char *str = strdup("fds"); + ORCA_LOG_ERR("string: %s", str); + + free(str); +} diff --git a/test/test_log_cxx.cc b/test/test_log_cxx.cc new file mode 100644 index 0000000..fa37b4b --- /dev/null +++ b/test/test_log_cxx.cc @@ -0,0 +1,19 @@ +//#include +//#include +#include +#include +#include "../src/valog.h" +#include + +int main() +{ + // C++ usage + ORCA_LOG_ERR(); + ORCA_LOG_ERR("HELLO"); + std::string str{ "fds" }; + ORCA_LOG_ERR("string: %s", str.c_str()); + // { + // // C++ usage + // ORCA_LOG_ERR("%s",std::string("test: " + std::string(str) + "end").c_str()); + // } +}