My Project 3.7.1
C++ Distributed Hash Table
Loading...
Searching...
No Matches
logger.h
1// Copyright (c) 2014-2026 Savoir-faire Linux Inc.
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "infohash.h"
6
7#include <fmt/format.h>
8#include <fmt/printf.h>
9
10#include <functional>
11#include <mutex>
12#include <string_view>
13#include <type_traits>
14#include <cstdarg>
15
16#if __cplusplus >= 202002L
17#include <source_location>
18#endif
19
20namespace dht {
21namespace log {
22
23#if __cplusplus >= 202002L
27consteval std::string_view
28getfilename(std::string_view path)
29{
30 size_t pos = path.size();
31 for (size_t i = path.size(); i-- > 0;) {
32 if (path[i] == '/' || path[i] == '\\') {
33 pos = i + 1;
34 break;
35 }
36 }
37 return path.substr(pos);
38}
39
40consteval std::string_view
41getfunctionname(std::string_view path)
42{
43 size_t pos = 0;
44 size_t end = path.size();
45 for (size_t i = 0; i < path.size(); i++) {
46 if (path[i] == ' ' || path[i] == '\t' || path[i] == ':') {
47 pos = i + 1;
48 } else if (path[i] == '(') {
49 end = i;
50 break;
51 }
52 }
53 return path.substr(pos, end - pos);
54}
55#endif
56
57struct source_loc
58{
59 std::string_view file;
60 std::uint_least32_t line;
61 std::string_view function;
62
63#if __cplusplus >= 202002L
64 consteval source_loc(const std::source_location& loc)
65 : file(getfilename(loc.file_name()))
66 , line(loc.line())
67 , function(getfunctionname(loc.function_name()))
68 {}
69#else
70 constexpr source_loc()
71 : file()
72 , line(0)
73 , function()
74 {}
75#endif
76};
77
78enum class LogLevel { debug, warning, error };
79
80using LogMethod = std::function<void(source_loc, LogLevel, std::string_view, std::string&&)>;
81
82template<typename... Args>
83struct LogFormat
84{
85 fmt::format_string<Args...> fmt;
86 source_loc loc;
87
88#if __cplusplus >= 202002L
89 template<typename S>
90 consteval LogFormat(const S& s, const std::source_location& l = std::source_location::current())
91 : fmt(s)
92 , loc(l)
93 {}
94#else
95 template<typename S>
96 constexpr LogFormat(const S& s)
97 : fmt(s)
98 , loc()
99 {}
100#endif
101};
102
103#if __cplusplus < 202002L
104template<class _Tp>
106{
107 typedef _Tp type;
108};
109template<class _Tp>
110using type_identity_t = typename type_identity<_Tp>::type;
111#else
112using std::type_identity_t;
113#endif
114
115struct OPENDHT_PUBLIC Logger
116{
117 Logger() = delete;
118 Logger(LogMethod&& l, std::string tag = "")
119 : logger_(std::move(l))
120 , tag_(std::move(tag))
121 , prefix_(tag_.empty() ? "" : fmt::format("[{}] ", tag_))
122 {
123 if (!logger_)
124 throw std::invalid_argument {"logger must be set"};
125 }
126 Logger(const Logger& parent, std::string tag)
127 : logger_(parent.logger_)
128 , tag_(std::move(tag))
129 , prefix_(fmt::format("{}[{}] ", parent.prefix_, tag_))
130 {}
131
132 std::shared_ptr<Logger> createChild(std::string tag)
133 {
134 std::lock_guard<std::mutex> lock {children_mutex_};
135 auto child = std::make_shared<Logger>(*this, std::move(tag));
136 children_.push_back(child);
137 return child;
138 }
139
140 void setFilter(std::string_view filter)
141 {
142 std::lock_guard<std::mutex> lock {children_mutex_};
143 enable_ = filter.empty() or tag_.find(filter) != std::string_view::npos;
144 for (auto it = children_.begin(); it != children_.end();) {
145 if (auto c = it->lock()) {
146 c->setFilter(enable_ ? std::string_view {} : filter);
147 ++it;
148 } else {
149 it = children_.erase(it);
150 }
151 }
152 }
153
154 void setFilter(const InfoHash& f) { setFilter(f.to_view()); }
155
156 inline void log0(source_loc loc, LogLevel level, fmt::string_view format, fmt::printf_args args) const
157 {
158 if (enable_)
159 logger_(loc, level, prefix_, fmt::vsprintf(format, args));
160 }
161 template<typename... Args>
162 inline void debug(LogFormat<type_identity_t<Args>...> format, Args&&... args) const
163 {
164 if (enable_)
165 logger_(format.loc, LogLevel::debug, prefix_, fmt::format(format.fmt, std::forward<Args>(args)...));
166 }
167 template<typename... Args>
168 inline void warn(LogFormat<type_identity_t<Args>...> format, Args&&... args) const
169 {
170 if (enable_)
171 logger_(format.loc, LogLevel::warning, prefix_, fmt::format(format.fmt, std::forward<Args>(args)...));
172 }
173 template<typename... Args>
174 inline void error(LogFormat<type_identity_t<Args>...> format, Args&&... args) const
175 {
176 if (enable_)
177 logger_(format.loc, LogLevel::error, prefix_, fmt::format(format.fmt, std::forward<Args>(args)...));
178 }
179 template<typename... T>
180 inline void d(LogFormat<type_identity_t<T>...> format, T&&... args) const
181 {
182 log0(format.loc, LogLevel::debug, format.fmt, fmt::make_printf_args(args...));
183 }
184 template<typename... T>
185 inline void w(LogFormat<type_identity_t<T>...> format, T&&... args) const
186 {
187 log0(format.loc, LogLevel::warning, format.fmt, fmt::make_printf_args(args...));
188 }
189 template<typename... T>
190 inline void e(LogFormat<type_identity_t<T>...> format, T&&... args) const
191 {
192 log0(format.loc, LogLevel::error, format.fmt, fmt::make_printf_args(args...));
193 }
194
195private:
196 const LogMethod logger_ = {};
197 const std::string tag_ {};
198 const std::string prefix_ {};
199 std::mutex children_mutex_ {};
200 std::vector<std::weak_ptr<Logger>> children_ {};
201 bool enable_ {true};
202};
203
204} // namespace log
205using Logger = log::Logger;
206} // namespace dht
std::string_view to_view() const
Definition infohash.h:240