added sinks types
This commit is contained in:
parent
31d1dda7f8
commit
c79004413d
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <ios>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace journal {
|
namespace journal {
|
||||||
|
@ -64,7 +65,16 @@ auto log_internal(const LogVerbosity &verbosity,
|
||||||
|
|
||||||
using detail::LogVerbosity;
|
using detail::LogVerbosity;
|
||||||
|
|
||||||
auto init_stdout(const LogVerbosity& min = LogVerbosity::Info) -> void;
|
auto init_std_out(const LogVerbosity &min = LogVerbosity::Info) -> void;
|
||||||
|
auto init_std_out_err(const LogVerbosity &min = LogVerbosity::Info) -> void;
|
||||||
|
auto init() -> void;
|
||||||
|
auto add_file(std::string_view file_path,
|
||||||
|
std::ios_base::openmode = std::ios_base::ate,
|
||||||
|
const LogVerbosity &min = LogVerbosity::Info,
|
||||||
|
const LogVerbosity &max = LogVerbosity::Error) -> void;
|
||||||
|
auto add_sink(std::shared_ptr<std::ostream> stream,
|
||||||
|
const LogVerbosity &min = LogVerbosity::Info,
|
||||||
|
const LogVerbosity &max = LogVerbosity::Error) -> void;
|
||||||
|
|
||||||
#ifdef JOURNAL_ALL
|
#ifdef JOURNAL_ALL
|
||||||
#define JOURNAL_TRACE
|
#define JOURNAL_TRACE
|
||||||
|
|
234
src/journal.cc
234
src/journal.cc
|
@ -3,14 +3,13 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <cstdio>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <ostream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <type_traits>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
namespace journal {
|
namespace journal {
|
||||||
namespace mutex {
|
namespace mutex {
|
||||||
|
@ -69,19 +68,99 @@ public:
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
Black,
|
||||||
|
Red,
|
||||||
|
Green,
|
||||||
|
Yellow,
|
||||||
|
Blue,
|
||||||
|
Magenta,
|
||||||
|
Cyan,
|
||||||
|
White,
|
||||||
|
BrightBlack,
|
||||||
|
BrightRed,
|
||||||
|
BrightGreen,
|
||||||
|
BrightYellow,
|
||||||
|
BrightBlue,
|
||||||
|
BrightMagenta,
|
||||||
|
BrightCyan,
|
||||||
|
BrightWhite,
|
||||||
|
None,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto color_code(const Color &color) -> std::string {
|
||||||
|
switch (color) {
|
||||||
|
case Black:
|
||||||
|
return "\e[0;30m";
|
||||||
|
case Red:
|
||||||
|
return "\e[0;31m";
|
||||||
|
case Green:
|
||||||
|
return "\e[0;32m";
|
||||||
|
case Yellow:
|
||||||
|
return "\e[0;33m";
|
||||||
|
case Blue:
|
||||||
|
return "\e[0;34m";
|
||||||
|
case Magenta:
|
||||||
|
return "\e[0;35m";
|
||||||
|
case Cyan:
|
||||||
|
return "\e[0;36m";
|
||||||
|
case White:
|
||||||
|
return "\e[0;37m";
|
||||||
|
|
||||||
|
case BrightBlack:
|
||||||
|
return "\e[1;30m";
|
||||||
|
case BrightRed:
|
||||||
|
return "\e[1;31m";
|
||||||
|
case BrightGreen:
|
||||||
|
return "\e[1;32m";
|
||||||
|
case BrightYellow:
|
||||||
|
return "\e[1;33m";
|
||||||
|
case BrightBlue:
|
||||||
|
return "\e[1;34m";
|
||||||
|
case BrightMagenta:
|
||||||
|
return "\e[1;35m";
|
||||||
|
case BrightCyan:
|
||||||
|
return "\e[1;36m";
|
||||||
|
case BrightWhite:
|
||||||
|
return "\e[1;37m";
|
||||||
|
case None:
|
||||||
|
return "\e[0;0m";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto colored(const std::string &str, const Color &color) -> std::string {
|
||||||
|
return color_code(color) + str + color_code(Color::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto to_string_colored(const LogVerbosity &verbosity) -> std::string {
|
||||||
|
switch (verbosity) {
|
||||||
|
case LogVerbosity::Trace:
|
||||||
|
return colored("TRACE", White);
|
||||||
|
case LogVerbosity::Debug:
|
||||||
|
return colored("DEBUG", Magenta);
|
||||||
|
case LogVerbosity::Info:
|
||||||
|
return colored("INFO ", Green);
|
||||||
|
case LogVerbosity::Warn:
|
||||||
|
return colored("WARN ", Yellow);
|
||||||
|
case LogVerbosity::Error:
|
||||||
|
return colored("ERROR", Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string {
|
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string {
|
||||||
switch (verbosity) {
|
switch (verbosity) {
|
||||||
case LogVerbosity::Trace:
|
case LogVerbosity::Trace:
|
||||||
return "Trace";
|
return "TRACE";
|
||||||
case LogVerbosity::Debug:
|
case LogVerbosity::Debug:
|
||||||
return "Debug";
|
return "DEBUG";
|
||||||
case LogVerbosity::Info:
|
case LogVerbosity::Info:
|
||||||
return "Info";
|
return "INFO ";
|
||||||
case LogVerbosity::Warn:
|
case LogVerbosity::Warn:
|
||||||
return "Warn";
|
return "WARN ";
|
||||||
case LogVerbosity::Error:
|
case LogVerbosity::Error:
|
||||||
return "Error";
|
return "ERROR";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Verbosity {
|
struct Verbosity {
|
||||||
|
@ -90,12 +169,77 @@ struct Verbosity {
|
||||||
Verbosity(journal::detail::LogVerbosity &&value) : inner(value) {}
|
Verbosity(journal::detail::LogVerbosity &&value) : inner(value) {}
|
||||||
Verbosity(const journal::detail::LogVerbosity &value) : inner(value) {}
|
Verbosity(const journal::detail::LogVerbosity &value) : inner(value) {}
|
||||||
|
|
||||||
auto operator<=>(const Verbosity &rhs) -> std::strong_ordering {
|
auto operator<=>(const Verbosity &rhs) const -> std::strong_ordering {
|
||||||
return static_cast<std::underlying_type_t<decltype(inner)>>(inner) <=>
|
return static_cast<std::underlying_type_t<decltype(inner)>>(inner) <=>
|
||||||
static_cast<std::underlying_type_t<decltype(rhs.inner)>>(rhs.inner);
|
static_cast<std::underlying_type_t<decltype(rhs.inner)>>(rhs.inner);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace sinks {
|
||||||
|
struct BaseSink {
|
||||||
|
Verbosity min_verbosity;
|
||||||
|
Verbosity max_verbosity;
|
||||||
|
|
||||||
|
BaseSink()
|
||||||
|
: min_verbosity(LogVerbosity::Trace), max_verbosity(LogVerbosity::Error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSink(const Verbosity &min, const Verbosity &max)
|
||||||
|
: min_verbosity(min), max_verbosity(max) {}
|
||||||
|
|
||||||
|
auto should_sink_verbosity(const Verbosity &verbosity) const -> bool {
|
||||||
|
return verbosity >= min_verbosity && verbosity <= max_verbosity;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set_max_verbosity(const Verbosity &new_max) -> Verbosity {
|
||||||
|
return std::exchange(max_verbosity, new_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set_min_verbosity(const Verbosity &new_min) -> Verbosity {
|
||||||
|
return std::exchange(min_verbosity, new_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto flush() -> void;
|
||||||
|
virtual auto operator<<(std::string_view str) -> void;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StdOutSink : public BaseSink {
|
||||||
|
StdOutSink() : BaseSink(LogVerbosity::Trace, LogVerbosity::Info) {}
|
||||||
|
|
||||||
|
auto write(std::string_view str) -> void { (*this) << str; }
|
||||||
|
virtual auto flush() -> void { std::cout.flush(); }
|
||||||
|
virtual auto operator<<(std::string_view str) -> void { std::cout << str; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StdErrSink : public BaseSink {
|
||||||
|
StdErrSink() : BaseSink(LogVerbosity::Warn, LogVerbosity::Error) {}
|
||||||
|
|
||||||
|
virtual auto flush() -> void { std::cerr.flush(); }
|
||||||
|
virtual auto operator<<(std::string_view str) -> void { std::cerr << str; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OStreamSink : public BaseSink {
|
||||||
|
std::shared_ptr<std::ostream> ostream;
|
||||||
|
|
||||||
|
OStreamSink(const std::shared_ptr<std::ostream> &stream,
|
||||||
|
const Verbosity &min = LogVerbosity::Trace,
|
||||||
|
const Verbosity &max = LogVerbosity::Error)
|
||||||
|
: ostream(stream), BaseSink(min, max) {}
|
||||||
|
|
||||||
|
virtual auto flush() -> void { ostream->flush(); }
|
||||||
|
virtual auto operator<<(std::string_view str) -> void { (*ostream) << str; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileSink : public OStreamSink {
|
||||||
|
FileSink(const std::string &file_path,
|
||||||
|
std::ios::ios_base::openmode open_mode = std::ios::ios_base::app,
|
||||||
|
const Verbosity &min = LogVerbosity::Trace,
|
||||||
|
const Verbosity &max = LogVerbosity::Error)
|
||||||
|
: OStreamSink(std::make_shared<std::ostream>(
|
||||||
|
std::ofstream(file_path, std::ios::ios_base::out | open_mode))) {}
|
||||||
|
};
|
||||||
|
} // namespace sinks
|
||||||
|
|
||||||
struct Sink {
|
struct Sink {
|
||||||
std::shared_ptr<std::ostream> stream;
|
std::shared_ptr<std::ostream> stream;
|
||||||
Verbosity min_verbosity;
|
Verbosity min_verbosity;
|
||||||
|
@ -112,25 +256,39 @@ struct Sink {
|
||||||
: stream(std::move(stream)), min_verbosity(min),
|
: stream(std::move(stream)), min_verbosity(min),
|
||||||
max_verbosity(journal::detail::Error) {}
|
max_verbosity(journal::detail::Error) {}
|
||||||
|
|
||||||
|
~Sink() { flush(); }
|
||||||
|
|
||||||
|
auto flush() -> void { stream->flush(); }
|
||||||
auto operator<<(std::string_view msg) { (*stream) << msg; }
|
auto operator<<(std::string_view msg) { (*stream) << msg; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Journal {
|
class Journal {
|
||||||
std::vector<Sink> sinks;
|
std::vector<std::unique_ptr<sinks::BaseSink>> sinks;
|
||||||
|
std::chrono::system_clock::time_point last_flushed;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Journal() {}
|
Journal() {}
|
||||||
auto log(const Verbosity &verbosity, source_location source,
|
auto log(const Verbosity &verbosity, source_location source,
|
||||||
std::string_view msg) {
|
std::string_view msg) {
|
||||||
|
const auto now = std::chrono::system_clock::now();
|
||||||
|
const auto do_flush = ((now - last_flushed).count() <= 5);
|
||||||
for (auto &&sink : sinks) {
|
for (auto &&sink : sinks) {
|
||||||
if (verbosity >= sink.min_verbosity && verbosity <= sink.max_verbosity) {
|
if (sink->should_sink_verbosity(verbosity)) {
|
||||||
sink << std::format("[{}] [{: <5}] [{}] {}\n",
|
(*sink) << format(msg, verbosity, source);
|
||||||
get_current_time_string(), to_string(verbosity.inner),
|
}
|
||||||
get_source_location_string(source), msg);
|
if (do_flush) {
|
||||||
|
sink->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto format(std::string_view str, const Verbosity &verbosity,
|
||||||
|
const source_location &source) -> std::string {
|
||||||
|
return std::format("[{}] [{: <5}] [{}] {}\n", get_current_time_string(),
|
||||||
|
to_string(verbosity.inner),
|
||||||
|
get_source_location_string(source), str);
|
||||||
|
}
|
||||||
|
|
||||||
auto get_source_location_string(const source_location& source) -> std::string {
|
auto get_source_location_string(const source_location& source) -> std::string {
|
||||||
const auto file = std::filesystem::path(source.file_name()).filename().string();
|
const auto file = std::filesystem::path(source.file_name()).filename().string();
|
||||||
return std::format("{}::{}", file, source.line());
|
return std::format("{}::{}", file, source.line());
|
||||||
|
@ -142,10 +300,19 @@ auto get_current_time_string() -> std::string {
|
||||||
return std::format("{:%Y-%m-%d %H:%M:%OS} UTC", now);
|
return std::format("{:%Y-%m-%d %H:%M:%OS} UTC", now);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_std_out(const Verbosity &min = journal::detail::LogVerbosity::Info) {
|
auto add_file(const std::string &file_name,
|
||||||
auto out = std::shared_ptr<std::ostream>(&std::cout, [](auto &&_) {});
|
std::ios::ios_base::openmode open_mode = std::ios::ios_base::app,
|
||||||
sinks.emplace_back(std::move(out));
|
const Verbosity &min = LogVerbosity::Trace,
|
||||||
|
const Verbosity &max = LogVerbosity::Error) -> void {
|
||||||
|
add_sink(std::make_unique<sinks::FileSink>(file_name, open_mode, min, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto add_sink(std::unique_ptr<sinks::BaseSink> &&sink) -> void {
|
||||||
|
sinks.emplace_back(std::move(sink));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_std_out() { add_sink(std::make_unique<sinks::StdOutSink>()); }
|
||||||
|
auto add_std_err() { add_sink(std::make_unique<sinks::StdErrSink>()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static mutex::Mutex<std::unique_ptr<Journal>> global_journal;
|
static mutex::Mutex<std::unique_ptr<Journal>> global_journal;
|
||||||
|
@ -158,16 +325,35 @@ auto log_internal(const LogVerbosity &verbosity, detail::source_location source,
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
auto init() {
|
auto init() -> void {
|
||||||
auto &&[lock, ref] = detail::global_journal.mut();
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
if (!ref.get()) {
|
if (!ref.get()) {
|
||||||
ref = std::make_unique<detail::Journal>();
|
ref = std::make_unique<detail::Journal>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto init_stdout(const LogVerbosity &min) -> void {
|
auto init_std_out(const LogVerbosity &min) -> void {
|
||||||
init();
|
init();
|
||||||
auto &&[lock, ref] = detail::global_journal.mut();
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
ref->add_std_out();
|
ref->add_std_out();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init_std_out_err(const LogVerbosity &min) -> void {
|
||||||
|
init();
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->add_std_out();
|
||||||
|
ref->add_std_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_sink(std::shared_ptr<std::ostream> stream, const LogVerbosity &min,
|
||||||
|
const LogVerbosity &max) -> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->add_sink(std::make_unique<detail::sinks::OStreamSink>(stream, min, max));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_file(std::string_view file_path, std::ios_base::openmode open_mode,
|
||||||
|
const LogVerbosity &min, const LogVerbosity &max) -> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->add_file(std::string(file_path), open_mode, min, max);
|
||||||
}
|
}
|
||||||
} // namespace journal
|
} // namespace journal
|
||||||
|
|
14
src/main.cc
14
src/main.cc
|
@ -3,11 +3,11 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
std::cin.get();
|
journal::init_std_out_err();
|
||||||
journal::init_stdout();
|
journal::add_file("test.log");
|
||||||
printf("Hello, Alloy!\n");
|
journal::info("some info!");
|
||||||
journal::info("some info!");
|
journal::error("something went wrong!");
|
||||||
journal::error("something went wrong!");
|
std::cin.get();
|
||||||
journal::trace("just some very verbose stuff here");
|
journal::trace("just some very verbose stuff here");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
Loading…
Reference in a new issue