Merge pull request 'anotherrewrite' (#18) from anotherrewrite into main
Reviewed-on: #18
This commit is contained in:
@@ -23,7 +23,7 @@ include_directories("include")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Event
|
||||
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
|
||||
URL https://git.redacted.cc/josh/Event/archive/Release-7.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
|
190
include/jlog/Logger.hpp
Normal file
190
include/jlog/Logger.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
#include "fstream"
|
||||
#include "iostream"
|
||||
#include "source_location"
|
||||
#include "Token.hpp"
|
||||
#include "Timestamp.hpp"
|
||||
|
||||
|
||||
namespace jlog {
|
||||
class Logger {
|
||||
public:
|
||||
Logger(std::ostream &stream = std::cout) : os{stream} {};
|
||||
public:
|
||||
void
|
||||
operator()(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) {
|
||||
if (Enable)
|
||||
Log(message, location, ts);
|
||||
};
|
||||
protected:
|
||||
virtual void
|
||||
Log(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) = 0;
|
||||
|
||||
public:
|
||||
bool Enable = true;
|
||||
bool IncludeLocation = true;
|
||||
bool IncludeTimestamp = true;
|
||||
protected:
|
||||
std::ostream &os = std::cout;
|
||||
};
|
||||
|
||||
class ColorLogger : public Logger {
|
||||
public:
|
||||
ColorLogger(std::ostream &stream = std::cout) : Logger(stream) {};
|
||||
public:
|
||||
bool IncludeColor = true;
|
||||
};
|
||||
|
||||
class ConsoleLogger : public ColorLogger {
|
||||
public:
|
||||
//explicit ConsoleLogger();
|
||||
explicit ConsoleLogger(const std::string &context) : ColorLogger() { this->context = context; };
|
||||
protected:
|
||||
virtual void
|
||||
Log(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) {
|
||||
if (!Enable)
|
||||
return;
|
||||
// Disable color on Windows. I've been trying my best to keep this macro hidden from the user. - maxine
|
||||
#ifdef WIN32
|
||||
IncludeColor = false;
|
||||
#endif
|
||||
if (IncludeTimestamp) {
|
||||
Timestamp ts;
|
||||
os << token{std::format(
|
||||
"{}-{}-{} {}:{}:{}.{}",
|
||||
ts.Year(),
|
||||
ts.Month(),
|
||||
ts.Day(),
|
||||
ts.Hour().count(),
|
||||
ts.Minute().count(),
|
||||
ts.Second().count(),
|
||||
ts.Millisecond().count()), "[]", timestampColor}.Stringer(IncludeColor);
|
||||
}
|
||||
|
||||
os << token(context, "[]", contextColor).Stringer(IncludeColor);
|
||||
|
||||
if (IncludeLocation) {
|
||||
os << token{location.function_name(), "[]", locationColor}.Stringer(IncludeColor);
|
||||
os << token{std::format("{}:{}", location.file_name(), location.line()), "[]", locationColor}.Stringer(
|
||||
IncludeColor);
|
||||
}
|
||||
|
||||
os << token{">>", "", pointerColor}.Stringer(IncludeColor)
|
||||
<< token(message, "", messageColor).Stringer(IncludeColor) << "\n";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string context = "CONSOLE";
|
||||
protected:
|
||||
Color4 timestampColor = Colors::Purples::Fuchsia;
|
||||
Color4 contextColor = Colors::White;
|
||||
Color4 locationColor = Colors::Pinks::Pink;
|
||||
Color4 pointerColor = Colors::Pinks::LightPink;
|
||||
Color4 messageColor = Colors::Greens::LightGreen;
|
||||
};
|
||||
|
||||
class FileLogger : public Logger {
|
||||
public:
|
||||
//explicit FileLogger();
|
||||
explicit FileLogger(const std::string &context, std::ofstream &file) : Logger(
|
||||
file) { this->context = context; };
|
||||
protected:
|
||||
virtual void
|
||||
Log(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) {
|
||||
if (!Enable)
|
||||
return;
|
||||
|
||||
if (IncludeTimestamp) {
|
||||
Timestamp ts;
|
||||
os << token{std::format(
|
||||
"{}-{}-{} {}:{}:{}.{}",
|
||||
ts.Year(),
|
||||
ts.Month(),
|
||||
ts.Day(),
|
||||
ts.Hour().count(),
|
||||
ts.Minute().count(),
|
||||
ts.Second().count(),
|
||||
ts.Millisecond().count()), "[]"}.Stringer(false);
|
||||
}
|
||||
|
||||
os << token(context, "[]").Stringer(false);
|
||||
|
||||
if (IncludeLocation) {
|
||||
os << token{location.function_name(), "[]"}.Stringer(false);
|
||||
os << token{std::format("{}:{}", location.file_name(), location.line()), "[]"}.Stringer(false);
|
||||
}
|
||||
|
||||
os << token{">>", ""}.Stringer(false) << token(message, "").Stringer(false) << "\n";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string context = "FILE";
|
||||
};
|
||||
|
||||
class CompoundLogger : protected ConsoleLogger, protected FileLogger {
|
||||
public:
|
||||
explicit CompoundLogger(const std::string &context, std::ofstream &file) : ConsoleLogger(context),
|
||||
FileLogger(context, file) {};
|
||||
public:
|
||||
void
|
||||
operator()(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) { Log(message, location, ts); };
|
||||
|
||||
virtual void
|
||||
Log(const std::string &message, const std::source_location &location = std::source_location::current(),
|
||||
const Timestamp &ts = Timestamp()) {
|
||||
ConsoleLogger::Log(message, location, ts);
|
||||
FileLogger::Log(message, location, ts);
|
||||
}
|
||||
|
||||
public:
|
||||
void EnableConsole(bool b) { ConsoleLogger::Enable = b; };
|
||||
|
||||
void EnableFile(bool b) { FileLogger::Enable = b; };
|
||||
|
||||
void IncludeTimestamp(bool b) {
|
||||
ConsoleLogger::IncludeTimestamp = b;
|
||||
FileLogger::IncludeTimestamp = b;
|
||||
};
|
||||
|
||||
void IncludeLocation(bool b) {
|
||||
ConsoleLogger::IncludeLocation = b;
|
||||
FileLogger::IncludeLocation = b;
|
||||
};
|
||||
|
||||
void IncludeColor(bool b) { ConsoleLogger::IncludeColor = b; };
|
||||
|
||||
|
||||
};
|
||||
|
||||
class GenericLogger : public CompoundLogger {
|
||||
public:
|
||||
GenericLogger(const std::string &context,
|
||||
std::ofstream &file,
|
||||
Color4 contextColor = Colors::White,
|
||||
Color4 timestampColor = Colors::Purples::Fuchsia,
|
||||
Color4 locationColor = Colors::Pinks::Pink,
|
||||
Color4 pointerColor = Colors::Pinks::LightPink,
|
||||
Color4 messageColor = Colors::Greens::LightGreen)
|
||||
: CompoundLogger(context, file) {
|
||||
this->contextColor = contextColor;
|
||||
this->timestampColor = timestampColor;
|
||||
this->locationColor = locationColor;
|
||||
this->pointerColor = pointerColor;
|
||||
this->messageColor = messageColor;
|
||||
}
|
||||
};
|
||||
|
||||
extern std::ofstream GlobalLogFile;
|
||||
|
||||
extern GenericLogger Info;
|
||||
extern GenericLogger Warning;
|
||||
extern GenericLogger Error;
|
||||
extern GenericLogger Fatal;
|
||||
extern GenericLogger Verbose;
|
||||
extern GenericLogger Debug;
|
||||
}
|
26
include/jlog/Timestamp.hpp
Normal file
26
include/jlog/Timestamp.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
28
include/jlog/Token.hpp
Normal file
28
include/jlog/Token.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mcolor.h>
|
||||
#include "Colors.hpp"
|
||||
|
||||
namespace jlog {
|
||||
using namespace mcolor;
|
||||
|
||||
class token {
|
||||
public:
|
||||
token(std::string content = "", std::string delimiter = "[]", Color4 colorCode = Colors::White) {
|
||||
this->colorCode = colorCode;
|
||||
this->content = content;
|
||||
this->delimiter = delimiter;
|
||||
}
|
||||
public:
|
||||
std::string Stringer(bool includeColor = true);
|
||||
std::string StringerWithColor();
|
||||
std::string StringerWithoutColor();
|
||||
public:
|
||||
Color4 colorCode = Colors::White;
|
||||
std::string content = "";
|
||||
std::string delimiter = "[]";
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, token t);
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
#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 = ""};
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
#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);
|
||||
*/
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
/// Josh's Logger
|
||||
/// A Redacted Software Product
|
||||
/// Developed & Maintained by Josh O'Leary
|
||||
/// This work is dedicated to the public domain.
|
||||
|
||||
/// Special thanks: Maxine Hayes, William J Tomasine II
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <Event.h>
|
||||
#include <mcolor.h>
|
||||
#include "token.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "source_location"
|
||||
#include <jlog/logger.hpp>
|
||||
|
||||
namespace jlog {
|
||||
|
||||
using namespace mcolor;
|
||||
|
||||
/// Built-in Global Loggers
|
||||
extern Logger info;
|
||||
extern Logger warning;
|
||||
extern Logger error;
|
||||
extern Logger fatal;
|
||||
extern Logger verbose;
|
||||
extern Logger debug;
|
||||
|
||||
|
||||
void SetTracebackOnGlobalLoggers(bool enabled);
|
||||
}
|
||||
|
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mcolor.h>
|
||||
#include "token.hpp"
|
||||
#include "Color4.hpp"
|
||||
#include "Colors.hpp"
|
||||
#include <source_location>
|
||||
#include <map>
|
||||
#include <jlog/token.hpp>
|
||||
#include <Event.h>
|
||||
#include "formatter.hpp"
|
||||
|
||||
namespace jlog
|
||||
{
|
||||
using namespace mcolor;
|
||||
|
||||
class LogEntry {
|
||||
public:
|
||||
LogEntry(Color4 cc, const std::string c, const std::string msg, const std::source_location t, const Timestamp ts);
|
||||
public:
|
||||
Color4 ContextColor() { return context_color; }
|
||||
std::string Context() { return context; }
|
||||
std::string Message() { return message; }
|
||||
std::source_location Trace() { return trace; }
|
||||
jlog::Timestamp GetTimeStamp() { return timestamp; };
|
||||
virtual std::vector<token> Tokenize();
|
||||
public:
|
||||
bool IncludeTrace;
|
||||
bool IncludeTimestamp;
|
||||
private:
|
||||
Color4 context_color;
|
||||
std::string context;
|
||||
std::string message;
|
||||
std::source_location trace;
|
||||
Timestamp timestamp;
|
||||
};
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
explicit Logger(const std::string& context, const Color4& color = Colors::LightGray);
|
||||
public:
|
||||
Event<LogEntry> OnLogEvent;
|
||||
public:
|
||||
void operator () (const std::string& message, const std::source_location& location = std::source_location::current());
|
||||
virtual void Log(const std::string &message, const std::source_location& location = std::source_location::current());
|
||||
public:
|
||||
void SetEnabled(bool state);
|
||||
void Enable();
|
||||
void Disable();
|
||||
bool Enabled();
|
||||
void LogFile(const std::string& f);
|
||||
std::string LogFile();
|
||||
// no cc no bullshit
|
||||
void SetColorCode(Color4 cc = Colors::LightGray);
|
||||
Color4 GetColorCode();
|
||||
public:
|
||||
std::string Context();
|
||||
void SetTraceback(bool b);
|
||||
void IncludeTimestamp(bool b);
|
||||
/**/
|
||||
protected:
|
||||
bool enabled = true;
|
||||
std::string logfile = "latest.log";
|
||||
Color4 colorcode = Colors::LightGray;
|
||||
std::string context;
|
||||
bool trace = true;
|
||||
bool timestamp = true;
|
||||
};
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
#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);
|
||||
}
|
84
main.cpp
84
main.cpp
@@ -4,82 +4,20 @@
|
||||
// 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>
|
||||
#include "jlog/Logger.hpp"
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mcolor;
|
||||
|
||||
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."));
|
||||
|
||||
|
||||
// Traceback is enabled on global Loggers by default
|
||||
demo("Traceback is enabled on global Loggers by default");
|
||||
jlog::info("info message traceback");
|
||||
jlog::debug("debug message traceback");
|
||||
jlog::verbose("verbose message traceback");
|
||||
jlog::warning("warning message traceback");
|
||||
jlog::error("error message traceback");
|
||||
jlog::fatal("fatal message traceback");
|
||||
|
||||
// We can disable/enable traceback on a logger
|
||||
demo("We can disable/enable traceback on a logger");
|
||||
demo("Disable = demo.SetTraceback(false);");
|
||||
demo.SetTraceback(true);
|
||||
demo("Enable = demo.SetTraceback(true);");
|
||||
demo.SetTraceback(false);
|
||||
|
||||
|
||||
// We can set the traceback for all the global loggers.
|
||||
demo(std::format("{}\n>\t{}", "We can set the traceback for all the global loggers.", "jlog::SetTracebackOnGlobalLoggers(false);"));
|
||||
jlog::SetTracebackOnGlobalLoggers(false);
|
||||
|
||||
|
||||
jlog::info("info message");
|
||||
jlog::debug("debug message");
|
||||
jlog::verbose("verbose message");
|
||||
jlog::warning("warning message");
|
||||
jlog::error("error message");
|
||||
jlog::fatal("fatal message");
|
||||
|
||||
// We can enable/disable loggers.
|
||||
demo(std::format("{}\n>\t{}\n>\t{}", "We can enable/disable loggers.", "jlog::info.Enable();", "jlog::info.Disable();"));
|
||||
jlog::info.Enable();
|
||||
jlog::info("Logger enabled");
|
||||
jlog::info.Disable();
|
||||
demo("You won't see the 'Logger disabled' message here since we just disabled it. Check main.cpp for proof.");
|
||||
jlog::info("Logger disabled");
|
||||
jlog::info.Enable();
|
||||
|
||||
// We can also add event hooks to a logger.
|
||||
demo(std::format("{}\n>\t{}\n>\t\t{}\n>\n>\t\t{}\n>\t{}",
|
||||
"We can also add event hooks to a logger.",
|
||||
"demo.OnLogEvent += [](jlog::LogEntry le) {",
|
||||
"jlog::token dbg = {.colorCode = jlog::debug.GetColorCode(), .content = \"This message is only seen when the event hook is added.\"};",
|
||||
"jlog::log_to_console(jlog::toks2consoleMsg(std::vector<jlog::token>{dbg}));",
|
||||
"}"
|
||||
));
|
||||
|
||||
|
||||
demo("Before event hook");
|
||||
|
||||
// Create and add event hook.
|
||||
demo.OnLogEvent += [](jlog::LogEntry le) {
|
||||
jlog::token dbg = {.colorCode = jlog::debug.GetColorCode(), .content = "This message is only seen when the event hook is added."};
|
||||
|
||||
//jlog::log_to_console(jlog::toks2consoleMsg(std::vector<jlog::token>{dbg}));
|
||||
jlog::LogToConsole(std::vector<jlog::token>{dbg});
|
||||
};
|
||||
|
||||
demo("After event hook");
|
||||
|
||||
jlog::GenericLogger Demo("demo", jlog::GlobalLogFile);
|
||||
Demo("No new demo yet");
|
||||
jlog::Info("dsadsd");
|
||||
jlog::Warning("dsadsd");
|
||||
jlog::Error("dsadsd");
|
||||
jlog::Fatal("dsadsd");
|
||||
jlog::Verbose("dsadsd");
|
||||
jlog::Debug("dsadsd");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
13
src/jlog/Logger.cpp
Normal file
13
src/jlog/Logger.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "jlog/Logger.hpp"
|
||||
#include <fstream>
|
||||
|
||||
namespace jlog {
|
||||
std::ofstream GlobalLogFile("latest.log", std::ios_base::app);
|
||||
|
||||
GenericLogger Info {"info", GlobalLogFile, Colors::Green, Colors::Gray, Colors::Gray, Colors::Green, Colors::White};
|
||||
GenericLogger Warning {"warning", GlobalLogFile, Colors::Yellow, Colors::Gray, Colors::Gray, Colors::Yellow, Colors::White};
|
||||
GenericLogger Error {"error", GlobalLogFile, Colors::Red, Colors::Gray, Colors::Gray, Colors::Red, Colors::White};
|
||||
GenericLogger Fatal {"fatal", GlobalLogFile, Colors::Reds::Crimson, Colors::Gray, Colors::Gray, Colors::Reds::Crimson, Colors::White};
|
||||
GenericLogger Verbose {"verbose", GlobalLogFile, Colors::Blue, Colors::Gray, Colors::Gray, Colors::Blue, Colors::White};
|
||||
GenericLogger Debug {"debug", GlobalLogFile, Colors::Purples::Purple, Colors::Gray, Colors::Gray, Colors::Purples::Purple, Colors::White};
|
||||
}
|
17
src/jlog/Timestamp.cpp
Normal file
17
src/jlog/Timestamp.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "jlog/Timestamp.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();
|
||||
}
|
||||
}
|
36
src/jlog/Token.cpp
Normal file
36
src/jlog/Token.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "jlog/Token.hpp"
|
||||
|
||||
namespace jlog {
|
||||
std::string token::Stringer(bool includeColor) {
|
||||
std::string msg;
|
||||
if (!includeColor)
|
||||
return StringerWithoutColor();
|
||||
return StringerWithColor();
|
||||
}
|
||||
|
||||
std::string token::StringerWithColor() {
|
||||
std::string msg;
|
||||
if (!delimiter.empty()) {
|
||||
return std::format("{}{}{}{}{} ",
|
||||
mcolor::toEscapeCode(colorCode),
|
||||
delimiter[0], content,
|
||||
delimiter[1],
|
||||
mcolor::toEscapeCode(AnsiColor::RESET));
|
||||
}
|
||||
return std::format("{}{}{} ",
|
||||
mcolor::toEscapeCode(colorCode),
|
||||
content,
|
||||
mcolor::toEscapeCode(AnsiColor::RESET));
|
||||
}
|
||||
std::string token::StringerWithoutColor() {
|
||||
if (!delimiter.empty())
|
||||
return std::format("{}{}{} ", delimiter[0], content, delimiter[1]);
|
||||
|
||||
return content + " ";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, token t) {
|
||||
os << t.Stringer();
|
||||
return os;
|
||||
}
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
#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();
|
||||
}
|
||||
*/
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
#include <jlog/logger.hpp>
|
||||
#include <jlog/jlog.hpp>
|
||||
#include <jlog/formatter.hpp>
|
||||
#include <jlog/token.hpp>
|
||||
#include "jlog/io.hpp"
|
||||
|
||||
namespace jlog
|
||||
{
|
||||
LogEntry::LogEntry(Color4 cc, const std::string c, const std::string msg, const std::source_location t, const Timestamp ts) {
|
||||
this->context_color = cc;
|
||||
this->context = c;
|
||||
this->message = msg;
|
||||
this->trace = t;
|
||||
this->timestamp = ts;
|
||||
};
|
||||
|
||||
std::vector<token> LogEntry::Tokenize() {
|
||||
std::vector<token> tokens;
|
||||
|
||||
if (IncludeTimestamp)
|
||||
tokens.push_back({.colorCode = Colors::Gray, .content = std::format(
|
||||
"{}-{}-{} {}:{}:{}.{}",
|
||||
timestamp.Year(),
|
||||
timestamp.Month(),
|
||||
timestamp.Day(),
|
||||
timestamp.Hour().count(),
|
||||
timestamp.Minute().count(),
|
||||
timestamp.Second().count(),
|
||||
timestamp.Millisecond().count())});
|
||||
|
||||
tokens.push_back({.colorCode = context_color, .content = context});
|
||||
|
||||
if (IncludeTrace) {
|
||||
tokens.push_back({.colorCode = Colors::Gray, .content = trace.function_name()});
|
||||
tokens.push_back({.colorCode = Colors::Gray, .content = std::format("{}:{}",trace.file_name(), trace.line())});
|
||||
}
|
||||
|
||||
tokens.push_back({.colorCode = Colors::Gray, .content = ">>", .delimiter = ""});
|
||||
|
||||
tokens.push_back({.colorCode = Colors::Gray, .content = message, .delimiter = ""});
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
Logger::Logger(const std::string& context, const Color4& color) {
|
||||
this->context = context;
|
||||
this->colorcode = color;
|
||||
}
|
||||
|
||||
void Logger::Log(const std::string &message, const std::source_location& location) {
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
LogEntry logentry = {colorcode, context, message, location, Timestamp()};
|
||||
logentry.IncludeTrace = this->trace;
|
||||
logentry.IncludeTimestamp = this->timestamp;
|
||||
|
||||
OnLogEvent(logentry);
|
||||
|
||||
LogToConsole(logentry.Tokenize());
|
||||
LogToConsole("\n");
|
||||
LogToFile(logfile, logentry.Tokenize());
|
||||
LogToFile(logfile, "\n");
|
||||
}
|
||||
|
||||
void Logger::SetEnabled(bool state) {
|
||||
this->enabled = state;
|
||||
}
|
||||
bool Logger::Enabled() { return this->enabled; }
|
||||
|
||||
void Logger::LogFile(const std::string& f) {
|
||||
this->logfile = f;
|
||||
}
|
||||
std::string Logger::LogFile() { return this->logfile; }
|
||||
|
||||
void Logger::SetColorCode(Color4 cc) { this->colorcode = cc; }
|
||||
Color4 Logger::GetColorCode() { return this->colorcode; }
|
||||
|
||||
std::string Logger::Context() { return this->context; }
|
||||
|
||||
void Logger::operator()(const std::string &message, const std::source_location& location) {
|
||||
Log(message, location);
|
||||
}
|
||||
|
||||
void Logger::SetTraceback(bool b) {
|
||||
trace = b;
|
||||
}
|
||||
|
||||
void Logger::Enable() { SetEnabled(true);}
|
||||
|
||||
void Logger::Disable() { SetEnabled(false); }
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
#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