13#include <system_error>
18#include <userver/formats/common/meta.hpp>
19#include <userver/logging/fwd.hpp>
20#include <userver/logging/level.hpp>
21#include <userver/logging/log_extra.hpp>
22#include <userver/utils/impl/source_location.hpp>
23#include <userver/utils/meta.hpp>
25USERVER_NAMESPACE_BEGIN
38 template <
typename Unsigned,
typename = std::enable_if_t<std::is_unsigned_v<Unsigned>>>
39 explicit constexpr HexBase(Unsigned value)
noexcept : value(value) {
40 static_assert(
sizeof(Unsigned) <=
sizeof(value));
44 explicit HexBase(T* pointer)
noexcept : HexBase(
reinterpret_cast<std::uintptr_t>(pointer)) {
45 static_assert(
sizeof(std::uintptr_t) <=
sizeof(value));
52struct Hex
final : impl::HexBase {
53 using impl::HexBase::HexBase;
52struct Hex
final : impl::HexBase {
…};
58struct HexShort
final : impl::HexBase {
59 using impl::HexBase::HexBase;
58struct HexShort
final : impl::HexBase {
…};
64 std::string_view string;
63struct Quoted
final {
…};
77class LogHelper
final {
87 LogClass log_class = LogClass::kLog,
88 const utils::impl::SourceLocation& location =
utils::impl::SourceLocation::Current()
97 const LoggerPtr& logger,
99 LogClass log_class = LogClass::kLog,
100 const utils::impl::SourceLocation& location =
utils::impl::SourceLocation::Current()
105 LogHelper(LogHelper&&) =
delete;
106 LogHelper(
const LogHelper&) =
delete;
107 LogHelper& operator=(LogHelper&&) =
delete;
108 LogHelper& operator=(
const LogHelper&) =
delete;
111 LogHelper& AsLvalue()
noexcept {
return *
this; }
114 template <
typename... Args>
115 LogHelper& AsLvalue(fmt::format_string<Args...> fmt, Args&&... args)
noexcept {
116 VFormat(fmt::string_view(fmt), fmt::make_format_args(args...));
121 bool IsLimitReached()
const noexcept;
123 template <
typename T>
124 LogHelper& operator<<(
const T& value) {
125 if constexpr (std::is_constructible_v<std::string_view, T>) {
127 *
this << std::string_view{value};
128 }
else if constexpr (std::is_signed_v<T>) {
129 using LongLong =
long long;
130 *
this << LongLong{value};
131 }
else if constexpr (std::is_unsigned_v<T>) {
132 using UnsignedLongLong =
unsigned long long;
133 *
this << UnsignedLongLong{value};
134 }
else if constexpr (std::is_base_of_v<std::exception, T>) {
135 *
this <<
static_cast<
const std::exception&>(value);
136 }
else if constexpr (meta::kIsOstreamWritable<T>) {
140 }
else if constexpr (meta::kIsRange<T> && !
formats::
common::kIsFormatValue<T>) {
146 "Please implement logging for your type: "
147 "logging::LogHelper& operator<<(logging::LogHelper& lh, const T& value)"
154 LogHelper& operator<<(
char value)
noexcept;
155 LogHelper& operator<<(std::string_view value)
noexcept;
156 LogHelper& operator<<(
float value)
noexcept;
157 LogHelper& operator<<(
double value)
noexcept;
158 LogHelper& operator<<(
long double value)
noexcept;
159 LogHelper& operator<<(
unsigned long long value)
noexcept;
160 LogHelper& operator<<(
long long value)
noexcept;
161 LogHelper& operator<<(
bool value)
noexcept;
162 LogHelper& operator<<(
const std::exception& value)
noexcept;
165 LogHelper& operator<<(
const LogExtra& extra)
noexcept;
168 LogHelper& operator<<(LogExtra&& extra)
noexcept;
170 LogHelper& operator<<(Hex hex)
noexcept;
172 LogHelper& operator<<(HexShort hex)
noexcept;
174 LogHelper& operator<<(Quoted value)
noexcept;
176 LogHelper& PutTag(std::string_view key,
const LogExtra::Value& value)
noexcept;
177 LogHelper& PutSwTag(std::string_view key, std::string_view value)
noexcept;
183 template <
typename... Args>
184 LogHelper&
Format(fmt::format_string<Args...> fmt, Args&&... args)
noexcept;
188 operator impl::Noop()
const noexcept {
return {}; }
193 impl::TagWriter GetTagWriter();
198 friend class impl::TagWriter;
200 void DoLog()
noexcept;
202 void InternalLoggingError(std::string_view message)
noexcept;
204 void PutFloatingPoint(
float value);
205 void PutFloatingPoint(
double value);
206 void PutFloatingPoint(
long double value);
207 void PutUnsigned(
unsigned long long value);
208 void PutSigned(
long long value);
209 void PutBoolean(
bool value);
210 void Put(std::string_view value);
211 void Put(
char value);
213 void PutRaw(std::string_view value_needs_no_escaping);
214 void PutException(
const std::exception& ex);
215 void PutQuoted(std::string_view value);
217 void VFormat(fmt::string_view fmt, fmt::format_args args)
noexcept;
219 template <
typename T>
220 void PutRangeElement(
const T& value);
222 template <
typename T,
typename U>
223 void PutMapElement(
const std::pair<
const T, U>& value);
225 template <
typename T>
226 void PutRange(
const T& range);
228 std::ostream& Stream();
232 std::unique_ptr<Impl> pimpl_;
77class LogHelper
final {
…};
235inline LogHelper& operator<<(LogHelper& lh, std::error_code ec) {
236 lh << ec.category().name() <<
':' << ec.value() <<
" (" << ec.message() <<
')';
241LogHelper& operator<<(LogHelper& lh,
const std::atomic<T>& value) {
242 return lh << value.load();
246LogHelper& operator<<(LogHelper& lh,
const T* value)
noexcept {
247 if (value ==
nullptr) {
248 lh << std::string_view{
"(null)"};
249 }
else if constexpr (std::is_same_v<T,
char>) {
250 lh << std::string_view{value};
258LogHelper& operator<<(LogHelper& lh, T* value) {
260 !std::is_function_v<T>,
261 "An attempt to log the function address is denied. If you really know what you're doing, cast it to void*."
263 return lh <<
static_cast<
const T*>(value);
267LogHelper& operator<<(LogHelper& lh,
const std::optional<T>& value) {
275template <
typename Fun,
typename = std::enable_if_t<std::is_invocable_r_v<
void, Fun, LogHelper&>>>
276LogHelper& operator<<(LogHelper& lh, Fun&& value) {
277 std::forward<Fun>(value)(lh);
281template <
class Result,
class... Args>
282LogHelper& operator<<(LogHelper& lh, Result (*)(Args...)) {
283 static_assert(!
sizeof(Result),
"Outputting functions or std::ostream formatters is forbidden");
287LogHelper& operator<<(LogHelper& lh, std::chrono::system_clock::time_point tp);
288LogHelper& operator<<(LogHelper& lh, std::chrono::seconds value);
289LogHelper& operator<<(LogHelper& lh, std::chrono::milliseconds value);
290LogHelper& operator<<(LogHelper& lh, std::chrono::microseconds value);
291LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
292LogHelper& operator<<(LogHelper& lh, std::chrono::minutes value);
293LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
294LogHelper& operator<<(LogHelper& lh, std::chrono::hours value);
297void LogHelper::PutRangeElement(
const T& value) {
298 if constexpr (std::is_constructible_v<std::string_view, T>) {
299 *
this << Quoted{value};
305template <
typename T,
typename U>
306void LogHelper::PutMapElement(
const std::pair<
const T, U>& value) {
307 PutRangeElement(value.first);
309 PutRangeElement(value.second);
313void LogHelper::PutRange(
const T& range) {
314 static_assert(meta::kIsRange<T>);
319 !std::is_same_v<meta::RangeValueType<T>,
char>,
320 "You should either manually convert type to 'std::string_view' or provide 'operator<<' specialization for your "
321 "type: 'logging::LogHelper& operator<<(logging::LogHelper& lh, const T& value)' or make your type convertible "
322 "to 'std::string_view'"
325 constexpr std::string_view kSeparator =
", ";
328 bool is_first =
true;
329 auto curr = begin(range);
330 const auto end_iter = end(range);
332 while (curr != end_iter) {
333 if (IsLimitReached()) {
342 if constexpr (meta::kIsMap<T>) {
343 PutMapElement(*curr);
345 PutRangeElement(*curr);
350 const auto extra_elements = std::distance(curr, end_iter);
352 if (extra_elements != 0) {
356 *
this <<
"..." << extra_elements <<
" more";
362template <
typename... Args>
363LogHelper& LogHelper::
Format(fmt::format_string<Args...> fmt, Args&&... args)
noexcept {
364 VFormat(fmt::string_view(fmt), fmt::make_format_args(args...));
363LogHelper& LogHelper::
Format(fmt::format_string<Args...> fmt, Args&&... args)
noexcept {
…}