Compare commits
5 commits
b78ffe90ce
...
fa8455d5dd
Author | SHA1 | Date | |
---|---|---|---|
|
fa8455d5dd | ||
|
0d9ec17ec3 | ||
|
e348c235fa | ||
|
8119729fb0 | ||
|
e9ca6a04e7 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
.cache/
|
.cache/
|
||||||
target/
|
target/
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
test.log
|
||||||
|
|
|
@ -6,8 +6,9 @@ version = "0.1.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libjournal"
|
name = "libjournal"
|
||||||
|
cc-flags = ["-DJOURNAL_GLOG_COMPAT", "-fno-threadsafe-statics"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "journal"
|
name = "journal"
|
||||||
cc-flags = ["-DJOURNAL_ALL", "-gcodeview", "-g"]
|
cc-flags = ["-DJOURNAL_GLOG_COMPAT", "-DJOURNAL_ALL", "-gcodeview", "-g"]
|
||||||
ld-flags = ["-g", "-gcodeview"]
|
ld-flags = ["-g", "-gcodeview"]
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "journal.hpp"
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace journal {
|
namespace journal {
|
||||||
|
@ -48,12 +51,34 @@ enum LogVerbosity {
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Verbosity {
|
||||||
|
journal::detail::LogVerbosity inner;
|
||||||
|
|
||||||
|
Verbosity(journal::detail::LogVerbosity &&value) : inner(value) {}
|
||||||
|
Verbosity(const journal::detail::LogVerbosity &value) : inner(value) {}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string;
|
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string;
|
||||||
|
|
||||||
|
namespace formatter {
|
||||||
|
|
||||||
|
struct Formatter {
|
||||||
|
virtual auto operator()(const Verbosity &verbosity,
|
||||||
|
const source_location &source) -> std::string = 0;
|
||||||
|
virtual ~Formatter() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace formatter
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto log(const LogVerbosity &verbosity, std::string_view fmt,
|
inline constexpr auto log(const LogVerbosity &verbosity,
|
||||||
Args... args, const detail::source_location source)
|
const detail::source_location &source,
|
||||||
-> void {
|
std::string_view fmt, Args... args) -> void {
|
||||||
const auto msg = std::vformat(fmt, std::make_format_args(args...));
|
const auto msg = std::vformat(fmt, std::make_format_args(args...));
|
||||||
log_internal(verbosity, source, msg);
|
log_internal(verbosity, source, msg);
|
||||||
}
|
}
|
||||||
|
@ -61,6 +86,7 @@ inline constexpr auto log(const LogVerbosity &verbosity, std::string_view fmt,
|
||||||
auto log_internal(const LogVerbosity &verbosity,
|
auto log_internal(const LogVerbosity &verbosity,
|
||||||
const detail::source_location source, const std::string &msg)
|
const detail::source_location source, const std::string &msg)
|
||||||
-> void;
|
-> void;
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
using detail::LogVerbosity;
|
using detail::LogVerbosity;
|
||||||
|
@ -68,6 +94,11 @@ using detail::LogVerbosity;
|
||||||
auto init_std_out(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_std_out_err(const LogVerbosity &min = LogVerbosity::Info) -> void;
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
|
auto init_no_threads() -> void;
|
||||||
|
auto set_formatter(std::unique_ptr<detail::formatter::Formatter> &&formatter)
|
||||||
|
-> void;
|
||||||
|
auto add_std_out() -> void;
|
||||||
|
auto add_std_err() -> void;
|
||||||
auto add_file(std::string_view file_path,
|
auto add_file(std::string_view file_path,
|
||||||
std::ios_base::openmode = std::ios_base::ate,
|
std::ios_base::openmode = std::ios_base::ate,
|
||||||
const LogVerbosity &min = LogVerbosity::Trace,
|
const LogVerbosity &min = LogVerbosity::Trace,
|
||||||
|
@ -76,7 +107,15 @@ auto add_sink(std::shared_ptr<std::ostream> stream,
|
||||||
const LogVerbosity &min = LogVerbosity::Trace,
|
const LogVerbosity &min = LogVerbosity::Trace,
|
||||||
const LogVerbosity &max = LogVerbosity::Error) -> void;
|
const LogVerbosity &max = LogVerbosity::Error) -> void;
|
||||||
|
|
||||||
#ifdef JOURNAL_ALL
|
template <typename T> inline constexpr auto ptr(T *p) -> const void * {
|
||||||
|
return reinterpret_cast<void *>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JOURNAL_NONE: undefines all logs
|
||||||
|
/// JOURNAL_ALL: defines all logs, on by default
|
||||||
|
/// JOURNAL_NOT_ALL: does not define any logs by default even it JOURNAL_ALL is
|
||||||
|
/// defined, off by default
|
||||||
|
#if defined(JOURNAL_ALL) && !defined(JOURNAL_NONE) && !defined(JOURNAL_NOT_ALL)
|
||||||
#define JOURNAL_TRACE
|
#define JOURNAL_TRACE
|
||||||
#define JOURNAL_DEBUG
|
#define JOURNAL_DEBUG
|
||||||
#define JOURNAL_INFO
|
#define JOURNAL_INFO
|
||||||
|
@ -84,69 +123,127 @@ auto add_sink(std::shared_ptr<std::ostream> stream,
|
||||||
#define JOURNAL_ERROR
|
#define JOURNAL_ERROR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(JOURNAL_NONE)
|
||||||
|
#undef JOURNAL_TRACE
|
||||||
|
#undef JOURNAL_DEBUG
|
||||||
|
#undef JOURNAL_INFO
|
||||||
|
#undef JOURNAL_WARN
|
||||||
|
#undef JOURNAL_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef JOURNAL_TRACE
|
#ifdef JOURNAL_TRACE
|
||||||
template <typename... Args>
|
template <typename... Ts> struct trace {
|
||||||
inline constexpr auto
|
trace(std::string_view fmt, Ts &&...args,
|
||||||
trace(std::string_view fmt, Args... args,
|
const detail::source_location &source =
|
||||||
const detail::source_location source = detail::source_location::current())
|
detail::source_location::current()) {
|
||||||
-> void {
|
detail::log(detail::LogVerbosity::Trace, source, fmt,
|
||||||
detail::log(detail::LogVerbosity::Trace, fmt, args..., source);
|
std::forward<Ts>(args)...);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts> trace(std::string_view, Ts &&...) -> trace<Ts...>;
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto trace(std::string_view fmt, Args... args) -> void {}
|
inline constexpr auto trace(std::string_view fmt, Args... args) -> void {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JOURNAL_DEBUG
|
#ifdef JOURNAL_DEBUG
|
||||||
template <typename... Args>
|
template <typename... Ts> struct debug {
|
||||||
inline constexpr auto
|
debug(std::string_view fmt, Ts &&...args,
|
||||||
debug(std::string_view fmt, Args... args,
|
const detail::source_location &source =
|
||||||
const detail::source_location source = detail::source_location::current())
|
detail::source_location::current()) {
|
||||||
-> void {
|
detail::log(detail::LogVerbosity::Debug, source, fmt,
|
||||||
detail::log(detail::LogVerbosity::Debug, fmt, args..., source);
|
std::forward<Ts>(args)...);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts> debug(std::string_view, Ts &&...) -> debug<Ts...>;
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto debug(std::string_view fmt, Args... args) -> void {}
|
inline constexpr auto debug(std::string_view fmt, Args... args) -> void {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JOURNAL_INFO
|
#ifdef JOURNAL_INFO
|
||||||
template <typename... Args>
|
template <typename... Ts> struct info {
|
||||||
inline constexpr auto
|
info(std::string_view fmt, Ts &&...args,
|
||||||
info(std::string_view fmt, Args... args,
|
const detail::source_location &source =
|
||||||
const detail::source_location source = detail::source_location::current())
|
detail::source_location::current()) {
|
||||||
-> void {
|
detail::log(detail::LogVerbosity::Info, source, fmt,
|
||||||
detail::log(detail::LogVerbosity::Info, fmt, args..., source);
|
std::forward<Ts>(args)...);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
info(std::string_view, Ts &&...) -> info<Ts...>;
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto info(std::string_view fmt, Args... args) -> void {}
|
inline constexpr auto info(std::string_view fmt, Args... args) -> void {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JOURNAL_WARN
|
#ifdef JOURNAL_WARN
|
||||||
template <typename... Args>
|
template <typename... Ts> struct warn {
|
||||||
inline constexpr auto
|
warn(std::string_view fmt, Ts &&...args,
|
||||||
warn(std::string_view fmt, Args... args,
|
const detail::source_location &source =
|
||||||
const detail::source_location source = detail::source_location::current())
|
detail::source_location::current()) {
|
||||||
-> void {
|
detail::log(detail::LogVerbosity::Warn, source, fmt,
|
||||||
detail::log(detail::LogVerbosity::Warn, fmt, args..., source);
|
std::forward<Ts>(args)...);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts> warn(std::string_view, Ts &&...) -> warn<Ts...>;
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto warn(std::string_view fmt, Args... args) -> void {}
|
inline constexpr auto warn(std::string_view fmt, Args... args) -> void {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JOURNAL_ERROR
|
#ifdef JOURNAL_ERROR
|
||||||
template <typename... Args>
|
template <typename... Ts> struct error {
|
||||||
inline constexpr auto
|
error(std::string_view fmt, Ts &&...args,
|
||||||
error(std::string_view fmt, Args... args,
|
const detail::source_location &source =
|
||||||
const detail::source_location source = detail::source_location::current())
|
detail::source_location::current()) {
|
||||||
-> void {
|
detail::log(detail::LogVerbosity::Error, source, fmt,
|
||||||
detail::log(detail::LogVerbosity::Error, fmt, args..., source);
|
std::forward<Ts>(args)...);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts> error(std::string_view, Ts &&...) -> error<Ts...>;
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline constexpr auto error(std::string_view fmt, Args... args) -> void {}
|
inline constexpr auto error(std::string_view fmt, Args... args) -> void {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace journal
|
} // namespace journal
|
||||||
|
|
||||||
|
/// JOURNAL_GLOG_COMPAT: enables LOG_F macro format which GLOG and Loguru use
|
||||||
|
/// for compatibility, on by default
|
||||||
|
#if defined(JOURNAL_GLOG_COMPAT)
|
||||||
|
namespace journal {
|
||||||
|
constexpr auto JournalGLogVerbosity_ERROR = detail::LogVerbosity::Error;
|
||||||
|
constexpr auto JournalGLogVerbosity_WARNING = detail::LogVerbosity::Warn;
|
||||||
|
constexpr auto JournalGLogVerbosity_WARN = detail::LogVerbosity::Warn;
|
||||||
|
constexpr auto JournalGLogVerbosity_INFO = detail::LogVerbosity::Info;
|
||||||
|
constexpr auto JournalGLogVerbosity_DEBUG = detail::LogVerbosity::Debug;
|
||||||
|
constexpr auto JournalGLogVerbosity_TRACE = detail::LogVerbosity::Trace;
|
||||||
|
|
||||||
|
struct GLogCompatHelper {
|
||||||
|
const detail::source_location source;
|
||||||
|
const detail::LogVerbosity verbosity;
|
||||||
|
|
||||||
|
consteval GLogCompatHelper(const detail::LogVerbosity &verbosity,
|
||||||
|
const detail::source_location &source =
|
||||||
|
detail::source_location::current()) noexcept
|
||||||
|
: source(source), verbosity(verbosity) {}
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
auto log(std::string_view fmt, Ts &&...args) const -> void {
|
||||||
|
detail::log(verbosity, source, fmt, std::forward<Ts>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace journal
|
||||||
|
|
||||||
|
#define LOG_F(V, ...) \
|
||||||
|
journal::GLogCompatHelper(journal::JournalGLogVerbosity_##V, \
|
||||||
|
journal::detail::source_location::current()) \
|
||||||
|
.log(__VA_ARGS__);
|
||||||
|
#endif
|
182
src/journal.cc
182
src/journal.cc
|
@ -10,7 +10,10 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <stop_token>
|
||||||
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace journal {
|
namespace journal {
|
||||||
namespace mutex {
|
namespace mutex {
|
||||||
|
@ -164,29 +167,39 @@ constexpr auto to_string(const LogVerbosity& verbosity) -> std::string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Verbosity {
|
namespace formatter {
|
||||||
journal::detail::LogVerbosity inner;
|
|
||||||
|
|
||||||
Verbosity(journal::detail::LogVerbosity &&value) : inner(value) {}
|
struct DefaultFormatter : public Formatter {
|
||||||
Verbosity(const journal::detail::LogVerbosity &value) : inner(value) {}
|
virtual auto operator()(const Verbosity &verbosity,
|
||||||
|
const source_location &source) -> std::string {
|
||||||
|
return std::format("[{}] [{: <5}] [{}]", get_current_time_string(),
|
||||||
|
to_string(verbosity.inner),
|
||||||
|
get_source_location_string(source));
|
||||||
|
}
|
||||||
|
|
||||||
auto operator<=>(const Verbosity &rhs) const -> std::strong_ordering {
|
auto get_source_location_string(const source_location &source)
|
||||||
return static_cast<std::underlying_type_t<decltype(inner)>>(inner) <=>
|
-> std::string {
|
||||||
static_cast<std::underlying_type_t<decltype(rhs.inner)>>(rhs.inner);
|
const auto file =
|
||||||
|
std::filesystem::path(source.file_name()).filename().string();
|
||||||
|
return std::format("{}::{}", file, source.line());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get_current_time_string() -> std::string {
|
||||||
|
const auto now = std::chrono::utc_clock::now();
|
||||||
|
|
||||||
|
return std::format("{:%Y-%m-%d %H:%M:%OS} UTC", now);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace formatter
|
||||||
namespace sinks {
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
struct BaseSink {
|
struct BaseSink {
|
||||||
Verbosity min_verbosity;
|
Verbosity min_verbosity;
|
||||||
Verbosity max_verbosity;
|
Verbosity max_verbosity;
|
||||||
|
|
||||||
std::optional<std::chrono::system_clock::time_point> last_flushed;
|
|
||||||
static constexpr auto TIME_BETWEEN_FLUSH = 2s;
|
|
||||||
|
|
||||||
BaseSink()
|
BaseSink()
|
||||||
: min_verbosity(LogVerbosity::Trace), max_verbosity(LogVerbosity::Error) {
|
: min_verbosity(LogVerbosity::Trace), max_verbosity(LogVerbosity::Error) {
|
||||||
}
|
}
|
||||||
|
@ -206,16 +219,6 @@ struct BaseSink {
|
||||||
return std::exchange(min_verbosity, new_min);
|
return std::exchange(min_verbosity, new_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto should_flush() -> bool {
|
|
||||||
const auto now = std::chrono::system_clock::now();
|
|
||||||
if (!last_flushed || (now - last_flushed.value()) >= TIME_BETWEEN_FLUSH) {
|
|
||||||
last_flushed = now;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual auto flush() -> void {}
|
virtual auto flush() -> void {}
|
||||||
virtual auto operator<<(std::string_view str) -> void {}
|
virtual auto operator<<(std::string_view str) -> void {}
|
||||||
};
|
};
|
||||||
|
@ -254,50 +257,102 @@ struct FileSink : public OStreamSink {
|
||||||
const Verbosity &max = LogVerbosity::Error)
|
const Verbosity &max = LogVerbosity::Error)
|
||||||
: OStreamSink(std::make_shared<std::ofstream>(file_path, open_mode), min,
|
: OStreamSink(std::make_shared<std::ofstream>(file_path, open_mode), min,
|
||||||
max) {}
|
max) {}
|
||||||
|
|
||||||
|
FileSink(const std::shared_ptr<std::ofstream> &file,
|
||||||
|
const Verbosity &min = LogVerbosity::Trace,
|
||||||
|
const Verbosity &max = LogVerbosity::Error)
|
||||||
|
: OStreamSink(file, min, max) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sinks
|
} // namespace sinks
|
||||||
|
|
||||||
|
static auto try_flush_all_loop(std::stop_token) -> void;
|
||||||
|
|
||||||
class Journal {
|
class Journal {
|
||||||
std::vector<std::unique_ptr<sinks::BaseSink>> sinks;
|
std::vector<std::unique_ptr<sinks::BaseSink>> sinks;
|
||||||
|
std::unique_ptr<formatter::Formatter> formatter;
|
||||||
|
std::optional<std::jthread> flush_thread;
|
||||||
|
std::chrono::system_clock::duration flush_interval;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Journal() {}
|
Journal()
|
||||||
auto log(const Verbosity &verbosity, source_location source,
|
: flush_interval(250ms),
|
||||||
std::string_view msg) {
|
formatter(std::make_unique<formatter::DefaultFormatter>()) {}
|
||||||
const auto now = std::chrono::system_clock::now();
|
~Journal() {
|
||||||
for (auto &&sink : sinks) {
|
if (flush_thread) {
|
||||||
if (sink->should_sink_verbosity(verbosity)) {
|
log(LogVerbosity::Trace, source_location::current(),
|
||||||
(*sink) << format(msg, verbosity, source);
|
"Requesting stop for flush thread");
|
||||||
|
flush_thread->request_stop();
|
||||||
|
log(LogVerbosity::Trace, source_location::current(),
|
||||||
|
"Waiting for flush thread to join..");
|
||||||
|
flush_thread->join();
|
||||||
|
log(LogVerbosity::Trace, source_location::current(),
|
||||||
|
"Flush thread joined");
|
||||||
}
|
}
|
||||||
if (sink->should_flush()) {
|
flush_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto reset_formatter() -> void {
|
||||||
|
formatter = std::make_unique<formatter::DefaultFormatter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set_formatter(std::unique_ptr<formatter::Formatter> &&formatter)
|
||||||
|
-> void {
|
||||||
|
formatter = std::move(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
set_flush_interval(const std::chrono::system_clock::duration &new_interval)
|
||||||
|
-> void {
|
||||||
|
flush_interval = new_interval;
|
||||||
|
}
|
||||||
|
auto get_flush_interval() const -> std::chrono::system_clock::duration {
|
||||||
|
return flush_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init_flush_thread() -> void {
|
||||||
|
flush_thread = std::jthread(&detail::try_flush_all_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto should_flush() const -> bool {
|
||||||
|
return !flush_thread.has_value() || flush_interval < 1ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flush_all() -> void { force_flush_all(); }
|
||||||
|
|
||||||
|
auto force_flush_all() -> void {
|
||||||
|
for (auto &&sink : sinks) {
|
||||||
sink->flush();
|
sink->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
auto log(const Verbosity &verbosity, source_location source,
|
||||||
|
std::string_view msg) -> void {
|
||||||
|
const auto do_flush = should_flush();
|
||||||
|
for (auto &&sink : sinks) {
|
||||||
|
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,
|
auto format(std::string_view str, const Verbosity &verbosity,
|
||||||
const source_location &source) -> std::string {
|
const source_location &source) -> std::string {
|
||||||
return std::format("[{}] [{: <5}] [{}] {}\n", get_current_time_string(),
|
return std::format("{} {}\n", (*formatter)(verbosity, source), str);
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_current_time_string() -> std::string {
|
|
||||||
const auto now = std::chrono::utc_clock::now();
|
|
||||||
|
|
||||||
return std::format("{:%Y-%m-%d %H:%M:%OS} UTC", now);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_file(const std::string &file_name,
|
auto add_file(const std::string &file_name,
|
||||||
std::ios::ios_base::openmode open_mode = std::ios::ios_base::app,
|
std::ios::ios_base::openmode open_mode = std::ios::ios_base::app,
|
||||||
const Verbosity &min = LogVerbosity::Trace,
|
const Verbosity &min = LogVerbosity::Trace,
|
||||||
const Verbosity &max = LogVerbosity::Error) -> void {
|
const Verbosity &max = LogVerbosity::Error) -> void {
|
||||||
add_sink(std::make_unique<sinks::FileSink>(file_name, open_mode, min, max));
|
auto file = std::make_shared<std::ofstream>(file_name, open_mode);
|
||||||
|
if (file->is_open() && !(file->bad() || file->fail())) {
|
||||||
|
add_sink(std::make_unique<sinks::FileSink>(file, min, max));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_sink(std::unique_ptr<sinks::BaseSink> &&sink) -> void {
|
auto add_sink(std::unique_ptr<sinks::BaseSink> &&sink) -> void {
|
||||||
|
@ -310,6 +365,18 @@ 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;
|
||||||
|
|
||||||
|
static auto try_flush_all_loop(std::stop_token stoken) -> void {
|
||||||
|
std::chrono::system_clock::duration interval = 250ms;
|
||||||
|
while (!stoken.stop_requested()) {
|
||||||
|
{
|
||||||
|
auto &&[lock, ref] = global_journal.mut();
|
||||||
|
interval = ref->get_flush_interval();
|
||||||
|
ref->flush_all();
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto log_internal(const LogVerbosity &verbosity, detail::source_location source,
|
auto log_internal(const LogVerbosity &verbosity, detail::source_location source,
|
||||||
const std::string &msg) -> void {
|
const std::string &msg) -> void {
|
||||||
auto &&[lock, ref] = global_journal.ref();
|
auto &&[lock, ref] = global_journal.ref();
|
||||||
|
@ -319,6 +386,14 @@ auto log_internal(const LogVerbosity &verbosity, detail::source_location source,
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
auto init() -> void {
|
auto init() -> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
if (!ref.get()) {
|
||||||
|
ref = std::make_unique<detail::Journal>();
|
||||||
|
ref->init_flush_thread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init_no_threads() -> 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>();
|
||||||
|
@ -338,6 +413,21 @@ auto init_std_out_err(const LogVerbosity &min) -> void {
|
||||||
ref->add_std_err();
|
ref->add_std_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto set_formatter(std::unique_ptr<detail::formatter::Formatter> &&formatter)
|
||||||
|
-> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->set_formatter(std::move(formatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_std_out() -> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->add_std_out();
|
||||||
|
}
|
||||||
|
auto add_std_err() -> void {
|
||||||
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
ref->add_std_err();
|
||||||
|
}
|
||||||
|
|
||||||
auto add_sink(std::shared_ptr<std::ostream> stream, const LogVerbosity &min,
|
auto add_sink(std::shared_ptr<std::ostream> stream, const LogVerbosity &min,
|
||||||
const LogVerbosity &max) -> void {
|
const LogVerbosity &max) -> void {
|
||||||
auto &&[lock, ref] = detail::global_journal.mut();
|
auto &&[lock, ref] = detail::global_journal.mut();
|
||||||
|
|
15
src/main.cc
15
src/main.cc
|
@ -1,13 +1,24 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include "journal.hpp"
|
#include "journal.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
journal::init_std_out_err();
|
auto stream = std::make_shared<std::stringstream>();
|
||||||
|
|
||||||
|
journal::init_no_threads();
|
||||||
|
journal::add_std_err();
|
||||||
|
journal::add_std_out();
|
||||||
|
journal::add_sink(stream, journal::LogVerbosity::Warn);
|
||||||
journal::add_file("test.log");
|
journal::add_file("test.log");
|
||||||
journal::info("some info!");
|
journal::info("some info!");
|
||||||
journal::error("something went wrong!");
|
journal::error("something went wrong!");
|
||||||
|
journal::warn("something went slightly wrong!");
|
||||||
|
LOG_F(INFO, "test ");
|
||||||
|
LOG_F(INFO, "test {}", 1.3f);
|
||||||
|
LOG_F(INFO, "test {} {} {}", 1.3f, true, 'C');
|
||||||
std::cin.get();
|
std::cin.get();
|
||||||
|
std::cout << "stream content: \n" << stream->view() << "\n";
|
||||||
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