added sinks types

This commit is contained in:
janis 2022-06-20 20:31:07 +01:00
parent 31d1dda7f8
commit c79004413d
4 changed files with 230 additions and 32 deletions

View file

@ -1,6 +1,7 @@
#pragma once
#include <format>
#include <ios>
#include <string_view>
namespace journal {
@ -64,7 +65,16 @@ auto log_internal(const LogVerbosity &verbosity,
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
#define JOURNAL_TRACE

View file

@ -3,14 +3,13 @@
#include <chrono>
#include <compare>
#include <concepts>
#include <cstdio>
#include <iostream>
#include <filesystem>
#include <fstream>
#include <memory>
#include <mutex>
#include <optional>
#include <ostream>
#include <string_view>
#include <type_traits>
#include <filesystem>
namespace journal {
namespace mutex {
@ -69,18 +68,98 @@ public:
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 {
switch (verbosity) {
case LogVerbosity::Trace:
return "Trace";
return "TRACE";
case LogVerbosity::Debug:
return "Debug";
return "DEBUG";
case LogVerbosity::Info:
return "Info";
return "INFO ";
case LogVerbosity::Warn:
return "Warn";
return "WARN ";
case LogVerbosity::Error:
return "Error";
return "ERROR";
}
}
@ -90,12 +169,77 @@ struct Verbosity {
Verbosity(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) <=>
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 {
std::shared_ptr<std::ostream> stream;
Verbosity min_verbosity;
@ -112,25 +256,39 @@ struct Sink {
: stream(std::move(stream)), min_verbosity(min),
max_verbosity(journal::detail::Error) {}
~Sink() { flush(); }
auto flush() -> void { stream->flush(); }
auto operator<<(std::string_view msg) { (*stream) << msg; }
};
class Journal {
std::vector<Sink> sinks;
std::vector<std::unique_ptr<sinks::BaseSink>> sinks;
std::chrono::system_clock::time_point last_flushed;
public:
Journal() {}
auto log(const Verbosity &verbosity, source_location source,
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) {
if (verbosity >= sink.min_verbosity && verbosity <= sink.max_verbosity) {
sink << std::format("[{}] [{: <5}] [{}] {}\n",
get_current_time_string(), to_string(verbosity.inner),
get_source_location_string(source), msg);
if (sink->should_sink_verbosity(verbosity)) {
(*sink) << format(msg, verbosity, source);
}
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 {
const auto file = std::filesystem::path(source.file_name()).filename().string();
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);
}
auto add_std_out(const Verbosity &min = journal::detail::LogVerbosity::Info) {
auto out = std::shared_ptr<std::ostream>(&std::cout, [](auto &&_) {});
sinks.emplace_back(std::move(out));
auto add_file(const std::string &file_name,
std::ios::ios_base::openmode open_mode = std::ios::ios_base::app,
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;
@ -158,16 +325,35 @@ auto log_internal(const LogVerbosity &verbosity, detail::source_location source,
}
} // namespace detail
auto init() {
auto init() -> void {
auto &&[lock, ref] = detail::global_journal.mut();
if (!ref.get()) {
ref = std::make_unique<detail::Journal>();
}
}
auto init_stdout(const LogVerbosity &min) -> void {
auto init_std_out(const LogVerbosity &min) -> void {
init();
auto &&[lock, ref] = detail::global_journal.mut();
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

View file

@ -3,11 +3,11 @@
#include <iostream>
int main(int argc, const char* argv[]) {
std::cin.get();
journal::init_stdout();
printf("Hello, Alloy!\n");
journal::init_std_out_err();
journal::add_file("test.log");
journal::info("some info!");
journal::error("something went wrong!");
std::cin.get();
journal::trace("just some very verbose stuff here");
return 1;
}

2
test.log Normal file
View file

@ -0,0 +1,2 @@
[2022-06-20 00:49:18 UTC] [INFO ] [main.cc::8] some info!
[2022-06-20 00:49:18 UTC] [ERROR] [main.cc::9] something went wrong!