diff options
Diffstat (limited to 'server/src/log.cpp')
| -rw-r--r-- | server/src/log.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/server/src/log.cpp b/server/src/log.cpp new file mode 100644 index 0000000..7fe725f --- /dev/null +++ b/server/src/log.cpp | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | module routemon:log$impl; | ||
| 2 | |||
| 3 | import :log; | ||
| 4 | |||
| 5 | namespace routemon::log { | ||
| 6 | |||
| 7 | auto operator<<(std::ostream& os, level lvl) -> std::ostream& | ||
| 8 | { | ||
| 9 | switch (lvl) | ||
| 10 | { | ||
| 11 | case level::debug: | ||
| 12 | os << "dbg"; | ||
| 13 | break; | ||
| 14 | case level::info: | ||
| 15 | os << "inf"; | ||
| 16 | break; | ||
| 17 | case level::warn: | ||
| 18 | os << "wrn"; | ||
| 19 | break; | ||
| 20 | case level::error: | ||
| 21 | os << "err"; | ||
| 22 | break; | ||
| 23 | } | ||
| 24 | return os; | ||
| 25 | } | ||
| 26 | |||
| 27 | sink::sink(enum level lvl) : lvl_{lvl} {} | ||
| 28 | |||
| 29 | auto sink::level() const -> enum level { return lvl_; } | ||
| 30 | |||
| 31 | auto sink::set_level(enum level lvl) -> void { lvl_ = lvl; } | ||
| 32 | |||
| 33 | auto sink::write(tmp_message msg) -> void | ||
| 34 | { | ||
| 35 | auto sos = std::osyncstream{os_}; | ||
| 36 | sos << "[" << msg.lvl; | ||
| 37 | if (!msg.component.empty()) | ||
| 38 | sos << " " << msg.component; | ||
| 39 | sos << "] " << msg.txt; | ||
| 40 | for (auto const& [k, v] : msg.attrs) | ||
| 41 | sos << " " << k << "=" << std::quoted(v); | ||
| 42 | sos << '\n'; | ||
| 43 | } | ||
| 44 | |||
| 45 | auto make_sink(level lvl) -> std::shared_ptr<sink> | ||
| 46 | { | ||
| 47 | return std::shared_ptr<sink>{new sink{lvl}}; | ||
| 48 | } | ||
| 49 | |||
| 50 | auto logger::log_at(log::level lvl, std::string_view fmt, std::format_args args) | ||
| 51 | -> logger& | ||
| 52 | { | ||
| 53 | if (sink_->level() <= lvl) | ||
| 54 | sink_->write( | ||
| 55 | sink::tmp_message{ | ||
| 56 | .lvl = lvl, | ||
| 57 | .component = component_, | ||
| 58 | .txt = std::vformat(fmt, args), | ||
| 59 | .attrs = attrs_, | ||
| 60 | }); | ||
| 61 | return *this; | ||
| 62 | } | ||
| 63 | |||
| 64 | logger::logger(std::shared_ptr<sink> const& sink) : sink_{sink} | ||
| 65 | { | ||
| 66 | if (!sink) | ||
| 67 | { | ||
| 68 | throw std::invalid_argument{"logger sink may not be null"}; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | auto logger::sub(std::string_view component) const -> logger | ||
| 73 | { | ||
| 74 | auto l = *this; | ||
| 75 | if (l.component_.empty()) | ||
| 76 | { | ||
| 77 | l.component_ = component; | ||
| 78 | } | ||
| 79 | else | ||
| 80 | { | ||
| 81 | l.component_ += "."; | ||
| 82 | l.component_ += component; | ||
| 83 | } | ||
| 84 | return l; | ||
| 85 | } | ||
| 86 | |||
| 87 | auto logger::with(std::string const& k, std::string&& v) const -> logger | ||
| 88 | { | ||
| 89 | auto l = *this; | ||
| 90 | l.attrs_[k] = std::move(v); | ||
| 91 | return l; | ||
| 92 | } | ||
| 93 | |||
| 94 | auto logger::with(std::string const& k, std::string_view v) const -> logger | ||
| 95 | { | ||
| 96 | return with(k, std::string{v}); | ||
| 97 | } | ||
| 98 | |||
| 99 | } // namespace routemon::log | ||