55 Commits

Author SHA1 Message Date
c5b9d50a2b Doing some cleaning up. There is now a Timestamp type used for log formatting. 2024-08-14 12:31:19 -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
e5d8ea5faa Removed unused include "format" 2024-06-28 09:43:31 -04:00
e870007004 Beginning documentation effort. 2024-06-27 15:09:10 -04:00
4138b45404 Implement basic capability to log to specified file. 2024-06-27 14:57:14 -04:00
f0ccdf00c0 consolidate as much as possible 2024-06-26 21:19:04 -04:00
Redacted
9f0ccef302 Refactor to abstract platform-specific colorcodes away from the higher-level API 2024-06-26 19:17:12 -04:00
c5d3f7dc82 Updated README.md 2024-06-19 11:26:53 -04:00
aaa7318672 Merge remote-tracking branch 'origin/main' 2024-06-19 11:25:01 -04:00
95f2c761c7 Rewritten most functionality to be more generic and flexible. Cleaned up code as well. Implemented formatter system for easier wrapping. Made it easier for custom loggers to be built from jlog generics and primitives. Removed unused ultra short and short loggers to remove clutter. 2024-06-19 11:23:57 -04:00
Redacted
16d1eaa1ee Update README.md 2024-06-18 21:49:22 -04:00
Redacted
80d9bcd240 Update include/jlog/jlog.hpp
Fix definition clash when using in multiple projects.
2024-06-18 14:40:31 -04:00
2799c918b8 Implemented log level handling/switching. Use LOGLEVEL macro for setting level/severity. See jlog::severity in jlog.hpp for more information. 2024-06-18 12:11:41 -04:00
a86e70a055 Merge remote-tracking branch 'origin/main' 2024-06-18 11:10:20 -04:00
3cf70f5f4f removed todo from README 2024-06-18 11:10:13 -04:00
3a28d4e43b Update ansi_escape_codes.hpp
Fix problem that'd sometimes cause errors when using the macros in a lot of different files.
2024-06-18 00:44:07 -04:00
17 changed files with 632 additions and 977 deletions

View File

@@ -14,16 +14,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
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")
endif()
file(GLOB_RECURSE jlog_SRC "src/jlog/*.cpp")
if(WIN32)
file(GLOB_RECURSE jlog_SRC "src/jlog/windows/*.c" "src/jlog/windows/*.cpp")
endif()
include_directories("include")
CPMAddPackage(
@@ -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 ${PROJECT_NAME})
target_link_libraries(LoggerDemo PUBLIC jlog)

View File

@@ -8,19 +8,20 @@ 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
Include this repository as a CPM dependency, and link against the library.
(TODO: Show the relevant CMake script lines.)
```cmake
CPMAddPackage(
NAME jlog
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-2.zip
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-7.zip
)
# ...
include_directories(${jlog_SOURCE_DIR}/include)
@@ -30,19 +31,20 @@ target_link_libraries(YourProgram ... jlog)
```
# Usage
Using jlog is straightforward:
```cpp
#include <jlog.h>
#include <jlog/jlog.hpp>
int main() {
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;
}
@@ -55,14 +57,10 @@ int main() {
## TODO
* Custom Contexts: Allow users to specify custom logging contexts for better organization.
* Disable & sort by context (other categories?)
* Custom Formats: Add support for custom log message formats.
* Documentation
* Thread Safety
* Memory Safety
* Stream Support
* Identify File, Line, Function name via macros (I hate macros!!!)
## License

BIN
img.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

@@ -1,139 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
#include <format>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _WIN32
namespace jlog::ansi_escape_codes
{
const WORD FG_BLACK = 0;
const WORD FG_RED = FOREGROUND_RED;
const WORD FG_GREEN = FOREGROUND_GREEN;
const WORD FG_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
const WORD FG_BLUE = FOREGROUND_BLUE;
const WORD FG_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE;
const WORD FG_CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD FG_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD FG_DEFAULT = FG_WHITE;
const WORD FG_BRIGHT_BLACK = 0 | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_RED = FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_GREEN = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_BLUE = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD FG_BRIGHT_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
inline void SetConsoleTextColor(WORD color) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
}
#else
namespace jlog::ansi_escape_codes
{
static const std::string CURSOR_HOME = "\033[H";
static const std::string ERASE_SCREEN_AFTER_CURSOR = "\033[0J";
static const std::string ERASE_SCREEN_BEFORE_CURSOR = "\033[1J";
static const std::string ERASE_SCREEN_ALL = "\033[2J";
static const std::string ERASE_LINE_AFTER_CURSOR = "\033[0K";
static const std::string ERASE_LINE_BEFORE_CURSOR = "\033[1K";
static const std::string ERASE_LINE_ALL = "\033[2K";
static const std::string RESET = "\033[0m";
static const std::string BOLD = "\033[1m";
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.
static const std::string CURSOR_INVISIBLE = "\033[?25l";
static const std::string CURSOR_VISIBLE = "\033[?25h";
static const std::string RESTORE_SCREEN = "\033[?47l";
static const std::string SAVE_SCREEN = "\033[?47h";
static const std::string FG_BLACK = "\033[30m";
static const std::string FG_RED = "\033[31m";
static const std::string FG_GREEN = "\033[32m";
static const std::string FG_YELLOW = "\033[33m";
static const std::string FG_BLUE = "\033[34m";
static const std::string FG_MAGENTA = "\033[35m";
static const std::string FG_CYAN = "\033[36m";
static const std::string FG_WHITE = "\033[37m";
static const std::string FG_DEFAULT = "\033[39m";
static const std::string FG_BRIGHT_BLACK = "\033[90m";
static const std::string FG_BRIGHT_RED = "\033[91m";
static const std::string FG_BRIGHT_GREEN = "\033[92m";
static const std::string FG_BRIGHT_YELLOW = "\033[93m";
static const std::string FG_BRIGHT_BLUE = "\033[94m";
static const std::string FG_BRIGHT_MAGENTA = "\033[95m";
static const std::string FG_BRIGHT_CYAN = "\033[96m";
static const std::string FG_BRIGHT_WHITE = "\033[97m";
static const std::string BG_BLACK = "\033[40m";
static const std::string BG_RED = "\033[41m";
static const std::string BG_GREEN = "\033[42m";
static const std::string BG_YELLOW = "\033[43m";
static const std::string BG_BLUE = "\033[44m";
static const std::string BG_MAGENTA = "\033[45m";
static const std::string BG_CYAN = "\033[46m";
static const std::string BG_WHITE = "\033[47m";
static const std::string BG_DEFAULT = "\033[49m";
static const std::string BG_BRIGHT_BLACK = "\033[100m";
static const std::string BG_BRIGHT_RED = "\033[101m";
static const std::string BG_BRIGHT_GREEN = "\033[102m";
static const std::string BG_BRIGHT_YELLOW = "\033[103m";
static const std::string BG_BRIGHT_BLUE = "\033[104m";
static const std::string BG_BRIGHT_MAGENTA = "\033[105m";
static const std::string BG_BRIGHT_CYAN = "\033[106m";
static const std::string BG_BRIGHT_WHITE = "\033[107m";
std::string true_color(uint8_t r, uint8_t g, uint8_t b)
{
return std::format("\033[38;2;{};{};{}m", r, g, b);
}
std::string cursor_to(int line, int col)
{
return "";
}
std::string cursor_up(int lines)
{
return "";
}
std::string cursor_down(int lines)
{
return "";
}
std::string cursor_left(int cols)
{
return "";
}
std::string cursor_right(int cols)
{
return "";
}
std::string cursor_to_col(int col)
{
return "";
}
}
#endif

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,135 +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 <format>
#include <string>
#include <iostream>
#include <map>
#include <Event.h>
#include <jlog/ansi_escape_codes.hpp>
#ifdef _WIN32
#include <windows.h>
#endif
#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
{
enum class severity
{
none,
verbose,
debug,
warning,
error,
fatal
};
/// Built-in Global Loggers
extern Logger info;
extern Logger warning;
extern Logger error;
extern Logger fatal;
extern Logger verbose;
extern Logger debug;
struct LogEntry
{
severity level;
std::string content;
std::string timestamp;
};
static Event<LogEntry> on_log = Event<LogEntry>();
inline std::vector<LogEntry> log_history;
struct token
{
#ifdef _WIN32
WORD colorCode = ansi_escape_codes::FG_DEFAULT;
#else
std::string colorCode = ansi_escape_codes::RESET;
#endif
std::string content = "";
std::string delimiter = "[]";
};
std::string get_timestamp();
void log_to_console(const std::string& message);
void log_to_file(const std::string& message);
void log(std::vector<token> tokens);
void info(const std::string& message);
void sinfo(const std::string& message);
void usinfo(const std::string& message);
void verbose(const std::string& message);
void sverbose(const std::string& message);
void usverbose(const std::string& message);
void debug(const std::string& message);
void sdebug(const std::string& message);
void usdebug(const std::string& message);
void warning(const std::string& message);
void swarning(const std::string& message);
void uswarning(const std::string& message);
void error(const std::string& message);
void serror(const std::string& message);
void userror(const std::string& message);
void fatal(const std::string& message);
void sfatal(const std::string& message);
void usfatal(const std::string& message);
void info_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void sinfo_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void usinfo_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void verbose_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void sverbose_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void usverbose_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void debug_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void sdebug_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void usdebug_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void warning_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void swarning_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void uswarning_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void error_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void serror_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void userror_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void fatal_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void sfatal_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void usfatal_spec(const std::string& message, const std::string& func, const std::string& file, int line);
void SetTracebackOnGlobalLoggers(bool enabled);
}
#define INFO(i) jlog::info_spec(i, FUNCTION, __FILE__, __LINE__);
#define SINFO(i) jlog::sinfo_spec(i, FUNCTION, __FILE__, __LINE__);
#define USINFO(i) jlog::usinfo_spec(i, FUNCTION, __FILE__, __LINE__);
#define VERBOSE(i) jlog::verbose_spec(i, FUNCTION, __FILE__, __LINE__);
#define SVERBOSE(i) jlog::sverbose_spec(i, FUNCTION, __FILE__, __LINE__);
#define USVERBOSE(i) jlog::usverbose_spec(i, FUNCTION, __FILE__, __LINE__);
#define DEBUG(i) jlog::debug_spec(i, FUNCTION, __FILE__, __LINE__);
#define SDEBUG(i) jlog::sdebug_spec(i, FUNCTION, __FILE__, __LINE__);
#define USDEBUG(i) jlog::usdebug_spec(i, FUNCTION, __FILE__, __LINE__);
#define WARNING(i) jlog::warning_spec(i, FUNCTION, __FILE__, __LINE__);
#define SWARNING(i) jlog::swarning_spec(i, FUNCTION, __FILE__, __LINE__);
#define USWARNING(i) jlog::uswarning_spec(i, FUNCTION, __FILE__, __LINE__);
#define ERROR(i) jlog::error_spec(i, FUNCTION, __FILE__, __LINE__);
#define SERROR(i) jlog::serror_spec(i, FUNCTION, __FILE__, __LINE__);
#define USERROR(i) jlog::userror_spec(i, FUNCTION, __FILE__, __LINE__);
#define FATAL(i) jlog::fatal_spec(i, FUNCTION, __FILE__, __LINE__);
#define SFATAL(i) jlog::sfatal_spec(i, FUNCTION, __FILE__, __LINE__);
#define USFATAL(i) jlog::usfatal_spec(i, FUNCTION, __FILE__, __LINE__);

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

@@ -0,0 +1,51 @@
#pragma once
#include <mcolor.h>
#include "Colors.hpp"
#include <source_location>
#include <map>
#include <jlog/token.hpp>
#include <Event.h>
namespace jlog
{
using namespace mcolor;
///
class Logger {
public:
explicit Logger(const std::string& context, const Color4& color = Colors::LightGray);
public:
Event<std::vector<token>> 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());
//virtual void LogTrace(const std::vector<token> tokens);
//virtual void LogTrace(const std::string& context, const std::string &message);
//virtual void LogTrace(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(AnsiColor cc = AnsiColor::FG_DEFAULT);
//AnsiColor GetColorCode();
void SetColorCode(Color4 cc = Colors::LightGray);
Color4 GetColorCode();
public:
std::string Context();
void SetTraceback(bool enabled);
/**/
protected:
bool enabled = true;
std::string logfile = "latest.log";
//AnsiColor colorcode = AnsiColor::FG_DEFAULT;
Color4 colorcode = Colors::LightGray;
std::string context;
bool trace = true;
};
}

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

@@ -1,30 +1,86 @@
// Josh's Logger
// Minimal, robust, Modern (C++20) Logging Framework
// Created by Joshua O'Leary @ Redacted Software, June 2024
// Contact: josh@redacted.cc
// Contributors: william@redacted.cc maxi@redacted.cc
// This work is dedicated to the public domain.
#include <jlog/jlog.hpp>
#include <jlog/io.hpp>
#include <mcolor.h>
int main()
{
INFO("This is barely useful information.");
DEBUG("Debugging Information");
VERBOSE("Yadda Yadda Yadda");
WARNING("Slight miscalculation!");
ERROR("Oops, something went wrong.");
FATAL("Unrecoverable Error!!!");
using namespace mcolor;
SINFO("This is even less useful information.");
SDEBUG("Shorter Debugging Information");
SVERBOSE("Yadda Yadda");
SWARNING("Minute miscalculation!");
SERROR("Oops, something went wrong, but the programmer used the short error logger so you're fucked!");
SFATAL("Unrecoverable Error, but the programmer used the short fatal logger so you're even more fucked!!!");
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."));
USINFO("This is EVEN less useful information.");
USDEBUG("Ultra compact debugging information.");
USVERBOSE("Isn't this an oxymoron?");
USWARNING("Captain Qwark grade miscalculation!");
USERROR("You're fucked!");
USFATAL("You're super fucked!!!");
// 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 += [](std::vector<jlog::token> t) {",
"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 += [](std::vector<jlog::token> t) {
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;
///
}
//Windows :(

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

@@ -0,0 +1,87 @@
#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,363 +0,0 @@
#include <source_location>
#include <jlog/ansi_escape_codes.hpp>
#include <jlog/jlog.hpp>
#include <string>
#include <fstream>
namespace jlog {
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("latest.log", std::ios_base::app);
latest_log << message;
latest_log.close();
}
void log(std::vector<token> tokens) {
for (token t : tokens) {
if (t.delimiter != "") {
log_to_console(std::format("{}{}{}{}{} ", t.colorCode, 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, t.content, ansi_escape_codes::RESET));
log_to_file(t.content + " ");
}
}
log_to_console("\n");
log_to_file("\n");
}
void direct(const std::string &message) { log({{.content = message, .delimiter=""}});}
void info(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({timestamp, severity, content});
}
void sinfo(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
}
void usinfo(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
}
void verbose(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({timestamp, severity, content});
//log(ansi_escape_codes::FG_CYAN, "VERBOSE", message);
}
void sverbose(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
//log(ansi_escape_codes::FG_CYAN, "VERBOSE", message);
}
void usverbose(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
//log(ansi_escape_codes::FG_CYAN, "VERBOSE", message);
}
void debug(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({timestamp, severity, content});
}
void sdebug(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
}
void usdebug(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
}
void warning(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({timestamp, severity, content});
//log(ansi_escape_codes::FG_YELLOW, "WARNING", message);
}
void uswarning(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
//log(ansi_escape_codes::FG_YELLOW, "WARNING", message);
}
void error(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({timestamp, severity, content});
//log(ansi_escape_codes::FG_RED, "ERROR", message);
}
void userror(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = };
log({severity, content});
//log(ansi_escape_codes::FG_RED, "ERROR", message);
}
void fatal(const std::string &message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({timestamp, severity, content});
}
void usfatal(const std::string &message) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void info_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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});
//log({severity, content});
}
void usinfo_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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});
log({severity, content});
}
void verbose_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({severity, content});
}
void debug_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({severity, content});
}
void warning_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
//auto trace = token{.content = func};
//auto filedata = token{.content = std::format("{}:{}", file, line)};
log({severity, content});
}
void error_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({timestamp, trace, filedata, severity, content});
}
void serror_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
//auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({severity, content});
}
void fatal_spec(const std::string &message, const std::string &func, const std::string &file,
int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({severity, content});
}
}

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

@@ -0,0 +1,66 @@
#include <jlog/logger.hpp>
#include <jlog/jlog.hpp>
#include <jlog/formatter.hpp>
#include <jlog/token.hpp>
#include "jlog/io.hpp"
namespace jlog
{
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;
std::vector<jlog::token> fmt;
if (trace)
fmt = log_format(this->context, message, location.function_name(), location.file_name(), location.line(),this->colorcode);
else
fmt = log_format(this->context, message, this->colorcode);
OnLogEvent(fmt);
//jlog::log_to_console(jlog::toks2consoleMsg(fmt) + '\n');
//jlog::log_to_file(this->logfile, jlog::toks2logfileMsg(fmt) + '\n');
//jlog::log_to_console(jlog::TokensToString(fmt) + '\n');
//jlog::log_to_file(logfile, jlog::TokensToString<WithoutColor>(fmt) + '\n');
LogToConsole(fmt);
LogToConsole("\n");
//LogToConsole(std::vector<token>{jlog::endl});
LogToFile(logfile, fmt);
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(AnsiColor cc) { this->colorcode = cc; }
//AnsiColor Logger::GetColorCode() { return this->colorcode; }
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 enabled) {
trace = enabled;
}
void Logger::Enable() { SetEnabled(true);}
void Logger::Disable() { SetEnabled(false); }
}

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,312 +0,0 @@
#include <source_location>
#include <jlog/ansi_escape_codes.hpp>
#include <jlog/jlog.hpp>
#include <string>
#include <chrono>
#include <fstream>
#include <iostream>
#include <windows.h>
namespace jlog {
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("latest.log", std::ios_base::app);
latest_log << message;
latest_log.close();
}
void log(std::vector<token> tokens) {
for (const token& t : tokens) {
if (!t.delimiter.empty()) {
ansi_escape_codes::SetConsoleTextColor(t.colorCode);
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 {
ansi_escape_codes::SetConsoleTextColor(t.colorCode);
log_to_console(t.content + " ");
log_to_file(t.content + " ");
}
}
ansi_escape_codes::SetConsoleTextColor(ansi_escape_codes::FG_DEFAULT);
log_to_console("\n");
log_to_file("\n");
}
void direct(const std::string& message) {
log({{.content = message, .delimiter = ""}});
}
void info(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usinfo(const std::string& message) {
auto severity = token{.colorCode = ansi_escape_codes::FG_WHITE, .content = "INFO"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void verbose(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usverbose(const std::string& message) {
auto severity = token{.colorCode = ansi_escape_codes::FG_CYAN, .content = "VERBOSE"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void debug(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void usdebug(const std::string& message) {
auto severity = token{.colorCode = ansi_escape_codes::FG_GREEN, .content = "DEBUG"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void warning(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void uswarning(const std::string& message) {
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .content = "WARNING"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void error(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void userror(const std::string& message) {
auto severity = token{.colorCode = ansi_escape_codes::FG_RED, .content = "ERROR"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void fatal(const std::string& message) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
void info_spec(const std::string& message, const std::string& func, const std::string& file, int line) {
auto timestamp = token{.content = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_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 = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_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 = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_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 = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_codes::FG_YELLOW, .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 = ansi_escape_codes::FG_YELLOW, .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 = ansi_escape_codes::FG_YELLOW, .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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({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 = ansi_escape_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 = ansi_escape_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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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({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 = get_timestamp()};
auto severity = token{.colorCode = ansi_escape_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 = ansi_escape_codes::FG_BRIGHT_RED, .content = "FATAL"};
auto content = token{.content = message, .delimiter = ""};
log({severity, content});
}
}