46 Commits

Author SHA1 Message Date
c65cc4f965 LogEntry class, prettied up code and log output more, OnLogEvent now takes a LogEntry instead of a vector<token> 2024-08-14 15:12:32 -04:00
7aa30a4966 FUCK YOU C++2 2024-08-14 14:44:33 -04:00
b69ba9650b FUCK YOU C++ 2024-08-14 14:36:06 -04:00
maxine
cde1aa507b Merge pull request 'Doing some cleaning up. There is now a Timestamp type used for log formatting.' (#17) from nomacros into main
Reviewed-on: #17
2024-08-14 12:31:10 -04:00
c5b9d50a2b Doing some cleaning up. There is now a Timestamp type used for log formatting. 2024-08-14 12:31:19 -04:00
maxine
bfb6fc0702 Merge pull request 'nomacros' (#16) from nomacros into main
Reviewed-on: #16
2024-08-13 16:21:49 -04:00
b19e2ea651 Added TODO 2024-08-13 16:16:09 -04:00
18dd697470 Disable color output on Windows for now. 2024-08-13 16:14:48 -04:00
ae46df7006 small fix for windows 2024-08-13 16:08:49 -04:00
eb9a2b26b9 Updated README.md 2024-08-13 16:05:40 -04:00
758925c837 Added "No more macros for traceback!" to README.md 2024-08-13 16:04:18 -04:00
d8439efcaf Updated README. New demo image. Fixed typo in demo. 2024-08-13 16:01:38 -04:00
7b25a097cd Made main.cpp more professional 2024-08-13 15:43:05 -04:00
fe158ab88e Make sure we're all up to date 2024-08-13 15:03:15 -04:00
633bee1e9f Using Color4 for logger color codes now. It's 2024 if your terminal doesn't support 16 million colors your terminal sucks 2024-08-13 14:50:39 -04:00
c735e4baa1 Added OnLogEvent 2024-08-13 14:25:54 -04:00
168af78441 Smoothing it out 2024-08-13 13:40:20 -04:00
96b759d54e Decent-size refactor pt1 2024-08-12 23:21:33 -04:00
1ae346304e Stylistic adjustments 2024-08-12 14:08:15 -04:00
2795756235 parent tracing plus other nice stuff 2024-08-12 13:54:20 -04:00
c17a34f0f1 Rewrote logging class/interface bullshit. Anyway it took a while and there's a lot of cool shit. 2024-08-09 16:01:48 -04:00
404c3dceba Rewrote jlog entirely. Macros are no longer needed thanks to C++ builtin shit. There's a lot to cover, so just read the source code if you actually care. 2024-08-08 14:25:34 -04:00
e0b6879ec5 Confirmed setting default log file to NUL on Windows works the same as /dev/null on Linux. Also placed a forgotten semicolon 2024-07-18 11:00:16 -04:00
73f92d0c1a Default logfile can be set to /dev/null on Linux to disable file logging. Supposedly NUL on Windows will work the same way. 2024-07-18 10:58:32 -04:00
maxine
f7ee1a347e Merge pull request 'Allow disabling of console output for logging. New macro CONSOLELOGGING set to true/false to enable/disable.' (#13) from mcolortest into main
Reviewed-on: #13
2024-07-18 10:49:39 -04:00
aace84af52 Allow disabling of console output for logging. New macro CONSOLELOGGING set to true/false to enable/disable. 2024-07-18 10:48:27 -04:00
maxine
47e06dd8ed Merge pull request 'mcolortest merge' (#12) from mcolortest into main
Reviewed-on: #12
2024-07-18 10:05:45 -04:00
cad79a474a Make jlog log_to_console use mcolor windowsSaneify for Windows platform 2024-07-02 13:33:52 -04:00
67a83bbac4 Removed need for jlog to handle colors. Using mcolor library now. 2024-07-02 13:28:00 -04:00
e553c74ade Cleanup 2024-07-01 14:48:56 -04:00
9d36f07717 Beating Windows and MSVC further into submission. 2024-07-01 14:28:18 -04:00
47caaba587 Forcing abstraction to work with windows and beating windows into submission to work like a good boy 2024-07-01 14:05:12 -04:00
f2651b58df FIx bug causing std::max to be an error in j3ml QuaternionTests 2024-06-28 18:19:22 -04:00
83df783e7c Unfortunate regression to get Windows ColorCodes working again. Will clean up shortly. (Test On Linux Also) 2024-06-28 14:45:04 -04:00
99c1fe9f4c Color output currently broken, see notes. 2024-06-28 14:09:31 -04:00
e0355d2a32 Merge remote-tracking branch 'origin/main' 2024-06-28 13:57:42 -04:00
8e0d99ce75 forgot semiclon 2024-06-28 13:57:42 -04:00
2394f51240 Fix syntax error 2024-06-28 13:57:27 -04:00
e83dd27d31 Made logger more platform agnostic. Hopefully supporting Windows properly for the message formatter functions. 2024-06-28 13:54:11 -04:00
623b9efc26 Accreditations 2024-06-28 13:16:25 -04:00
f74b97ac11 const-ref tokens in loop since they aren't modified here 2024-06-28 13:09:26 -04:00
abb9eed60f use std::function signature in argument? 2024-06-28 13:06:43 -04:00
5675480499 Merge remote-tracking branch 'origin/main' 2024-06-28 12:59:15 -04:00
3e414abc8d Implemented ability to specify custom logfile globally and per-function. Wrote helper functions to make writing custom loggers easier. Still need to work on the windows side of things, but that should be easy. 2024-06-28 12:59:07 -04:00
69ef213d85 More documentation 2024-06-28 12:57:33 -04:00
22e75476f3 Remove several now-unused functions 2024-06-28 12:30:04 -04:00
20 changed files with 668 additions and 928 deletions

View File

@@ -16,13 +16,8 @@ include(cmake/CPM.cmake)
file(GLOB_RECURSE jlog_HEADERS "include/jlog/*.h" "include/jlog/*.hpp")
if(UNIX AND NOT APPLE)
file(GLOB_RECURSE jlog_SRC "src/jlog/linux/*.c" "src/jlog/linux/*.cpp" "src/jlog/shared/*.c" "src/jlog/shared/*.cpp")
endif()
file(GLOB_RECURSE jlog_SRC "src/jlog/*.cpp")
if(WIN32)
file(GLOB_RECURSE jlog_SRC "src/jlog/windows/*.c" "src/jlog/windows/*.cpp" "src/jlog/shared/*.c" "src/jlog/shared/*.cpp")
endif()
include_directories("include")
@@ -31,7 +26,10 @@ CPMAddPackage(
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
)
include_directories(${Event_SOURCE_DIR}/include)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-4.zip
)
if (UNIX)
add_library(jlog SHARED ${jlog_SRC})
@@ -39,8 +37,11 @@ endif()
if (WIN32)
add_library(jlog STATIC ${jlog_SRC})
target_compile_options(jlog PRIVATE /wd4005)
endif()
target_include_directories(jlog PUBLIC ${Event_SOURCE_DIR}/include ${mcolor_SOURCE_DIR}/include)
set_target_properties(jlog PROPERTIES LINKER_LANGUAGE CXX)
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})
@@ -48,7 +49,7 @@ install(FILES ${jlog_HEADERS} DESTINATION include/${PROJECT_NAME})
#add_subdirectory(tests)
target_link_libraries(jlog PRIVATE Event)
target_link_libraries(jlog PUBLIC Event mcolor)
add_executable(LoggerDemo main.cpp)
target_link_libraries(LoggerDemo PUBLIC jlog)

View File

@@ -8,10 +8,11 @@ jlog is a C++ library for logging to file, console, and event callbacks.
* Modern (C++20)
* Static Library
* Color Output
* Color Output (Now in RGB!)
* Logs to file AND console!
* Idiomatic Event callback for hooking into your game engine gui!
* GCC and MSVC support
* No more macros for traceback!
## Installation
@@ -35,17 +36,15 @@ Using jlog is straightforward:
```cpp
#include <jlog.h>
#include <jlog/jlog.hpp>
int main() {
LOGLEVEL(jlog::severity::debug); // <- see jlog::severity for full list of log levels
INFO("This is barely useful information.");
DEBUG("Debugging Information");
VERBOSE("Yadda Yadda Yadda");
WARNING("Slight miscalculation!");
ERROR("Oops, something went wrong.");
FATAL("Unrecoverable Error!!!");
jlog::info("This is barely useful information.");
jlog::debug("Debugging Information");
jlog::verbose("Yadda Yadda Yadda");
jlog::warning("Slight miscalculation!");
jlog::error("Oops, something went wrong.");
jlog::fatal("Unrecoverable Error!!!");
return 0;
}
@@ -58,8 +57,6 @@ int main() {
## TODO
* Custom Contexts: Allow users to specify custom logging contexts for better organization.
* Disable & sort by context (other categories?)
* Documentation
* Thread Safety
* Memory Safety

BIN
img.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

@@ -1,108 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
#include <format>
namespace jlog::ansi_escape_codes
{
inline static const std::string CURSOR_HOME = "\033[H";
inline static const std::string ERASE_SCREEN_AFTER_CURSOR = "\033[0J";
inline static const std::string ERASE_SCREEN_BEFORE_CURSOR = "\033[1J";
inline static const std::string ERASE_SCREEN_ALL = "\033[2J";
inline static const std::string ERASE_LINE_AFTER_CURSOR = "\033[0K";
inline static const std::string ERASE_LINE_BEFORE_CURSOR = "\033[1K";
inline static const std::string ERASE_LINE_ALL = "\033[2K";
inline static const std::string RESET = "\033[0m";
inline static const std::string BOLD = "\033[1m";
inline static const std::string DIM = "\033[2m";
/// These are some examples of private modes, which are not defined by the spec, but are implemented in most terminals.
/// @see xterm control sequences for a more in-depth list.
/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
/// @note While these modes may be supported by most terminals, some may not work in multiplexers like tmux.
inline static const std::string CURSOR_INVISIBLE = "\033[?25l";
inline static const std::string CURSOR_VISIBLE = "\033[?25h";
inline static const std::string RESTORE_SCREEN = "\033[?47l";
inline static const std::string SAVE_SCREEN = "\033[?47h";
inline static const std::string FG_BLACK = "\033[30m";
inline static const std::string FG_RED = "\033[31m";
inline static const std::string FG_GREEN = "\033[32m";
inline static const std::string FG_YELLOW = "\033[33m";
inline static const std::string FG_BLUE = "\033[34m";
inline static const std::string FG_MAGENTA = "\033[35m";
inline static const std::string FG_CYAN = "\033[36m";
inline static const std::string FG_WHITE = "\033[37m";
inline static const std::string FG_DEFAULT = "\033[39m";
inline static const std::string FG_BRIGHT_BLACK = "\033[90m";
inline static const std::string FG_BRIGHT_RED = "\033[91m";
inline static const std::string FG_BRIGHT_GREEN = "\033[92m";
inline static const std::string FG_BRIGHT_YELLOW = "\033[93m";
inline static const std::string FG_BRIGHT_BLUE = "\033[94m";
inline static const std::string FG_BRIGHT_MAGENTA = "\033[95m";
inline static const std::string FG_BRIGHT_CYAN = "\033[96m";
inline static const std::string FG_BRIGHT_WHITE = "\033[97m";
inline static const std::string BG_BLACK = "\033[40m";
inline static const std::string BG_RED = "\033[41m";
inline static const std::string BG_GREEN = "\033[42m";
inline static const std::string BG_YELLOW = "\033[43m";
inline static const std::string BG_BLUE = "\033[44m";
inline static const std::string BG_MAGENTA = "\033[45m";
inline static const std::string BG_CYAN = "\033[46m";
inline static const std::string BG_WHITE = "\033[47m";
inline static const std::string BG_DEFAULT = "\033[49m";
inline static const std::string BG_BRIGHT_BLACK = "\033[100m";
inline static const std::string BG_BRIGHT_RED = "\033[101m";
inline static const std::string BG_BRIGHT_GREEN = "\033[102m";
inline static const std::string BG_BRIGHT_YELLOW = "\033[103m";
inline static const std::string BG_BRIGHT_BLUE = "\033[104m";
inline static const std::string BG_BRIGHT_MAGENTA = "\033[105m";
inline static const std::string BG_BRIGHT_CYAN = "\033[106m";
inline static const std::string BG_BRIGHT_WHITE = "\033[107m";
inline std::string true_color(uint8_t r, uint8_t g, uint8_t b)
{
return std::format("\033[38;2;{};{};{}m", r, g, b);
}
inline std::string cursor_to(int line, int col)
{
return "";
}
inline std::string cursor_up(int lines)
{
return "";
}
inline std::string cursor_down(int lines)
{
return "";
}
inline std::string cursor_left(int cols)
{
return "";
}
inline std::string cursor_right(int cols)
{
return "";
}
inline std::string cursor_to_col(int col)
{
return "";
}
}

View File

@@ -1,52 +0,0 @@
#pragma once
#include <jlog/ansi_escape_codes.hpp>
#include <jlog/nt_color_codes.hpp>
// Platform independent color code mapping
struct colorcode
{
std::string ansi_code;
WORD nt_code;
};
namespace jlog::color_codes
{
static const colorcode FG_BLACK {ansi_escape_codes::FG_BLACK, nt_color_codes::FG_BLACK };
static const colorcode FG_RED {ansi_escape_codes::FG_RED, nt_color_codes::FG_RED };
static const colorcode FG_GREEN {ansi_escape_codes::FG_GREEN, nt_color_codes::FG_GREEN };
static const colorcode FG_YELLOW {ansi_escape_codes::FG_YELLOW, nt_color_codes::FG_YELLOW };
static const colorcode FG_BLUE {ansi_escape_codes::FG_BLUE, nt_color_codes::FG_BLUE };
static const colorcode FG_MAGENTA {ansi_escape_codes::FG_MAGENTA, nt_color_codes::FG_MAGENTA };
static const colorcode FG_CYAN {ansi_escape_codes::FG_CYAN, nt_color_codes::FG_CYAN };
static const colorcode FG_WHITE {ansi_escape_codes::FG_WHITE, nt_color_codes::FG_WHITE };
static const colorcode FG_DEFAULT {ansi_escape_codes::FG_DEFAULT, nt_color_codes::FG_DEFAULT };
static const colorcode FG_BRIGHT_BLACK {ansi_escape_codes::FG_BRIGHT_BLACK, nt_color_codes::FG_BRIGHT_BLACK};
static const colorcode FG_BRIGHT_RED {ansi_escape_codes::FG_BRIGHT_RED, nt_color_codes::FG_BRIGHT_RED};
static const colorcode FG_BRIGHT_GREEN {ansi_escape_codes::FG_BRIGHT_GREEN, nt_color_codes::FG_BRIGHT_GREEN};
static const colorcode FG_BRIGHT_YELLOW {ansi_escape_codes::FG_BRIGHT_YELLOW, nt_color_codes::FG_BRIGHT_YELLOW};
static const colorcode FG_BRIGHT_BLUE {ansi_escape_codes::FG_BRIGHT_MAGENTA, nt_color_codes::FG_BRIGHT_MAGENTA};
static const colorcode FG_BRIGHT_MAGENTA {ansi_escape_codes::FG_BRIGHT_MAGENTA, nt_color_codes::FG_BRIGHT_MAGENTA};
static const colorcode FG_BRIGHT_CYAN {ansi_escape_codes::FG_BRIGHT_CYAN, nt_color_codes::FG_BRIGHT_CYAN};
static const colorcode FG_BRIGHT_WHITE {ansi_escape_codes::FG_BRIGHT_WHITE, nt_color_codes::FG_BRIGHT_WHITE};
static const colorcode BG_BLACK {ansi_escape_codes::BG_BLACK, nt_color_codes::BG_BLACK};
static const colorcode BG_RED {ansi_escape_codes::BG_RED, nt_color_codes::BG_RED};
static const colorcode BG_GREEN {ansi_escape_codes::BG_GREEN, nt_color_codes::BG_GREEN};
static const colorcode BG_YELLOW {ansi_escape_codes::BG_YELLOW, nt_color_codes::BG_YELLOW};
static const colorcode BG_BLUE {ansi_escape_codes::BG_BLUE, nt_color_codes::BG_BLUE};
static const colorcode BG_MAGENTA {ansi_escape_codes::BG_MAGENTA, nt_color_codes::BG_MAGENTA};
static const colorcode BG_CYAN {ansi_escape_codes::BG_CYAN, nt_color_codes::BG_CYAN};
static const colorcode BG_WHITE {ansi_escape_codes::BG_WHITE, nt_color_codes::BG_WHITE};
static const colorcode BG_DEFAULT {ansi_escape_codes::BG_DEFAULT, nt_color_codes::BG_DEFAULT};
static const colorcode BG_BRIGHT_BLACK {ansi_escape_codes::BG_BRIGHT_BLACK, nt_color_codes::BG_BRIGHT_BLACK};
static const colorcode BG_BRIGHT_RED {ansi_escape_codes::BG_BRIGHT_RED, nt_color_codes::BG_BRIGHT_RED};
static const colorcode BG_BRIGHT_GREEN {ansi_escape_codes::BG_BRIGHT_GREEN, nt_color_codes::BG_BRIGHT_GREEN};
static const colorcode BG_BRIGHT_YELLOW {ansi_escape_codes::BG_BRIGHT_YELLOW, nt_color_codes::BG_BRIGHT_YELLOW};
static const colorcode BG_BRIGHT_BLUE {ansi_escape_codes::BG_BRIGHT_BLUE, nt_color_codes::BG_BRIGHT_BLUE};
static const colorcode BG_BRIGHT_MAGENTA {ansi_escape_codes::BG_BRIGHT_MAGENTA, nt_color_codes::BG_BRIGHT_MAGENTA};
static const colorcode BG_BRIGHT_CYAN {ansi_escape_codes::BG_BRIGHT_CYAN, nt_color_codes::BG_BRIGHT_CYAN};
static const colorcode BG_BRIGHT_WHITE {ansi_escape_codes::BG_BRIGHT_WHITE, nt_color_codes::BG_BRIGHT_WHITE};
}

View File

@@ -0,0 +1,66 @@
#pragma once
#include "token.hpp"
namespace jlog {
class Timestamp {
public:
Timestamp();
public:
std::chrono::year Year() {return y;};
std::chrono::month Month() {return m;};
std::chrono::day Day() {return d;}
std::chrono::duration<long, std::ratio<3600>> Hour() {return h;};
std::chrono::duration<long, std::ratio<60>> Minute() {return M;};
std::chrono::duration<long> Second() {return s;};
std::chrono::duration<long, std::ratio<1, 1000>> Millisecond() {return ms;};
private:
std::chrono::year y;
std::chrono::month m;
std::chrono::day d;
std::chrono::duration<long, std::ratio<3600>> h;
std::chrono::duration<long, std::ratio<60>> M;
std::chrono::duration<long> s;
std::chrono::duration<long, std::ratio<1, 1000>> ms;
};
std::vector<token> timestamp_format(Timestamp tstamp);
/// Returns a string timestamp in the format of 'YYYY-MM-DD hh:mm:ss.ms'
std::string get_timestamp();
/// Returns a pseudo-"stacktrace" formatted sequence of tokens.
/// @param func The function name/signature to trace back to. Should be provided by a __FUNCTION__ macro variant.
/// @param file The file name to trace back to. Should be provided by a __FILE__ macro variant.
/// @param line The source-code line to trace back to. Should be provided by a __LINE__ macro variant.
std::vector<token> trace_format(
const std::string &func,
const std::string &file,
int line);
/// Returns a formatted sequence of tokens given a severity and message.
/// @param severity_name The severity tag to prefix to the message. Could theoretically also be a context.
/// @param message The actual message to include
/// @param severity_cc The colorcode to assign to the severity.
std::vector<token> log_format(
const std::string &severity_name,
const std::string &message,
const Color4 &severity_cc = Colors::White);
/// Returns a more detailed formatted sequence of tokens.
/// @param severity_name The severity tag to prefix to the message. Could theoretically also be a context.
/// @param message The actual message to include
/// @param func The function name/signature to trace back to. Should be provided by a __FUNCTION__ macro variant.
/// @param file The file name to trace back to. Should be provided by a __FILE__ macro variant.
/// @param line The source-code line to trace back to. Should be provided by a __LINE__ macro variant.
/// @param severity_cc The colorcode to assign to the severity.
std::vector<token> log_format(
const std::string &severity_name,
const std::string &message,
const std::string &func,
const std::string &file,
int line,
const Color4 &severity_cc = Colors::White);
// Generic token for line ending
//const token endl = {.content = std::endl, .delimiter = ""};
}

29
include/jlog/io.hpp Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <string>
#include <jlog/token.hpp>
namespace jlog
{
/// Writes a std::vector of tokens directly to standard output
void LogToConsole(const std::vector<token>& ts);
/// Writes a std::string directly to standard output
void LogToConsole(const std::string& s);
/// Writes a std::vector of tokens to the specified logfile
void LogToFile(const std::string& filename, const std::vector<token>& ts);
/// Writes a std::string to the specified logfile
void LogToFile(const std::string& filename, const std::string& s);
/*
/// Writes an input string directly to standard output
/// @note Does not append a newline to the message.
void log_to_console(const std::string &message);
/// Writes an input string directly to the specified destination logfile
/// @note Does not append a newline to the message.
void log_to_file(const std::string &filename, const std::string &message);
*/
}

View File

@@ -3,164 +3,32 @@
/// Developed & Maintained by Josh O'Leary
/// This work is dedicated to the public domain.
/// Special thanks: Maxine Hayes, William J Tomasine II
#pragma once
#include <string>
#include <map>
#include <Event.h>
#include <jlog/color_codes.hpp>
#include <mcolor.h>
#include "token.hpp"
#include "formatter.hpp"
#include "source_location"
#include <jlog/logger.hpp>
#ifdef __linux__
#define FUNCTION __PRETTY_FUNCTION__
#endif
namespace jlog {
#ifdef _WIN32
#define FUNCTION __FUNCSIG__
#endif
using namespace mcolor;
namespace jlog
{
/// Severity levels for logging. Higher numbers filter less messages out.
/// @see LOG_LEVEL macro
enum class severity : uint8_t
{
none, // Show no output
fatal, // Show only fatal errors
error, // Show fatal and not-necessarily-fatal errors
warning, // Show warnings additionally
verbose, // Show errors, warnings, and 'verbose' output (i.e. extra information)
debug, // Show debugging messages (Basically everything).
};
/// Built-in Global Loggers
extern Logger info;
extern Logger warning;
extern Logger error;
extern Logger fatal;
extern Logger verbose;
extern Logger debug;
inline severity loglevel = severity::debug; // Default log level always debug
struct LogEntry
{
severity level;
std::string content;
std::string timestamp;
};
// TODO: Fully implement logging callback.
static Event<LogEntry> on_log = Event<LogEntry>();
inline std::vector<LogEntry> log_history;
/// A single piece of a logging message, with color code, content, and delimiter
/// These are strung together to build full logger messages in a flexible manner.
struct token
{
colorcode colorCode = color_codes::FG_DEFAULT;
std::string content = "";
std::string delimiter = "[]";
};
void set_default_logfile(const std::string& filename);
std::string get_timestamp();
/// Writes an input string directly to standard output
/// @note Does not append a newline to the message.
void log_to_console(const std::string& message);
/// Writes an input string directly to the default destination logfile
/// @note Does not append a newline to the message.
/// @see set_default_logfile()
void log_to_file(const std::string& message);
/// Writes an input string directly to the specified destination logfile
/// @note Does not append a newline to the message.
void log_to_file(const std::string& filename, const std::string& message);
/// Writes an input string directly to the specified output stream
/// @note Does not append a newline to the message.
void log_to_stream(std::ostream stream, const std::string& message);
/// Parses a sequence of tokens into a printable message, and logs to the following destinations:
/// standard output (console)
/// output file (default)
/// logging callback (Event)
/// @note This file is implemented differently per-platform to handle differences in console color handling.
/// @see windows/jlog.cpp linux/jlog.cpp
void log(std::vector<token> tokens);
// Generic formatters for building loggers.
std::vector<token> trace_format(
const std::string& func,
const std::string& file,
int line);
std::vector<token> log_format(
const std::string& severity_name,
const std::string& message,
const colorcode& severity_cc = color_codes::FG_WHITE);
std::vector<token> log_detailed_format(
const std::string& severity_name,
const std::string& message,
const std::string& func,
const std::string& file,
int line,
const colorcode& severity_cc = color_codes::FG_WHITE);
// Predefined generic loggers for jlog.
std::vector<token> info_format(const std::string& message);
std::vector<token> info_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
std::vector<token> warning_format(const std::string& message);
std::vector<token> warning_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
std::vector<token> error_format(const std::string& message);
std::vector<token> error_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
std::vector<token> fatal_format(const std::string& message);
std::vector<token> fatal_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
std::vector<token> verbose_format(const std::string& message);
std::vector<token> verbose_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
std::vector<token> debug_format(const std::string& message);
std::vector<token> debug_detailed_format(
const std::string &message,
const std::string &func,
const std::string &file,
int line);
void SetTracebackOnGlobalLoggers(bool enabled);
}
#define INFO(i) if (jlog::loglevel >= jlog::severity::none) { jlog::log(jlog::info_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define VERBOSE(i) if (jlog::loglevel >= jlog::severity::verbose) { jlog::log(jlog::verbose_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define DEBUG(i) if (jlog::loglevel >= jlog::severity::debug) { jlog::log(jlog::debug_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define WARNING(i) if (jlog::loglevel >= jlog::severity::warning) { jlog::log(jlog::warning_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define ERROR(i) if (jlog::loglevel >= jlog::severity::error) { jlog::log(jlog::error_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define FATAL(i) if (jlog::loglevel >= jlog::severity::fatal) { jlog::log(jlog::fatal_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
#define LOGLEVEL(i) jlog::loglevel = i;

69
include/jlog/logger.hpp Normal file
View File

@@ -0,0 +1,69 @@
#pragma once
#include <mcolor.h>
#include "token.hpp"
#include "Color4.hpp"
#include "Colors.hpp"
#include <source_location>
#include <map>
#include <jlog/token.hpp>
#include <Event.h>
#include "formatter.hpp"
namespace jlog
{
using namespace mcolor;
class LogEntry {
public:
LogEntry(Color4 cc, const std::string c, const std::string msg, const std::source_location t, const Timestamp ts);
public:
Color4 ContextColor() { return context_color; }
std::string Context() { return context; }
std::string Message() { return message; }
std::source_location Trace() { return trace; }
jlog::Timestamp GetTimeStamp() { return timestamp; };
virtual std::vector<token> Tokenize();
public:
bool IncludeTrace;
bool IncludeTimestamp;
private:
Color4 context_color;
std::string context;
std::string message;
std::source_location trace;
Timestamp timestamp;
};
class Logger {
public:
explicit Logger(const std::string& context, const Color4& color = Colors::LightGray);
public:
Event<LogEntry> OnLogEvent;
public:
void operator () (const std::string& message, const std::source_location& location = std::source_location::current());
virtual void Log(const std::string &message, const std::source_location& location = std::source_location::current());
public:
void SetEnabled(bool state);
void Enable();
void Disable();
bool Enabled();
void LogFile(const std::string& f);
std::string LogFile();
// no cc no bullshit
void SetColorCode(Color4 cc = Colors::LightGray);
Color4 GetColorCode();
public:
std::string Context();
void SetTraceback(bool b);
void IncludeTimestamp(bool b);
/**/
protected:
bool enabled = true;
std::string logfile = "latest.log";
Color4 colorcode = Colors::LightGray;
std::string context;
bool trace = true;
bool timestamp = true;
};
}

View File

@@ -1,55 +0,0 @@
#pragma once
// NT color codes taken from windows.h / consoleapi2.h
#ifdef WIN32
#include <windows.h>
#endif
#ifndef WORD
#define WORD short
#endif
namespace jlog::nt_color_codes
{
const WORD FG_BLACK = 0x0000;
const WORD FG_BLUE = 0x0001;
const WORD FG_GREEN = 0x0002;
const WORD FG_RED = 0x0004;
const WORD FG_YELLOW = FG_RED | FG_GREEN;
const WORD FG_MAGENTA = FG_RED | FG_BLUE;
const WORD FG_CYAN = FG_GREEN | FG_BLUE;
const WORD FG_WHITE = FG_RED | FG_GREEN | FG_BLUE;
const WORD FG_DEFAULT = FG_WHITE;
const WORD FG_BRIGHT_BLACK = 0 | 0x0008;
const WORD FG_BRIGHT_RED = FG_RED | 0x0008;
const WORD FG_BRIGHT_GREEN = FG_GREEN | 0x0008;
const WORD FG_BRIGHT_YELLOW = FG_RED | FG_GREEN | 0x0008;
const WORD FG_BRIGHT_BLUE = FG_BLUE | 0x0008;
const WORD FG_BRIGHT_MAGENTA = FG_RED | FG_BLUE | 0x0008;
const WORD FG_BRIGHT_CYAN = FG_GREEN | FG_BLUE | 0x0008;
const WORD FG_BRIGHT_WHITE = FG_RED | FG_GREEN | FG_BLUE | 0x0008;
const WORD BG_BLACK = 0x0000;
const WORD BG_BLUE = 0x0010;
const WORD BG_GREEN = 0x0020;
const WORD BG_RED = 0x0040;
const WORD BG_YELLOW = BG_RED | BG_GREEN;
const WORD BG_MAGENTA = BG_RED | BG_BLUE;
const WORD BG_CYAN = BG_GREEN | BG_BLUE;
const WORD BG_WHITE = BG_RED | BG_GREEN | BG_BLUE;
const WORD BG_BRIGHT_BLACK = 0 | 0x0080;
const WORD BG_BRIGHT_RED = BG_RED | 0x0080;
const WORD BG_BRIGHT_GREEN = BG_GREEN | 0x0080;
const WORD BG_BRIGHT_YELLOW = BG_YELLOW | 0x0080;
const WORD BG_BRIGHT_BLUE = BG_BLUE | 0x0080;
const WORD BG_BRIGHT_MAGENTA = BG_RED | BG_BLUE | 0x0080;
const WORD BG_BRIGHT_CYAN = BG_GREEN | BG_BLUE | 0x0080;
const WORD BG_BRIGHT_WHITE = BG_RED | BG_GREEN | BG_BLUE | 0x0080;
const WORD BG_DEFAULT = BG_WHITE;
}

75
include/jlog/token.hpp Normal file
View File

@@ -0,0 +1,75 @@
#pragma once
#include <functional>
#include <mcolor.h>
#include "Colors.hpp"
namespace jlog {
using namespace mcolor;
/// A single piece of a logging message, with color code, content, and delimiter
/// These are strung together to build full logger messages in a flexible manner.
struct token {
Color4 colorCode = Colors::White;
std::string content = "";
std::string delimiter = "[]";
};
//class TokenStringer {
//public:
// virtual std::string Stringer(std::vector<token> ts) = 0;
//};
// I did these after reading the Bjarne book.
// May or may not be a good idea, but it looks cool(?)
class WithColor {
public:
static std::string Stringer(std::vector<token> ts) {
std::string msg;
for (const token &t: ts) {
if (!t.delimiter.empty()) {
msg += std::format("{}{}{}{}{} ",
mcolor::toEscapeCode(t.colorCode),
t.delimiter[0], t.content,
t.delimiter[1],
mcolor::toEscapeCode(AnsiColor::RESET));
} else {
msg += std::format("{}{}{} ",
mcolor::toEscapeCode(t.colorCode),
t.content,
mcolor::toEscapeCode(AnsiColor::RESET));
}
}
return msg;
};
};
class WithoutColor {
public:
static std::string Stringer(std::vector<token> ts) {
std::string msg;
for (const token &t: ts) {
if (!t.delimiter.empty())
msg += std::format("{}{}{} ", t.delimiter[0], t.content, t.delimiter[1]);
else
msg += t.content + " ";
}
return msg;
}
};
// By default we use the WithColor token stringer
template<class S = WithColor>
std::string TokensToString(std::vector<token> ts) {
return S::Stringer(ts);
}
/// These are helper functions designed to be wrapped around for easier custom logger building.
std::string toks2msg(std::vector<token> tokens, std::function<std::string(token)>);
std::string consoleMsgFormatter(token t);
std::string logfileMsgFormatter(token t);
std::string toks2consoleMsg(std::vector<token> tokens);
std::string toks2logfileMsg(std::vector<token> tokens);
}

View File

@@ -4,35 +4,81 @@
// Contact: josh@redacted.cc
// Contributors: william@redacted.cc maxi@redacted.cc
// This work is dedicated to the public domain.
#include <jlog/jlog.hpp>
// Writing custom wrappers for jlog is super easy!
/*void coollog(std::vector<jlog::token> tokens) {
std::vector<jlog::token> wtokens;
auto group = jlog::token{.content = "COOLLOGGER"};
wtokens.push_back(group);
wtokens.insert(wtokens.end(), tokens.begin(), tokens.end());
jlog::log(wtokens);
}*/
// We can either define custom logging macros or redefine jlog's builtin macros.
//#define COOLINFO(i) coollog(jlog::info_format(i));
//#define COOLINFOTRACE(i) coollog(jlog::info_detailed_format(i, FUNCTION, __FILE__, __LINE__));
#include <jlog/io.hpp>
#include <mcolor.h>
int main()
{
LOGLEVEL(jlog::severity::debug); // <- see jlog::severity for full list of log levels
using namespace mcolor;
INFO("This is barely useful information.");
DEBUG("Debugging Information");
VERBOSE("Yadda Yadda Yadda");
WARNING("Slight miscalculation!");
ERROR("Oops, something went wrong.");
FATAL("Unrecoverable Error!!!");
jlog::Logger demo{"demo", Colors::Pinks::DeepPink};
demo.SetTraceback(false);
demo(std::format("{}\n>\t{}\n>\t{}",
"Custom loggers such as this one can be easily created",
"jlog::Logger demo{\"demo\", Colors::Pinks::DeepPink};", "demo.SetTraceback(false);"));
// "Custom loggers such as this one can be easily created."));
//COOLINFO("This is really cool!!!");
//COOLINFOTRACE("THIS IS EVEN COOLER!!!");
// Traceback is enabled on global Loggers by default
demo("Traceback is enabled on global Loggers by default");
jlog::info("info message traceback");
jlog::debug("debug message traceback");
jlog::verbose("verbose message traceback");
jlog::warning("warning message traceback");
jlog::error("error message traceback");
jlog::fatal("fatal message traceback");
// We can disable/enable traceback on a logger
demo("We can disable/enable traceback on a logger");
demo("Disable = demo.SetTraceback(false);");
demo.SetTraceback(true);
demo("Enable = demo.SetTraceback(true);");
demo.SetTraceback(false);
// We can set the traceback for all the global loggers.
demo(std::format("{}\n>\t{}", "We can set the traceback for all the global loggers.", "jlog::SetTracebackOnGlobalLoggers(false);"));
jlog::SetTracebackOnGlobalLoggers(false);
jlog::info("info message");
jlog::debug("debug message");
jlog::verbose("verbose message");
jlog::warning("warning message");
jlog::error("error message");
jlog::fatal("fatal message");
// We can enable/disable loggers.
demo(std::format("{}\n>\t{}\n>\t{}", "We can enable/disable loggers.", "jlog::info.Enable();", "jlog::info.Disable();"));
jlog::info.Enable();
jlog::info("Logger enabled");
jlog::info.Disable();
demo("You won't see the 'Logger disabled' message here since we just disabled it. Check main.cpp for proof.");
jlog::info("Logger disabled");
jlog::info.Enable();
// We can also add event hooks to a logger.
demo(std::format("{}\n>\t{}\n>\t\t{}\n>\n>\t\t{}\n>\t{}",
"We can also add event hooks to a logger.",
"demo.OnLogEvent += [](jlog::LogEntry le) {",
"jlog::token dbg = {.colorCode = jlog::debug.GetColorCode(), .content = \"This message is only seen when the event hook is added.\"};",
"jlog::log_to_console(jlog::toks2consoleMsg(std::vector<jlog::token>{dbg}));",
"}"
));
demo("Before event hook");
// Create and add event hook.
demo.OnLogEvent += [](jlog::LogEntry le) {
jlog::token dbg = {.colorCode = jlog::debug.GetColorCode(), .content = "This message is only seen when the event hook is added."};
//jlog::log_to_console(jlog::toks2consoleMsg(std::vector<jlog::token>{dbg}));
jlog::LogToConsole(std::vector<jlog::token>{dbg});
};
demo("After event hook");
return 0;
}

89
src/jlog/formatter.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include <string>
#include <format>
#include <vector>
#include <chrono>
#include "mcolor.h"
#include "jlog/formatter.hpp"
#include "jlog/token.hpp"
namespace jlog {
Timestamp::Timestamp() {
auto const timestamp = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
auto dp = floor<std::chrono::days>(timestamp);
std::chrono::year_month_day ymd{floor<std::chrono::days>(timestamp)};
std::chrono::hh_mm_ss time{floor<std::chrono::milliseconds>(timestamp - dp)};
y = ymd.year();
m = ymd.month();
d = ymd.day();
h = time.hours();
M = time.minutes();
s = time.seconds();
ms = time.subseconds();
}
// [2024-Aug-14 12:0:58.815]
std::string get_timestamp() {
using namespace std::chrono;
auto const timestamp = current_zone()->to_local(system_clock::now());
auto dp = floor<days>(timestamp);
year_month_day ymd{floor<days>(timestamp)};
hh_mm_ss time{floor<milliseconds>(timestamp - dp)};
auto y = ymd.year();
auto m = ymd.month();
auto d = ymd.day();
auto h = time.hours();
auto M = time.minutes();
auto s = time.seconds();
auto ms = time.subseconds();
return std::format("{}-{}-{} {}:{}:{}.{}", y, m, d, h.count(), M.count(), s.count(), ms.count());
}
//[2024-Aug-14 12:0:58.815]
std::vector<token> timestamp_format(Timestamp tstamp) {
return std::vector<token>{{.content = std::format("{}-{}-{} {}:{}:{}.{}", tstamp.Year(), tstamp.Month(), tstamp.Day(), tstamp.Hour().count(), tstamp.Minute().count(), tstamp.Second().count(), tstamp.Millisecond().count())}};
}
std::vector<token> trace_format(
const std::string& func,
const std::string& file,
int line)
{
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
return {trace, filedata};
}
std::vector<token> log_format(
const std::string& severity_name,
const std::string& message,
const Color4& severity_cc)
{
auto severity = token{.colorCode = severity_cc, .content = severity_name};
auto content = token{.content = message, .delimiter = ""};
return {severity, content};
}
std::vector<token> log_format(
const std::string& severity_name,
const std::string& message,
const std::string& func,
const std::string& file,
int line,
const Color4& severity_cc)
{
std::vector<token> tokens;
//auto timestamp = token{.content = jlog::get_timestamp()};
auto tsf_tokens = jlog::timestamp_format(Timestamp());
auto tf_tokens = jlog::trace_format(func, file, line);
auto lf_tokens = jlog::log_format(severity_name, message, severity_cc);
//tokens.push_back(timestamp);
tokens.insert(tokens.end(), tsf_tokens.begin(), tsf_tokens.end());
tokens.insert(tokens.end(), tf_tokens.begin(), tf_tokens.end());
tokens.insert(tokens.end(), lf_tokens.begin(), lf_tokens.end());
return tokens;
}
}

53
src/jlog/io.cpp Normal file
View File

@@ -0,0 +1,53 @@
#include <mcolor.h>
#include <jlog/token.hpp>
#include <jlog/io.hpp>
#include <fstream>
#include <iostream>
#include <chrono>
namespace jlog
{
// Is there really a need for this? No, I'm just being consistent.
void LogToConsole(const std::string& s) {
std::cout << s;
}
void LogToConsole(const std::vector<token>& ts) {
// Disable color output on Windows for now.
#ifdef WIN32
//std::cout << TokensToString<WithoutColor>(ts);
LogToConsole(TokensToString<WithoutColor>(ts));
#else
//std::cout << TokensToString(ts);//<< std::endl;
LogToConsole(TokensToString(ts));
#endif
}
void LogToFile(const std::string& filename, const std::string& s) {
std::ofstream logfile(filename, std::ios_base::app);
logfile << s;// << std::endl;
logfile.close();
}
void LogToFile(const std::string& filename, const std::vector<token>& ts) {
LogToFile(filename, TokensToString<WithoutColor>(ts));
}
/*
void log_to_console(const std::string& message)
{
#ifdef WIN32
mcolor::windowsSaneify();
#endif
std::cout << message;
}
void log_to_file(const std::string& filename, const std::string& message)
{
std::ofstream latest_log(filename, std::ios_base::app);
latest_log << message;
latest_log.close();
}
*/
}

30
src/jlog/jlog.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include <jlog/jlog.hpp>
#include <fstream>
#include <iostream>
#include <chrono>
/*
#ifdef WIN32
#define NOMINMAX
#include <windows.h>
#endif
*/
namespace jlog
{
Logger info {"info", Colors::Primary::Green};
Logger warning {"warning", Colors::Primary::Yellow};
Logger error {"error", Colors::Primary::Red};
Logger fatal {"fatal", Colors::Reds::Crimson};
Logger verbose {"verbose", Colors::Primary::Blue};
Logger debug {"debug", Colors::Purples::Purple};
void SetTracebackOnGlobalLoggers(bool enabled) {
info.SetTraceback(enabled);
warning.SetTraceback(enabled);
error.SetTraceback(enabled);
fatal.SetTraceback(enabled);
verbose.SetTraceback(enabled);
debug.SetTraceback(enabled);
}
}

View File

@@ -1,17 +0,0 @@
#include <jlog/jlog.hpp>
namespace jlog {
void log(std::vector<token> tokens) {
for (token t: tokens) {
if (!t.delimiter.empty())
log_to_console(std::format("{}{}{}{}{} ", t.colorCode.ansi_code, t.delimiter[0], t.content, t.delimiter[1], ansi_escape_codes::RESET)),
log_to_file(std::format("{}{}{} ", t.delimiter[0], t.content, t.delimiter[1]));
else
log_to_console(std::format("{}{}{} ", t.colorCode.ansi_code, t.content, ansi_escape_codes::RESET)),
log_to_file(t.content + " ");
}
log_to_console("\n");
log_to_file("\n");
}
}

92
src/jlog/logger.cpp Normal file
View File

@@ -0,0 +1,92 @@
#include <jlog/logger.hpp>
#include <jlog/jlog.hpp>
#include <jlog/formatter.hpp>
#include <jlog/token.hpp>
#include "jlog/io.hpp"
namespace jlog
{
LogEntry::LogEntry(Color4 cc, const std::string c, const std::string msg, const std::source_location t, const Timestamp ts) {
this->context_color = cc;
this->context = c;
this->message = msg;
this->trace = t;
this->timestamp = ts;
};
std::vector<token> LogEntry::Tokenize() {
std::vector<token> tokens;
if (IncludeTimestamp)
tokens.push_back({.colorCode = Colors::Gray, .content = std::format(
"{}-{}-{} {}:{}:{}.{}",
timestamp.Year(),
timestamp.Month(),
timestamp.Day(),
timestamp.Hour().count(),
timestamp.Minute().count(),
timestamp.Second().count(),
timestamp.Millisecond().count())});
tokens.push_back({.colorCode = context_color, .content = context});
if (IncludeTrace) {
tokens.push_back({.colorCode = Colors::Gray, .content = trace.function_name()});
tokens.push_back({.colorCode = Colors::Gray, .content = std::format("{}:{}",trace.file_name(), trace.line())});
}
tokens.push_back({.colorCode = Colors::Gray, .content = ">>", .delimiter = ""});
tokens.push_back({.colorCode = Colors::Gray, .content = message, .delimiter = ""});
return tokens;
}
Logger::Logger(const std::string& context, const Color4& color) {
this->context = context;
this->colorcode = color;
}
void Logger::Log(const std::string &message, const std::source_location& location) {
if (!enabled)
return;
LogEntry logentry = {colorcode, context, message, location, Timestamp()};
logentry.IncludeTrace = this->trace;
logentry.IncludeTimestamp = this->timestamp;
OnLogEvent(logentry);
LogToConsole(logentry.Tokenize());
LogToConsole("\n");
LogToFile(logfile, logentry.Tokenize());
LogToFile(logfile, "\n");
}
void Logger::SetEnabled(bool state) {
this->enabled = state;
}
bool Logger::Enabled() { return this->enabled; }
void Logger::LogFile(const std::string& f) {
this->logfile = f;
}
std::string Logger::LogFile() { return this->logfile; }
void Logger::SetColorCode(Color4 cc) { this->colorcode = cc; }
Color4 Logger::GetColorCode() { return this->colorcode; }
std::string Logger::Context() { return this->context; }
void Logger::operator()(const std::string &message, const std::source_location& location) {
Log(message, location);
}
void Logger::SetTraceback(bool b) {
trace = b;
}
void Logger::Enable() { SetEnabled(true);}
void Logger::Disable() { SetEnabled(false); }
}

View File

@@ -1,475 +0,0 @@
#include <jlog/jlog.hpp>
#include <fstream>
#include <iostream>
#include <chrono>
namespace jlog
{
static std::string default_logfile = "latest.log";
void set_default_logfile(const std::string& filename)
{
default_logfile = filename;
}
std::string get_timestamp()
{
using namespace std::chrono;
auto const timestamp = current_zone()->to_local(system_clock::now());
auto dp = floor<days>(timestamp);
year_month_day ymd{floor<days>(timestamp)};
hh_mm_ss time{floor<milliseconds>(timestamp - dp)};
auto y = ymd.year();
auto m = ymd.month();
auto d = ymd.day();
auto h = time.hours();
auto M = time.minutes();
auto s = time.seconds();
auto ms = time.subseconds();
return std::format("{}-{}-{} {}:{}:{}.{}", y, m, d, h.count(), M.count(), s.count(), ms.count());
}
void log_to_console(const std::string& message)
{
std::cout << message;
}
void log_to_file(const std::string& message)
{
std::ofstream latest_log(default_logfile, std::ios_base::app);
latest_log << message;
latest_log.close();
}
void log_to_file(const std::string& filename, const std::string& message)
{
std::ofstream latest_log(filename, std::ios_base::app);
latest_log << message;
latest_log.close();
}
void log_to_stream(std::ostream stream, const std::string& message)
{
stream << message;
}
std::vector<token> trace_format(
const std::string& func,
const std::string& file,
int line)
{
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
return {trace, filedata};
}
std::vector<token> info_format(const std::string& message)
{
return log_format("INFO", message);
}
std::vector<token> warning_format(const std::string& message)
{
return log_format("INFO", message, color_codes::FG_YELLOW);
}
std::vector<token> error_format(const std::string& message)
{
return log_format("ERROR", message, color_codes::FG_RED);
}
std::vector<token> verbose_format(const std::string& message)
{
return log_format("VERBOSE", message, color_codes::FG_CYAN);
}
std::vector<token> debug_format(const std::string& message)
{
return log_format("DEBUG", message, color_codes::FG_GREEN);
}
std::vector<token> debug_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("DEBUG", message, func, file, line, color_codes::FG_GREEN);
}
void direct(const std::string& message)
{
log({{.content = message, .delimiter = ""}});
}
void info(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void sinfo(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usinfo(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void verbose(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void sverbose(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usverbose(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void debug(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void sdebug(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usdebug(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void warning(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void swarning(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void uswarning(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void error(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void serror(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void userror(const std::string& message)
{
auto severity = token{.colorCode = color_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void fatal(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void sfatal(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usfatal(const std::string& message)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
std::vector<token> info_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("INFO", message, func, file, line);
}
std::vector<token> warning_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("WARNING", message, func, file, line, color_codes::FG_YELLOW);
}
std::vector<token> error_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("ERROR", message, func, file, line, color_codes::FG_RED);
}
std::vector<token> fatal_format(const std::string& message)
{
return log_format("FATAL", message, color_codes::FG_BRIGHT_RED);
}
std::vector<token> verbose_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("VERBOSE", message, func, file, line, color_codes::FG_CYAN);
}
std::vector<token> fatal_detailed_format(
const std::string& message,
const std::string& func,
const std::string& file,
int line)
{
return log_detailed_format("FATAL", message, func, file, line, color_codes::FG_BRIGHT_RED);
}
std::vector<token> log_format(
const std::string& severity_name,
const std::string& message,
const colorcode& severity_cc)
{
auto severity = token{.colorCode = severity_cc, .content = severity_name};
auto content = token{.content = message, .delimiter = ""};
return {severity, content};
}
std::vector<token> log_detailed_format(
const std::string& severity_name,
const std::string& message,
const std::string& func,
const std::string& file,
int line,
const colorcode& severity_cc)
{
std::vector<token> tokens;
auto timestamp = token{.content = jlog::get_timestamp()};
auto tf_tokens = jlog::trace_format(func, file, line);
auto lf_tokens = jlog::log_format(severity_name, message, severity_cc);
tokens.push_back(timestamp);
tokens.insert(tokens.end(), tf_tokens.begin(), tf_tokens.end());
tokens.insert(tokens.end(), lf_tokens.begin(), lf_tokens.end());
return tokens;
}
void info_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void sinfo_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void usinfo_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void verbose_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void sverbose_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void usverbose_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void debug_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void sdebug_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void usdebug_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void warning_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void swarning_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void uswarning_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void error_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_GREEN, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void serror_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void userror_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void fatal_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({timestamp, trace, filedata, severity, content});
}
void sfatal_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto timestamp = token{.content = jlog::get_timestamp()};
auto severity = token{.colorCode = color_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
auto trace = token{.content = func};
auto filedata = token{.content = std::format("{}:{}", file, line)};
log({trace, filedata, severity, content});
}
void usfatal_spec(const std::string& message, const std::string& func, const std::string& file, int line)
{
auto severity = token{.colorCode = color_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
}

60
src/jlog/token.cpp Normal file
View File

@@ -0,0 +1,60 @@
#include <string>
#include <vector>
#include <functional>
#include <format>
#include <mcolor.h>
#include <jlog/token.hpp>
namespace jlog {
//template<class S = WithColor>
//template<class S>
//std::string TokensToString(std::vector<token> ts) {
// return S::Stringer(ts);
//}
std::string toks2msg(std::vector <token> tokens, std::function<std::string(token)> formatter) {
std::string msg;
for (const token &t: tokens) {
msg += formatter(t);
}
return msg;
}
std::string toks2consoleMsg(std::vector <token> tokens) {
return toks2msg(tokens, consoleMsgFormatter);
}
std::string toks2logfileMsg(std::vector <token> tokens) {
return toks2msg(tokens, logfileMsgFormatter);
}
std::string consoleMsgFormatter(token t) {
// Just disable color output on Windows for now
// TODO: Figure out why ANSI RGB isn't working quite right on Windows
#ifdef WIN32
if (!t.delimiter.empty()) {
return std::format("{}{}{} ", t.delimiter[0], t.content, t.delimiter[1]);
}
return t.content + " ";
#else
if (!t.delimiter.empty()) {
return std::format("{}{}{}{}{} ", mcolor::toEscapeCode(t.colorCode), t.delimiter[0], t.content,
t.delimiter[1], mcolor::toEscapeCode(AnsiColor::RESET));
}
return std::format("{}{}{} ", mcolor::toEscapeCode(t.colorCode), t.content,
mcolor::toEscapeCode(AnsiColor::RESET));
#endif
}
std::string logfileMsgFormatter(token t) {
if (!t.delimiter.empty()) {
return std::format("{}{}{} ", t.delimiter[0], t.content, t.delimiter[1]);
}
return t.content + " ";
}
}

View File

@@ -1,28 +0,0 @@
#include <jlog/jlog.hpp>
#include <string>
inline void SetConsoleTextColor(WORD color) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
namespace jlog
{
void log(const std::vector<token> tokens) {
for (const token& t : tokens) {
if (!t.delimiter.empty()) {
SetConsoleTextColor(t.colorCode.nt_code);
log_to_console(std::string(1, t.delimiter[0]) + t.content + std::string(1, t.delimiter[1]) + " ");
log_to_file(std::string(1, t.delimiter[0]) + t.content + std::string(1, t.delimiter[1]) + " ");
} else {
SetConsoleTextColor(t.colorCode.nt_code);
log_to_console(t.content + " ");
log_to_file(t.content + " ");
}
}
SetConsoleTextColor(color_codes::FG_DEFAULT.nt_code);
log_to_console("\n");
log_to_file("\n");
}
}