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 <thread>
#include <string_view> #include <string_view>
#include <cmath> #include <cmath>
#include <filesystem>
#include <fstream>
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
// Private functions Prototypes // Internal functions Prototypes
// Global State
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level); const char* _orca_log_level_to_string(const ORCA_LOG_LEVEL* level);
bool _orca_logfile_open(void);
void _orca_logfile_close(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
namespace Orca { namespace Orca {
namespace Utils { namespace Utils {
std::atomic<int> termsize_x = 120;
std::string _to_termcol(const ORCA_LOG_COLOR& col); std::string _to_termcol(const ORCA_LOG_COLOR& col);
std::string _decorate_three_lines(std::string_view msg, char decoration = '-'); std::string _decorate_three_lines(std::string_view msg, char decoration = '-');
std::string _decorate_centered(std::string_view msg, char decoration = '-'); std::string _decorate_centered(std::string_view msg, char decoration = '-');
} // namespace Utils } // namespace Utils
namespace Log { namespace Log {
std::mutex _mtx_log{};
std::atomic<ORCA_LOG_LEVEL> _log_level{ ORCA_LOG_LEVEL_NONE }; std::atomic<ORCA_LOG_LEVEL> _log_level{ ORCA_LOG_LEVEL_NONE };
std::atomic<ORCA_LOG_COLOR> _log_color{ ORCA_LOG_COLOR_WHITE }; std::atomic<ORCA_LOG_COLOR> _log_color{ ORCA_LOG_COLOR_WHITE };
namespace Backend { namespace Backend {
void _log_stderr(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT); void _dispatcher(std::string_view msg, ORCA_LOG_COLOR col = ORCA_LOG_COLOR_DEFAULT);
void _log_file(std::string_view msg); namespace Console {
} std::mutex _mtx_stdout{};
} // namespace Log 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 } // namespace Orca
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
@ -41,55 +59,81 @@ namespace Orca {
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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) { if (col == ORCA_LOG_COLOR_DEFAULT) {
col = ORCA_LOG_COLOR_RESET; 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) 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) void orca_log_h1(const char* msg)
{ {
Orca::Log::Backend::_log_stderr( Orca::Log::Backend::_dispatcher(
Orca::Utils::_decorate_three_lines(msg, '='), Orca::Utils::_decorate_three_lines(msg, '='),
Orca::Log::_log_color.load()); Orca::Log::_log_color);
} }
void orca_log_h2(const char* msg) void orca_log_h2(const char* msg)
{ {
Orca::Log::Backend::_log_stderr( Orca::Log::Backend::_dispatcher(
"\n" + Orca::Utils::_decorate_centered(msg, '='), "\n" + Orca::Utils::_decorate_centered(msg, '='),
Orca::Log::_log_color.load()); Orca::Log::_log_color);
} }
void orca_log_h3(const char* msg) 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( void _orca_log_for_macro(
ORCA_LOG_LEVEL level, ORCA_LOG_LEVEL level,
const char* file, const char* file,
@ -98,7 +142,6 @@ extern "C" {
const char* fmt, const char* fmt,
...) ...)
{ {
std::lock_guard<std::mutex> l{ Orca::Log::_mtx_log };
if (level > Orca::Log::_log_level) { if (level > Orca::Log::_log_level) {
return; return;
} }
@ -124,7 +167,7 @@ extern "C" {
} }
} }
free(msg_fmtd); free(msg_fmtd);
Orca::Log::log(msg); Orca::Log::Backend::_dispatcher(msg);
va_end(var_args); va_end(var_args);
} }
@ -145,6 +188,38 @@ extern "C" {
return "invalid log level"; 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 #ifdef __cplusplus
} }
#endif #endif
@ -158,25 +233,27 @@ namespace Orca {
// for C++ some functions are just wrappers for the // for C++ some functions are just wrappers for the
// C linkage functions // C linkage functions
// to be nicely available in the namespace // 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) void set_level(ORCA_LOG_LEVEL level)
{ {
::orca_log_set_level(level); ::orca_log_level_set(level);
} }
ORCA_LOG_LEVEL get_level() ORCA_LOG_LEVEL get_level()
{ {
return ::orca_log_get_level(); return ::orca_log_level_get();
} }
void set_color(ORCA_LOG_COLOR col) void set_color(ORCA_LOG_COLOR col)
{ {
::orca_log_set_color(col); ::orca_log_color_set(col);
} }
ORCA_LOG_COLOR get_color() ORCA_LOG_COLOR get_color()
{ {
return ::orca_log_get_color(); return ::orca_log_color_get();
} }
void _log_for_macro( void _log_for_macro(
@ -191,54 +268,96 @@ namespace Orca {
void log(std::string_view msg, ORCA_LOG_COLOR col) 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) 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) 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) 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 { namespace Backend {
// TODO: add file backend void _dispatcher(std::string_view msg, ORCA_LOG_COLOR col)
void _log_stderr(std::string_view msg, ORCA_LOG_COLOR col)
{ {
std::lock_guard<std::mutex> l{ _mtx_raw_log }; Console::_write_stderr(msg, col);
std::cerr << Utils::_to_termcol(col) << msg Logfile::_write(msg);
<< Utils::_to_termcol(ORCA_LOG_COLOR_RESET)
<< std::endl; //endl also flushes, but cerr is unbuffered anyways
_log_file(msg);
} }
void _log_file(std::string_view msg) { namespace Console {
std::lock_guard<std::mutex> l{ _mtx_backend_file }; void _write_stdout(std::string_view msg, ORCA_LOG_COLOR col)
std::filesystem::path path{ "logfile.log" }; {
std::lock_guard<std::mutex> l{ _mtx_stdout };
std::ofstream ofs(path); std::cerr << Utils::_to_termcol(col) << msg
ofs << msg << std::endl; << Utils::_to_termcol(ORCA_LOG_COLOR_RESET)
ofs.close(); << std::endl; //endl also flushes, but cerr is unbuffered anyways
} }
} // namespace Backend void _write_stderr(std::string_view msg, ORCA_LOG_COLOR col)
} // namespace Log {
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 { namespace Utils {
int termsize_x = 120;
std::string _to_termcol(const ORCA_LOG_COLOR& col) std::string _to_termcol(const ORCA_LOG_COLOR& col)
{ {
switch (col) { switch (col) {
case ORCA_LOG_COLOR_DEFAULT: 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); return _to_termcol(Orca::Log::_log_color);
case ORCA_LOG_COLOR_RESET: case ORCA_LOG_COLOR_RESET:
return "\033[0m"; return "\033[0m";
@ -298,7 +417,7 @@ namespace Orca {
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& o, const ORCA_LOG_LEVEL* level) 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 // Stuff like that would be fucking handy

42
src/log.h

@ -15,6 +15,11 @@
#define ORCA_LOG_MACRO_FUNCNAME __func__ #define ORCA_LOG_MACRO_FUNCNAME __func__
#endif #endif
typedef enum {
ORCA_LOG_BACKEND_STDOUT,
ORCA_LOG_BACKEND_STDERR,
ORCA_LOG_BACKEND_FILE
} ORCA_LOG_BACKEND;
typedef enum { typedef enum {
ORCA_LOG_LEVEL_NONE = 0, // Logging Disabled 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_INFO(...) ORCA_LOG(ORCA_LOG_LEVEL_INFO, __VA_ARGS__)
#define ORCA_LOG(level, ...) \ #define ORCA_LOG(level, ...) \
do { \ do { \
_orca_log_for_macro(level, __FILE__, __LINE__, ORCA_LOG_MACRO_FUNCNAME, "" __VA_ARGS__); \ _orca_log_for_macro(level, __FILE__, __LINE__, ORCA_LOG_MACRO_FUNCNAME, "" __VA_ARGS__); \
} while (0) } while (0)
// config/settings // config/settings
void orca_log_set_level(ORCA_LOG_LEVEL level); void orca_log_level_set(ORCA_LOG_LEVEL level);
ORCA_LOG_LEVEL orca_log_get_level(); ORCA_LOG_LEVEL orca_log_level_get(void);
void orca_log_set_color(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR orca_log_get_color(); 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 // logging
void orca_log(const char* msg); void orca_log(const char* msg);
@ -84,6 +96,7 @@ void _orca_log_for_macro(
#ifdef __cplusplus #ifdef __cplusplus
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <filesystem>
#define ORCA_LOG_ERR(msg) ORCA_LOG(ORCA_LOG_LEVEL_ERROR, msg) #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); void set_color(ORCA_LOG_COLOR col);
ORCA_LOG_COLOR get_color(); 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 // logging
void log(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(const std::string& 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(const std::string& 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(const std::string& 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 // helper function for macro use only
void _log_for_macro( void _log_for_macro(

32
test/test_log.c

@ -7,26 +7,34 @@
// ORCA LOG C usage // ORCA LOG C usage
int main() int main(void)
{ {
// Test Levels // Test Levels
{ {
ORCA_LOG_ERR("SHOULD NOT SEE THIS"); 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_ERR();
ORCA_LOG_WARN(); ORCA_LOG_WARN();
ORCA_LOG_INFO(); ORCA_LOG_INFO();
orca_log_set_level(ORCA_LOG_LEVEL_ERROR); orca_log_level_set(ORCA_LOG_LEVEL_ERROR);
ORCA_LOG_ERR(); ORCA_LOG_ERR();
ORCA_LOG_WARN("SHOULD NOT SEE THIS"); ORCA_LOG_WARN("SHOULD NOT SEE THIS");
ORCA_LOG_INFO("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 // BASIC USAGE MACRO
{ {
orca_log_set_level(ORCA_LOG_LEVEL_INFO); orca_log_level_set(ORCA_LOG_LEVEL_INFO);
// no message // no message
ORCA_LOG_INFO(); ORCA_LOG_INFO();
@ -44,7 +52,7 @@ int main()
// BASIC USAGE FUNC // BASIC USAGE FUNC
{ {
orca_log_set_level(ORCA_LOG_LEVEL_INFO); orca_log_level_set(ORCA_LOG_LEVEL_INFO);
// literal // literal
orca_log("Literal RAW"); orca_log("Literal RAW");
@ -62,12 +70,12 @@ int main()
{ {
orca_log_h1("Colors functions only"); orca_log_h1("Colors functions only");
orca_log("DEFAULT COLOR"); 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("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"); strdup("YELLOW ONE OFF");
orca_log(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"); orca_log("COLOR RESET");
} }
@ -75,11 +83,13 @@ int main()
{ {
orca_log_h1("Colors using Macros"); orca_log_h1("Colors using Macros");
orca_log("DEFAULT COLOR"); 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_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_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_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"); 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 // BASIC USAGE MACRO
{ {
Orca::Log::set_level(ORCA_LOG_LEVEL_INFO); Orca::Log::set_level(ORCA_LOG_LEVEL_INFO);
@ -89,6 +95,5 @@ int main()
ORCA_LOG_ERR("DEFAULT COLOR GREEN"); ORCA_LOG_ERR("DEFAULT COLOR GREEN");
} }
Orca::Log::log("ALL TEST SUCCESSFUL");
// FUNCTIONS
} }

Loading…
Cancel
Save