Browse Source

Log: add file backend

master
heck 2 years ago
parent
commit
c55102d91b
  1. 221
      src/log.cc
  2. 42
      src/log.h
  3. 32
      test/test_log.c
  4. 9
      test/test_log_cxx.cc

221
src/log.cc

@ -6,33 +6,51 @@
#include <thread>
#include <string_view>
#include <cmath>
#include <filesystem>
#include <fstream>
//-------------------------------------------------------------------------------------------------
// Private functions Prototypes
// Internal functions Prototypes
// Global State
//-------------------------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level);
bool _orca_logfile_open(void);
void _orca_logfile_close(void);
#ifdef __cplusplus
}
#endif
namespace Orca {
namespace Utils {
std::atomic<int> termsize_x = 120;
std::string _to_termcol(const ORCA_LOG_COLOR& col);
std::string _decorate_three_lines(std::string_view msg, char decoration = '-');
std::string _decorate_centered(std::string_view msg, char decoration = '-');
} // namespace Utils
namespace 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(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void _log_file(std::string_view msg);
}
} // namespace Log
void _dispatcher(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
namespace Console {
std::mutex _mtx_stdout{};
void _write_stdout(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
std::mutex _mtx_stderr{};
void _write_stderr(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
} // namespace Console
namespace Logfile {
std::recursive_mutex _mtx_path{};
std::filesystem::path _path{ "orca.log" };
std::recursive_mutex _mtx_stream{};
std::ofstream _stream{};
std::atomic<bool> _clear_on_open{ true };
void _write(std::string_view msg);
} // namespace Logfile
} // namespace Backend
} // namespace Log
} // namespace Orca
//-------------------------------------------------------------------------------------------------
@ -41,55 +59,81 @@ namespace Orca {
#ifdef __cplusplus
extern "C" {
#endif
void orca_log_level_set(ORCA_LOG_LEVEL level)
{
Orca::Log::_log_level = level;
}
ORCA_LOG_LEVEL orca_log_level_get(void)
{
return Orca::Log::_log_level;
}
void orca_log_set_level(ORCA_LOG_LEVEL level)
void orca_log_logfile_path_set(const char* path)
{
Orca::Log::_log_level.store(level);
std::lock_guard<std::recursive_mutex> l{ Orca::Log::Backend::Logfile::_mtx_path };
std::lock_guard<std::recursive_mutex> l2{ Orca::Log::Backend::Logfile::_mtx_stream };
Orca::Log::Backend::Logfile::_path = path;
if (Orca::Log::Backend::Logfile::_stream.is_open()) {
Orca::Log::Backend::Logfile::_stream.close();
}
}
ORCA_LOG_LEVEL orca_log_get_level()
void orca_log_logfile_path_get(const char** path)
{
return Orca::Log::_log_level.load();
std::lock_guard<std::recursive_mutex> l{ Orca::Log::Backend::Logfile::_mtx_path };
*path = Orca::Log::Backend::Logfile::_path.c_str();
}
void orca_log_set_color(ORCA_LOG_COLOR col)
void orca_log_color_set(ORCA_LOG_COLOR col)
{
if (col == ORCA_LOG_COLOR_DEFAULT) {
col = ORCA_LOG_COLOR_RESET;
}
Orca::Log::_log_color.store(col);
Orca::Log::_log_color = col;
}
ORCA_LOG_COLOR orca_log_get_color()
ORCA_LOG_COLOR orca_log_color_get(void)
{
return Orca::Log::_log_color.load();
return Orca::Log::_log_color;
}
void orca_log_logfile_clear_on_open_set(bool clear)
{
Orca::Log::Backend::Logfile::_clear_on_open = clear;
}
bool orca_log_logfile_clear_on_open_get(void)
{
return Orca::Log::Backend::Logfile::_clear_on_open;
}
void orca_log(const char* msg)
{
Orca::Log::Backend::_log_stderr(msg, Orca::Log::_log_color.load());
Orca::Log::Backend::_dispatcher(msg, Orca::Log::_log_color);
}
void orca_log_h1(const char* msg)
{
Orca::Log::Backend::_log_stderr(
Orca::Log::Backend::_dispatcher(
Orca::Utils::_decorate_three_lines(msg, '='),
Orca::Log::_log_color.load());
Orca::Log::_log_color);
}
void orca_log_h2(const char* msg)
{
Orca::Log::Backend::_log_stderr(
Orca::Log::Backend::_dispatcher(
"\n" + Orca::Utils::_decorate_centered(msg, '='),
Orca::Log::_log_color.load());
Orca::Log::_log_color);
}
void orca_log_h3(const char* msg)
{
Orca::Log::Backend::_log_stderr(Orca::Utils::_decorate_centered(msg, '-'), Orca::Log::_log_color.load());
Orca::Log::Backend::_dispatcher(
Orca::Utils::_decorate_centered(msg, '-'),
Orca::Log::_log_color);
}
void _orca_log_for_macro(
ORCA_LOG_LEVEL level,
const char* file,
@ -98,7 +142,6 @@ extern "C" {
const char* fmt,
...)
{
std::lock_guard<std::mutex> l{ Orca::Log::_mtx_log };
if (level > Orca::Log::_log_level) {
return;
}
@ -124,7 +167,7 @@ extern "C" {
}
}
free(msg_fmtd);
Orca::Log::log(msg);
Orca::Log::Backend::_dispatcher(msg);
va_end(var_args);
}
@ -145,6 +188,38 @@ extern "C" {
return "invalid log level";
}
}
bool _orca_logfile_open(void)
{
std::lock_guard<std::recursive_mutex> l{ Orca::Log::Backend::Logfile::_mtx_stream };
std::lock_guard<std::recursive_mutex> l2{ Orca::Log::Backend::Logfile::_mtx_path };
if (Orca::Log::Backend::Logfile::_stream.is_open()) {
return true;
}
// Append or clear
unsigned int openmode = std::ios::app;
if (Orca::Log::Backend::Logfile::_clear_on_open) {
openmode = std::ios::out | std::ios::trunc;
}
Orca::Log::Backend::Logfile::_stream.open(Orca::Log::Backend::Logfile::_path, openmode);
if (Orca::Log::Backend::Logfile::_stream.fail()) {
// TODO: Where to log error
std::cerr << "LOGFILE ERROR" << std::endl;
Orca::Log::Backend::Logfile::_stream.clear();
return false;
}
return true;
}
void _orca_logfile_close(void)
{
std::lock_guard<std::recursive_mutex> l{ Orca::Log::Backend::Logfile::_mtx_stream };
Orca::Log::Backend::Logfile::_stream.close();
}
#ifdef __cplusplus
}
#endif
@ -158,25 +233,27 @@ namespace Orca {
// for C++ some functions are just wrappers for the
// C linkage functions
// to be nicely available in the namespace
// C linkage functions are mutexed and therefore
// wrapped here even if otherwise trivial
void set_level(ORCA_LOG_LEVEL level)
{
::orca_log_set_level(level);
::orca_log_level_set(level);
}
ORCA_LOG_LEVEL get_level()
{
return ::orca_log_get_level();
return ::orca_log_level_get();
}
void set_color(ORCA_LOG_COLOR col)
{
::orca_log_set_color(col);
::orca_log_color_set(col);
}
ORCA_LOG_COLOR get_color()
{
return ::orca_log_get_color();
return ::orca_log_color_get();
}
void _log_for_macro(
@ -191,54 +268,96 @@ namespace Orca {
void log(std::string_view msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(msg, col);
Backend::_dispatcher(msg, col);
}
void logH1(std::string_view msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(Utils::_decorate_three_lines(msg, '='), col);
Backend::_dispatcher(Utils::_decorate_three_lines(msg, '='), col);
}
void logH2(std::string_view msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr("\n" + Utils::_decorate_centered(msg, '='), col);
Backend::_dispatcher("\n" + Utils::_decorate_centered(msg, '='), col);
}
void logH3(std::string_view msg, ORCA_LOG_COLOR col)
{
Backend::_log_stderr(Utils::_decorate_centered(msg, '-'), col);
Backend::_dispatcher(Utils::_decorate_centered(msg, '-'), col);
}
namespace Backend {
// TODO: add file backend
void _log_stderr(std::string_view msg, ORCA_LOG_COLOR col)
void _dispatcher(std::string_view 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
_log_file(msg);
Console::_write_stderr(msg, col);
Logfile::_write(msg);
}
void _log_file(std::string_view msg) {
std::lock_guard<std::mutex> l{ _mtx_backend_file };
std::filesystem::path path{ "logfile.log" };
std::ofstream ofs(path);
ofs << msg << std::endl;
ofs.close();
}
} // namespace Backend
} // namespace Log
namespace Console {
void _write_stdout(std::string_view msg, ORCA_LOG_COLOR col)
{
std::lock_guard<std::mutex> l{ _mtx_stdout };
std::cerr << Utils::_to_termcol(col) << msg
<< Utils::_to_termcol(ORCA_LOG_COLOR_RESET)
<< std::endl; //endl also flushes, but cerr is unbuffered anyways
}
void _write_stderr(std::string_view msg, ORCA_LOG_COLOR col)
{
std::lock_guard<std::mutex> l{ _mtx_stderr };
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 Console
namespace Logfile {
void _write(std::string_view msg)
{
std::lock_guard<std::recursive_mutex> l{ _mtx_stream };
if (!_orca_logfile_open()) {
std::cerr << "ERROR: Logfile open failed" << std::endl;
} else {
_stream << msg << std::endl;
if (_stream.fail()) {
std::cerr << "ERROR: Logfile Write failed" << std::endl;
_stream.clear();
}
}
}
void set_path(const std::filesystem::path& path)
{
::orca_log_logfile_path_set(path.c_str());
}
const std::filesystem::path& get_path()
{
std::lock_guard<std::recursive_mutex> l{ Orca::Log::Backend::Logfile::_mtx_path };
return Orca::Log::Backend::Logfile::_path;
}
void set_clear_on_open(bool clear)
{
::orca_log_logfile_clear_on_open_set(clear);
}
bool get_clear_on_open()
{
return ::orca_log_logfile_clear_on_open_get();
}
} // namespace Logfile
} // namespace Backend
} // namespace Log
namespace Utils {
int termsize_x = 120;
std::string _to_termcol(const ORCA_LOG_COLOR& col)
{
switch (col) {
case ORCA_LOG_COLOR_DEFAULT:
// Caution: Make sure Orca::Log::_log_color can
// NEVER be set to ORCA_LOG_COLOR_DEFAULT
return _to_termcol(Orca::Log::_log_color);
case ORCA_LOG_COLOR_RESET:
return "\033[0m";
@ -298,7 +417,7 @@ namespace Orca {
//-------------------------------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level)
{
return o << std::string_view (_orca_log_level_to_string(level));
return o << std::string_view(_orca_log_level_to_string(level));
}
// Stuff like that would be fucking handy

42
src/log.h

@ -15,6 +15,11 @@
#define ORCA_LOG_MACRO_FUNCNAME __func__
#endif
typedef enum {
ORCA_LOG_BACKEND_STDOUT,
ORCA_LOG_BACKEND_STDERR,
ORCA_LOG_BACKEND_FILE
} ORCA_LOG_BACKEND;
typedef enum {
ORCA_LOG_LEVEL_NONE = 0, // Logging Disabled
@ -50,16 +55,23 @@ typedef enum {
#define ORCA_LOG_INFO(...) ORCA_LOG(ORCA_LOG_LEVEL_INFO, __VA_ARGS__)
#define ORCA_LOG(level, ...) \
do { \
#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();
void orca_log_level_set(ORCA_LOG_LEVEL level);
ORCA_LOG_LEVEL orca_log_level_get(void);
void orca_log_logfile_path_set(const char* path);
void orca_log_logfile_path_get(const char** path);
void orca_log_color_set(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR orca_log_color_get(void);
void orca_log_logfile_clear_on_open_set(bool clear);
bool orca_log_logfile_clear_on_open_get(void);
// logging
void orca_log(const char* msg);
@ -84,6 +96,7 @@ void _orca_log_for_macro(
#ifdef __cplusplus
#include <string>
#include <sstream>
#include <filesystem>
#define ORCA_LOG_ERR(msg) ORCA_LOG(ORCA_LOG_LEVEL_ERROR, msg)
@ -106,11 +119,20 @@ namespace Orca {
void set_color(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR get_color();
namespace Backend {
namespace Logfile {
void set_path(const std::filesystem::path& path);
const std::filesystem::path& get_path();
void set_clear_on_open(bool clear);
bool get_clear_on_open();
} // namespace Logfile
} // namespace Backend
// 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);
void log(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH1(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH2(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void logH3(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
// helper function for macro use only
void _log_for_macro(

32
test/test_log.c

@ -7,26 +7,34 @@
// ORCA LOG C usage
int main()
int main(void)
{
// Test Levels
{
ORCA_LOG_ERR("SHOULD NOT SEE THIS");
orca_log_set_level(ORCA_LOG_LEVEL_ALL);
orca_log_level_set(ORCA_LOG_LEVEL_ALL);
ORCA_LOG_ERR();
ORCA_LOG_WARN();
ORCA_LOG_INFO();
orca_log_set_level(ORCA_LOG_LEVEL_ERROR);
orca_log_level_set(ORCA_LOG_LEVEL_ERROR);
ORCA_LOG_ERR();
ORCA_LOG_WARN("SHOULD NOT SEE THIS");
ORCA_LOG_INFO("SHOULD NOT SEE THIS");
}
// Logfile
{
const char *path = NULL;
orca_log_logfile_path_get(&path);
printf("LOGFILE PATH: %s\n", path);
orca_log_logfile_path_set("newlogfile.log");
}
// BASIC USAGE MACRO
{
orca_log_set_level(ORCA_LOG_LEVEL_INFO);
orca_log_level_set(ORCA_LOG_LEVEL_INFO);
// no message
ORCA_LOG_INFO();
@ -44,7 +52,7 @@ int main()
// BASIC USAGE FUNC
{
orca_log_set_level(ORCA_LOG_LEVEL_INFO);
orca_log_level_set(ORCA_LOG_LEVEL_INFO);
// literal
orca_log("Literal RAW");
@ -62,12 +70,12 @@ int main()
{
orca_log_h1("Colors functions only");
orca_log("DEFAULT COLOR");
orca_log_set_color(ORCA_LOG_COLOR_GREEN);
orca_log_color_set(ORCA_LOG_COLOR_GREEN);
orca_log("DEFAULT COLOR AFTER SET GREEN");
orca_log_set_color(ORCA_LOG_COLOR_YELLOW);
orca_log_color_set(ORCA_LOG_COLOR_YELLOW);
strdup("YELLOW ONE OFF");
orca_log(strdup("YELLOW ONE OFF"));
orca_log_set_color(ORCA_LOG_COLOR_RESET);
orca_log_color_set(ORCA_LOG_COLOR_RESET);
orca_log("COLOR RESET");
}
@ -75,11 +83,13 @@ int main()
{
orca_log_h1("Colors using Macros");
orca_log("DEFAULT COLOR");
orca_log_set_color(ORCA_LOG_COLOR_GREEN);
orca_log_color_set(ORCA_LOG_COLOR_GREEN);
ORCA_LOG_ERR("DEFAULT COLOR AFTER SET GREEN");
orca_log_set_color(ORCA_LOG_COLOR_YELLOW);
orca_log_color_set(ORCA_LOG_COLOR_YELLOW);
ORCA_LOG_ERR("YELLOW ONE OFF");
orca_log_set_color(ORCA_LOG_COLOR_RESET);
orca_log_color_set(ORCA_LOG_COLOR_RESET);
ORCA_LOG_ERR("COLOR RESET");
}
orca_log("ALL TEST SUCCESSFUL");
}

9
test/test_log_cxx.cc

@ -25,6 +25,12 @@ int main()
ORCA_LOG_INFO("SHOULD NOT SEE THIS");
}
// Logfile
{
std::cout << " LOGFILE PATH: " << Orca::Log::Backend::Logfile::get_path();
Orca::Log::Backend::Logfile::set_path("newlogfile.log");
}
// BASIC USAGE MACRO
{
Orca::Log::set_level(ORCA_LOG_LEVEL_INFO);
@ -89,6 +95,5 @@ int main()
ORCA_LOG_ERR("DEFAULT COLOR GREEN");
}
// FUNCTIONS
Orca::Log::log("ALL TEST SUCCESSFUL");
}

Loading…
Cancel
Save