Compare commits
24 Commits
Prerelease
...
nomacros
Author | SHA1 | Date | |
---|---|---|---|
c5b9d50a2b | |||
b19e2ea651 | |||
18dd697470 | |||
ae46df7006 | |||
eb9a2b26b9 | |||
758925c837 | |||
d8439efcaf | |||
7b25a097cd | |||
fe158ab88e | |||
633bee1e9f | |||
c735e4baa1 | |||
168af78441 | |||
96b759d54e | |||
1ae346304e | |||
2795756235 | |||
c17a34f0f1 | |||
404c3dceba | |||
e0b6879ec5 | |||
73f92d0c1a | |||
|
f7ee1a347e | ||
aace84af52 | |||
|
47e06dd8ed | ||
cad79a474a | |||
67a83bbac4 |
@@ -26,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})
|
||||
@@ -37,6 +40,8 @@ if (WIN32)
|
||||
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})
|
||||
@@ -44,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)
|
||||
|
21
README.md
21
README.md
@@ -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
BIN
img.png
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 152 KiB |
@@ -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 "";
|
||||
}
|
||||
}
|
||||
|
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <jlog/ansi_escape_codes.hpp>
|
||||
|
||||
// Platform independent color code mapping
|
||||
|
||||
struct colorcode
|
||||
{
|
||||
std::string ansi_code;
|
||||
};
|
||||
|
||||
namespace jlog::color_codes
|
||||
{
|
||||
static const colorcode FG_BLACK {ansi_escape_codes::FG_BLACK};
|
||||
static const colorcode FG_RED {ansi_escape_codes::FG_RED};
|
||||
static const colorcode FG_GREEN {ansi_escape_codes::FG_GREEN };
|
||||
static const colorcode FG_YELLOW {ansi_escape_codes::FG_YELLOW};
|
||||
static const colorcode FG_BLUE {ansi_escape_codes::FG_BLUE};
|
||||
static const colorcode FG_MAGENTA {ansi_escape_codes::FG_MAGENTA};
|
||||
static const colorcode FG_CYAN {ansi_escape_codes::FG_CYAN};
|
||||
static const colorcode FG_WHITE {ansi_escape_codes::FG_WHITE};
|
||||
static const colorcode FG_DEFAULT {ansi_escape_codes::FG_DEFAULT};
|
||||
|
||||
static const colorcode FG_BRIGHT_BLACK {ansi_escape_codes::FG_BRIGHT_BLACK};
|
||||
static const colorcode FG_BRIGHT_RED {ansi_escape_codes::FG_BRIGHT_RED};
|
||||
static const colorcode FG_BRIGHT_GREEN {ansi_escape_codes::FG_BRIGHT_GREEN};
|
||||
static const colorcode FG_BRIGHT_YELLOW {ansi_escape_codes::FG_BRIGHT_YELLOW};
|
||||
static const colorcode FG_BRIGHT_BLUE {ansi_escape_codes::FG_BRIGHT_MAGENTA};
|
||||
static const colorcode FG_BRIGHT_MAGENTA {ansi_escape_codes::FG_BRIGHT_MAGENTA};
|
||||
static const colorcode FG_BRIGHT_CYAN {ansi_escape_codes::FG_BRIGHT_CYAN};
|
||||
static const colorcode FG_BRIGHT_WHITE {ansi_escape_codes::FG_BRIGHT_WHITE};
|
||||
|
||||
static const colorcode BG_BLACK {ansi_escape_codes::BG_BLACK};
|
||||
static const colorcode BG_RED {ansi_escape_codes::BG_RED};
|
||||
static const colorcode BG_GREEN {ansi_escape_codes::BG_GREEN};
|
||||
static const colorcode BG_YELLOW {ansi_escape_codes::BG_YELLOW};
|
||||
static const colorcode BG_BLUE {ansi_escape_codes::BG_BLUE};
|
||||
static const colorcode BG_MAGENTA {ansi_escape_codes::BG_MAGENTA};
|
||||
static const colorcode BG_CYAN {ansi_escape_codes::BG_CYAN};
|
||||
static const colorcode BG_WHITE {ansi_escape_codes::BG_WHITE};
|
||||
static const colorcode BG_DEFAULT {ansi_escape_codes::BG_DEFAULT};
|
||||
|
||||
static const colorcode BG_BRIGHT_BLACK {ansi_escape_codes::BG_BRIGHT_BLACK};
|
||||
static const colorcode BG_BRIGHT_RED {ansi_escape_codes::BG_BRIGHT_RED};
|
||||
static const colorcode BG_BRIGHT_GREEN {ansi_escape_codes::BG_BRIGHT_GREEN};
|
||||
static const colorcode BG_BRIGHT_YELLOW {ansi_escape_codes::BG_BRIGHT_YELLOW};
|
||||
static const colorcode BG_BRIGHT_BLUE {ansi_escape_codes::BG_BRIGHT_BLUE};
|
||||
static const colorcode BG_BRIGHT_MAGENTA {ansi_escape_codes::BG_BRIGHT_MAGENTA};
|
||||
static const colorcode BG_BRIGHT_CYAN {ansi_escape_codes::BG_BRIGHT_CYAN};
|
||||
static const colorcode BG_BRIGHT_WHITE {ansi_escape_codes::BG_BRIGHT_WHITE};
|
||||
}
|
66
include/jlog/formatter.hpp
Normal file
66
include/jlog/formatter.hpp
Normal 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
29
include/jlog/io.hpp
Normal 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);
|
||||
*/
|
||||
}
|
@@ -8,232 +8,27 @@
|
||||
#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);
|
||||
|
||||
/// Returns a string timestamp in the format of 'YYYY-MM-DD hh:mm:ss.ms'
|
||||
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);
|
||||
|
||||
/// These are helper functions designed to be wrapped around for easier custom logger building.
|
||||
/// @note This file is implemented differently per-platform to handle differences in console color handling.
|
||||
/// @see windows/jlog.cpp linux/jlog.cpp
|
||||
std::string toks2msg(std::vector<token> tokens, std::function<std::string(token)> formatter);
|
||||
std::string consoleMsgFormatter(token t);
|
||||
std::string logfileMsgFormatter(token t);
|
||||
std::string toks2consoleMsg(std::vector<token> tokens);
|
||||
std::string toks2logfileMsg(std::vector<token> tokens);
|
||||
|
||||
/// 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(const std::vector<token>& tokens, const std::string& filename);
|
||||
void log(const std::vector<token>& tokens);
|
||||
void ltlog(const std::vector<token>& tokens); // Just for debug purposes
|
||||
|
||||
#pragma region Generic Formatters
|
||||
|
||||
/// 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. See color_codes.hpp
|
||||
std::vector<token> log_format(
|
||||
const std::string& severity_name,
|
||||
const std::string& message,
|
||||
const colorcode& severity_cc = color_codes::FG_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. See color_codes.hpp
|
||||
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);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the INFO log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> info_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the INFO log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> info_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the WARNING log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> warning_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the WARNING log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> warning_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the ERROR log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> error_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the ERROR log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> error_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the FATAL log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> fatal_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the FATAL log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> fatal_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the VERBOSE log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> verbose_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the VERBOSE log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> verbose_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the DEBUG log level.
|
||||
/// @param message The message to send out.
|
||||
std::vector<token> debug_format(const std::string& message);
|
||||
|
||||
/// Returns a token sequence pre-formatted for the DEBUG log level.
|
||||
/// @param message The message to send out.
|
||||
/// @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> debug_detailed_format(
|
||||
const std::string &message,
|
||||
const std::string &func,
|
||||
const std::string &file,
|
||||
int line);
|
||||
#pragma endregion
|
||||
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;
|
||||
|
||||
#define LOGTEST(i) if (jlog::loglevel >= jlog::severity::none) { jlog::ltlog(jlog::info_detailed_format(i, FUNCTION, __FILE__, __LINE__)); }
|
||||
|
||||
|
51
include/jlog/logger.hpp
Normal file
51
include/jlog/logger.hpp
Normal 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
75
include/jlog/token.hpp
Normal 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);
|
||||
}
|
93
main.cpp
93
main.cpp
@@ -4,38 +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!!!");
|
||||
|
||||
LOGTEST("This is a really cool test man :3");
|
||||
LOGTEST("Go check cmake-build-debug/logtest.log and cmake-build-debug/latest.log");
|
||||
// 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;
|
||||
}
|
||||
|
87
src/jlog/formatter.cpp
Normal file
87
src/jlog/formatter.cpp
Normal 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
53
src/jlog/io.cpp
Normal 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();
|
||||
}
|
||||
*/
|
||||
}
|
@@ -3,254 +3,28 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
/*
|
||||
#ifdef WIN32
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
namespace jlog
|
||||
{
|
||||
static std::string default_logfile = "latest.log";
|
||||
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 set_default_logfile(const std::string& filename)
|
||||
{
|
||||
default_logfile = filename;
|
||||
void SetTracebackOnGlobalLoggers(bool enabled) {
|
||||
info.SetTraceback(enabled);
|
||||
warning.SetTraceback(enabled);
|
||||
error.SetTraceback(enabled);
|
||||
fatal.SetTraceback(enabled);
|
||||
verbose.SetTraceback(enabled);
|
||||
debug.SetTraceback(enabled);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
// Beat windows into submission and make it use ANSI color codes
|
||||
// This also looks fugly, but it works
|
||||
#ifdef WIN32
|
||||
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD consoleMode;
|
||||
GetConsoleMode( handleOut, &consoleMode);
|
||||
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||
SetConsoleMode( handleOut , consoleMode );
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
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::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)
|
||||
{
|
||||
if (!t.delimiter.empty())
|
||||
{
|
||||
return std::format("{}{}{}{}{} ", t.colorCode.ansi_code, t.delimiter[0], t.content, t.delimiter[1], ansi_escape_codes::RESET);
|
||||
}
|
||||
|
||||
return std::format("{}{}{} ", t.colorCode.ansi_code, t.content, ansi_escape_codes::RESET);
|
||||
}
|
||||
|
||||
std::string logfileMsgFormatter(token t)
|
||||
{
|
||||
if (!t.delimiter.empty())
|
||||
{
|
||||
return std::format("{}{}{} ", t.delimiter[0], t.content, t.delimiter[1]);
|
||||
}
|
||||
|
||||
return t.content + " ";
|
||||
}
|
||||
|
||||
void log(const std::vector<token>& tokens, const std::string& filename)
|
||||
{
|
||||
log_to_console(toks2consoleMsg(tokens));
|
||||
log_to_console("\n");
|
||||
log_to_file(filename, toks2logfileMsg(tokens));
|
||||
log_to_file(filename, "\n");
|
||||
}
|
||||
|
||||
void log(const std::vector<token>& tokens)
|
||||
{
|
||||
log(tokens, default_logfile);
|
||||
}
|
||||
|
||||
// Mainly for debug purposes
|
||||
void ltlog(const std::vector<token>& tokens)
|
||||
{
|
||||
log(tokens);
|
||||
log_to_file("logtest.log", toks2logfileMsg(tokens) + "\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
66
src/jlog/logger.cpp
Normal file
66
src/jlog/logger.cpp
Normal 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
60
src/jlog/token.cpp
Normal 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 + " ";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user