Browse Source

Logging Module improved a LOT

master
heck 2 years ago
parent
commit
48adc084c3
  1. 301
      src/log.cc
  2. 127
      src/log.h
  3. 170
      src/valog.cc
  4. 17
      src/valog.h
  5. 49
      src/valog.hh
  6. 35
      src/valog_internal.h

301
src/log.cc

@ -0,0 +1,301 @@
#include "log.h"
#include <iostream>
#include <sstream>
#include <cstdarg>
#include <unistd.h>
#include <thread>
#include <cmath>
//-------------------------------------------------------------------------------------------------
// Private functions Prototypes
//-------------------------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level);
#ifdef __cplusplus
}
#endif
namespace Orca {
namespace Utils {
std::string _to_termcol(const ORCA_LOG_COLOR& col);
std::string _decorate_three_lines(const std::string& msg, char decoration = '-');
std::string _decorate_centered(const std::string& msg, char decoration = '-');
} // namespace Utils
namespace Log {
std::mutex _mtx_raw_log{};
std::mutex _mtx_log{};
std::atomic<ORCA_LOG_LEVEL> _log_level{ ORCA_LOG_LEVEL_NONE };
std::atomic<ORCA_LOG_COLOR> _log_color{ ORCA_LOG_COLOR_WHITE };
namespace Backend {
void _log_stderr(const std::string& msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
}
} // namespace Log
} // namespace Orca
//-------------------------------------------------------------------------------------------------
// C linkage functions
//-------------------------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
void orca_log_set_level(ORCA_LOG_LEVEL level)
{
Orca::Log::_log_level.store(level);
}
ORCA_LOG_LEVEL orca_log_get_level()
{
return Orca::Log::_log_level.load();
}
void orca_log_set_color(ORCA_LOG_COLOR col)
{
if (col == ORCA_LOG_COLOR_DEFAULT) {
col = ORCA_LOG_COLOR_RESET;
}
Orca::Log::_log_color.store(col);
}
ORCA_LOG_COLOR orca_log_get_color()
{
return Orca::Log::_log_color.load();
}
void orca_log(const char* msg)
{
Orca::Log::Backend::_log_stderr(msg, Orca::Log::_log_color.load());
}
void orca_log_h1(const char* msg)
{
Orca::Log::Backend::_log_stderr(
Orca::Utils::_decorate_three_lines(msg, '='),
Orca::Log::_log_color.load());
}
void orca_log_h2(const char* msg)
{
Orca::Log::Backend::_log_stderr(
"\n" + Orca::Utils::_decorate_centered(msg, '='),
Orca::Log::_log_color.load());
}
void orca_log_h3(const char* msg)
{
Orca::Log::Backend::_log_stderr(Orca::Utils::_decorate_centered(msg, '-'), Orca::Log::_log_color.load());
}
void _orca_log_for_macro(
ORCA_LOG_LEVEL level,
const char* file,
int line,
const char* funcname,
const char* fmt,
...)
{
std::lock_guard<std::mutex> l{ Orca::Log::_mtx_log };
if (level > Orca::Log::_log_level) {
return;
}
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();
if (!std::string(msg_fmtd).empty()) {
msg += "- " + std::string(msg_fmtd);
}
}
free(msg_fmtd);
Orca::Log::log(msg);
va_end(var_args);
}
const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level)
{
switch (*level) {
case ORCA_LOG_LEVEL_NONE:
return "NONE";
case ORCA_LOG_LEVEL_ERROR:
return "ERROR";
case ORCA_LOG_LEVEL_WARN:
return "WARN";
case ORCA_LOG_LEVEL_INFO:
return "INFO";
case ORCA_LOG_LEVEL_ALL:
return "ALL";
default:
return "invalid log level";
}
}
#ifdef __cplusplus
}
#endif
//-------------------------------------------------------------------------------------------------
// C++ Linkage functions
//-------------------------------------------------------------------------------------------------
namespace Orca {
namespace Log {
// for C++ some functions are just wrappers for the
// C linkage functions
// to be nicely available in the namespace
void set_level(ORCA_LOG_LEVEL level)
{
::orca_log_set_level(level);
}
ORCA_LOG_LEVEL get_level()
{
return ::orca_log_get_level();
}
void set_color(ORCA_LOG_COLOR col)
{
::orca_log_set_color(col);
}
ORCA_LOG_COLOR get_color()
{
return ::orca_log_get_color();
}
void _log_for_macro(
ORCA_LOG_LEVEL level,
const std::string& file,
int line,
const std::string& funcname,
const std::string& msg)
{
::_orca_log_for_macro(level, file.c_str(), line, funcname.c_str(), "%s", msg.c_str());
}
void log(const std::string& msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(msg, col);
}
void logH1(const std::string& msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(Utils::_decorate_three_lines(msg, '='), col);
}
void logH2(const std::string& msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr("\n" + Utils::_decorate_centered(msg, '='), col);
}
void logH3(const std::string& msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(Utils::_decorate_centered(msg, '-'), col);
}
namespace Backend {
// TODO: add file backend
void _log_stderr(const std::string& msg, ORCA_LOG_COLOR col)
{
std::lock_guard<std::mutex> l{ _mtx_raw_log };
std::cerr << Utils::_to_termcol(col) << msg
<< Utils::_to_termcol(ORCA_LOG_COLOR_RESET)
<< std::endl; //endl also flushes, but cerr is unbuffered anyways
}
}
} // namespace Log
namespace Utils {
int termsize_x = 120;
std::string _to_termcol(const ORCA_LOG_COLOR& col)
{
switch (col) {
case ORCA_LOG_COLOR_DEFAULT:
return _to_termcol(Orca::Log::_log_color);
case ORCA_LOG_COLOR_RESET:
return "\033[0m";
case ORCA_LOG_COLOR_BLACK:
return "\033[30m";
case ORCA_LOG_COLOR_RED:
return "\033[31m";
case ORCA_LOG_COLOR_GREEN:
return "\033[32m";
case ORCA_LOG_COLOR_YELLOW:
return "\033[33m";
case ORCA_LOG_COLOR_BLUE:
return "\033[34m";
case ORCA_LOG_COLOR_MAGENTA:
return "\033[35m";
case ORCA_LOG_COLOR_CYAN:
return "\033[36m";
case ORCA_LOG_COLOR_WHITE:
return "\033[37m";
default:
return _to_termcol(ORCA_LOG_COLOR_RESET);
}
}
std::string _decorate_three_lines(const std::string& msg, char decoration)
{
std::stringstream tmp;
tmp << std::string(termsize_x, decoration) << std::endl
<< msg << std::endl
<< std::string(termsize_x, decoration);
return tmp.str();
}
std::string _decorate_centered(const std::string& msg, char decoration)
{
std::stringstream tmp;
size_t max_len = termsize_x - 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<int>(floor((double(termsize_x - msg_truncated.length()))) / 2.0);
tmp << std::string(decolen, decoration) << ' ' << msg_truncated << ' '
<< std::string(decolen, decoration);
return tmp.str();
}
} // namespace Utils
} // namespace Orca
//-------------------------------------------------------------------------------------------------
// C++ Linkage global namespace members
//-------------------------------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level)
{
return o << std::string(_orca_log_level_to_string(level));
}
// Stuff like that would be fucking handy
// TODO: make a lib with operator<< for ALL libstc++ types
template<typename T> std::ostream& operator<<(std::ostream& o, std::vector<T>& vec)
{
std::stringstream ss{};
for (const T& elem : vec) {
o << elem;
}
return o;
}

127
src/log.h

@ -0,0 +1,127 @@
#ifndef _ORCA_VALOG_H
#define _ORCA_VALOG_H
#define ORCA_LOG_FUNCTION_ENTRY 1
//TODO implement compile time max level/disable
#ifndef ORCA_LOG_LEVEL_MAXIMUM
#define ORCA_LOG_LEVEL_MAXIMUM ORCA_LOG_LEVEL_INFO
#endif
//TODO auto detect via compiler
#ifdef ORCA_LOG_HAVE_PRETTY_FUNCTION
#define ORCA_LOG_MACRO_FUNCNAME __PRETTY_FUNCTION__
#else
#define ORCA_LOG_MACRO_FUNCNAME __func__
#endif
typedef enum {
ORCA_LOG_LEVEL_NONE = 0, // Logging Disabled
ORCA_LOG_LEVEL_ERROR = 100,
ORCA_LOG_LEVEL_WARN = 200,
ORCA_LOG_LEVEL_INFO = 300,
ORCA_LOG_LEVEL_ALL = 1000000 // Convenience
} ORCA_LOG_LEVEL;
typedef enum {
ORCA_LOG_COLOR_DEFAULT,
ORCA_LOG_COLOR_RESET,
ORCA_LOG_COLOR_BLACK,
ORCA_LOG_COLOR_RED,
ORCA_LOG_COLOR_GREEN,
ORCA_LOG_COLOR_YELLOW,
ORCA_LOG_COLOR_BLUE,
ORCA_LOG_COLOR_MAGENTA,
ORCA_LOG_COLOR_CYAN,
ORCA_LOG_COLOR_WHITE,
} ORCA_LOG_COLOR;
//---------------------------------------------------------------------------------------
// C99
//---------------------------------------------------------------------------------------
#ifndef __cplusplus
#include <stdbool.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_INFO(...) ORCA_LOG(ORCA_LOG_LEVEL_INFO, __VA_ARGS__)
#define ORCA_LOG(level, ...) \
do { \
_orca_log_for_macro(level, __FILE__, __LINE__, ORCA_LOG_MACRO_FUNCNAME, "" __VA_ARGS__); \
} while (0)
// config/settings
void orca_log_set_level(ORCA_LOG_LEVEL level);
ORCA_LOG_LEVEL orca_log_get_level();
void orca_log_set_color(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR orca_log_get_color();
// logging
void orca_log(const char* msg);
void orca_log_h1(const char* msg);
void orca_log_h2(const char* msg);
void orca_log_h3(const char* msg);
// helper function for macro use only
void _orca_log_for_macro(
ORCA_LOG_LEVEL level,
const char* file,
int line,
const char* funcname,
const char* fmt,
...);
#endif // NOT __cplusplus
//---------------------------------------------------------------------------------------
// C++
//---------------------------------------------------------------------------------------
#ifdef __cplusplus
#include <string>
#include <sstream>
#define ORCA_LOG_ERR(msg) ORCA_LOG(ORCA_LOG_LEVEL_ERROR, msg)
#define ORCA_LOG_WARN(msg) ORCA_LOG(ORCA_LOG_LEVEL_WARN, msg)
#define ORCA_LOG_INFO(msg) ORCA_LOG(ORCA_LOG_LEVEL_INFO, msg)
#define ORCA_LOG(level, msg) \
do { \
std::stringstream ss{}; \
ss << msg; \
::Orca::Log::_log_for_macro(level, __FILE__, __LINE__, ORCA_LOG_MACRO_FUNCNAME, ss.str()); \
} while (0)
namespace Orca {
namespace Log {
// config/settings
void set_level(ORCA_LOG_LEVEL level);
ORCA_LOG_LEVEL get_level();
void set_color(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR get_color();
// logging
void log(const std::string& msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH1(const std::string& msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH2(const std::string& msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH3(const std::string& msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
// helper function for macro use only
void _log_for_macro(
ORCA_LOG_LEVEL level,
const std::string& file,
int line,
const std::string& funcname,
const std::string& msg);
} // namespace Log
} // namespace Orca
std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level);
#endif //__cplusplus
#endif

170
src/valog.cc

@ -1,170 +0,0 @@
#include "valog.h"
#include "valog.hh"
#include <iostream>
#include <sstream>
#include <cstdarg>
#include <unistd.h>
#include <thread>
#include <cmath>
#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<std::mutex> 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<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 Log
} // namespace Orca

17
src/valog.h

@ -1,17 +0,0 @@
#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

49
src/valog.hh

@ -1,49 +0,0 @@
#ifndef _ORCA_VALOG_HH
#define _ORCA_VALOG_HH
#include <string>
#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

35
src/valog_internal.h

@ -1,35 +0,0 @@
#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
Loading…
Cancel
Save