added sinks types
This commit is contained in:
parent
31d1dda7f8
commit
c79004413d
|
@ -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
|
||||
|
|
234
src/journal.cc
234
src/journal.cc
|
@ -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,19 +68,99 @@ 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";
|
||||
}
|
||||
}
|
||||
|
||||
struct Verbosity {
|
||||
|
@ -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 {
|
||||
init();
|
||||
auto &&[lock, ref] = detail::global_journal.mut();
|
||||
ref->add_std_out();
|
||||
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
|
||||
|
|
14
src/main.cc
14
src/main.cc
|
@ -3,11 +3,11 @@
|
|||
#include <iostream>
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
std::cin.get();
|
||||
journal::init_stdout();
|
||||
printf("Hello, Alloy!\n");
|
||||
journal::info("some info!");
|
||||
journal::error("something went wrong!");
|
||||
journal::trace("just some very verbose stuff here");
|
||||
return 1;
|
||||
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;
|
||||
}
|
Loading…
Reference in a new issue