13#include <system_error>
16#include <userver/formats/common/meta.hpp>
17#include <userver/logging/fwd.hpp>
18#include <userver/logging/level.hpp>
19#include <userver/logging/log_extra.hpp>
20#include <userver/utils/impl/source_location.hpp>
21#include <userver/utils/meta.hpp>
23USERVER_NAMESPACE_BEGIN
36 template <
typename Unsigned,
37 typename = std::enable_if_t<std::is_unsigned_v<Unsigned>>>
38 explicit constexpr HexBase(Unsigned value)
noexcept : value(value) {
39 static_assert(
sizeof(Unsigned) <=
sizeof(value));
43 explicit HexBase(T* pointer)
noexcept
44 : 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;
58struct HexShort
final : impl::HexBase {
59 using impl::HexBase::HexBase;
64 std::string_view string;
72class LogHelper
final {
79 const utils::impl::SourceLocation& location =
87 const utils::impl::SourceLocation& location =
92 LogHelper(LogHelper&&) =
delete;
93 LogHelper(
const LogHelper&) =
delete;
94 LogHelper& operator=(LogHelper&&) =
delete;
95 LogHelper& operator=(
const LogHelper&) =
delete;
98 LogHelper& AsLvalue()
noexcept {
return *
this; }
100 bool IsLimitReached()
const noexcept;
102 template <
typename T>
103 LogHelper& operator<<(
const T& value) {
104 if constexpr (std::is_constructible_v<std::string_view, T>) {
106 *
this << std::string_view{value};
107 }
else if constexpr (std::is_signed_v<T>) {
108 using LongLong =
long long;
109 *
this << LongLong{value};
110 }
else if constexpr (std::is_unsigned_v<T>) {
111 using UnsignedLongLong =
unsigned long long;
112 *
this << UnsignedLongLong{value};
113 }
else if constexpr (std::is_base_of_v<std::exception, T>) {
114 *
this <<
static_cast<
const std::exception&>(value);
115 }
else if constexpr (meta::kIsOstreamWritable<T>) {
119 }
else if constexpr (meta::kIsRange<T> &&
120 !formats::
common::kIsFormatValue<T>) {
124 static_assert(!
sizeof(T),
125 "Please implement logging for your type: "
126 "logging::LogHelper& operator<<(logging::LogHelper& lh, "
133 LogHelper& operator<<(
char value)
noexcept;
134 LogHelper& operator<<(std::string_view value)
noexcept;
135 LogHelper& operator<<(
float value)
noexcept;
136 LogHelper& operator<<(
double value)
noexcept;
137 LogHelper& operator<<(
long double value)
noexcept;
138 LogHelper& operator<<(
unsigned long long value)
noexcept;
139 LogHelper& operator<<(
long long value)
noexcept;
140 LogHelper& operator<<(
bool value)
noexcept;
141 LogHelper& operator<<(
const std::exception& value)
noexcept;
144 LogHelper& operator<<(
const LogExtra& extra)
noexcept;
147 LogHelper& operator<<(LogExtra&& extra)
noexcept;
149 LogHelper& operator<<(
const LogExtra::Value& value)
noexcept;
151 LogHelper& operator<<(Hex hex)
noexcept;
153 LogHelper& operator<<(HexShort hex)
noexcept;
155 LogHelper& operator<<(Quoted value)
noexcept;
159 operator impl::Noop()
const noexcept {
return {}; }
164 impl::TagWriter GetTagWriterAfterText(InternalTag);
168 friend class impl::TagWriter;
172 void DoLog()
noexcept;
174 void InternalLoggingError(std::string_view message)
noexcept;
176 impl::TagWriter GetTagWriter();
178 void PutFloatingPoint(
float value);
179 void PutFloatingPoint(
double value);
180 void PutFloatingPoint(
long double value);
181 void PutUnsigned(
unsigned long long value);
182 void PutSigned(
long long value);
183 void PutBoolean(
bool value);
184 void Put(std::string_view value);
185 void Put(
char value);
187 void PutRaw(std::string_view value_needs_no_escaping);
188 void PutException(
const std::exception& ex);
189 void PutQuoted(std::string_view value);
191 template <
typename T>
192 void PutRangeElement(
const T& value);
194 template <
typename T,
typename U>
195 void PutMapElement(
const std::pair<
const T, U>& value);
197 template <
typename T>
198 void PutRange(
const T& range);
200 std::ostream& Stream();
204 std::unique_ptr<Impl> pimpl_;
207inline LogHelper& operator<<(LogHelper& lh, std::error_code ec) {
208 lh << ec.category().name() <<
':' << ec.value() <<
" (" << ec.message()
214LogHelper& operator<<(LogHelper& lh,
const std::atomic<T>& value) {
215 return lh << value.load();
219LogHelper& operator<<(LogHelper& lh,
const T* value)
noexcept {
220 if (value ==
nullptr) {
221 lh << std::string_view{
"(null)"};
222 }
else if constexpr (std::is_same_v<T,
char>) {
223 lh << std::string_view{value};
231LogHelper& operator<<(LogHelper& lh, T* value) {
232 return lh <<
static_cast<
const T*>(value);
236LogHelper& operator<<(LogHelper& lh,
const std::optional<T>& value) {
244template <
class Result,
class... Args>
245LogHelper& operator<<(LogHelper& lh, Result (*)(Args...)) {
246 static_assert(!
sizeof(Result),
247 "Outputting functions or std::ostream formatters is forbidden");
251LogHelper& operator<<(LogHelper& lh, std::chrono::system_clock::time_point tp);
252LogHelper& operator<<(LogHelper& lh, std::chrono::seconds value);
253LogHelper& operator<<(LogHelper& lh, std::chrono::milliseconds value);
254LogHelper& operator<<(LogHelper& lh, std::chrono::microseconds value);
255LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
256LogHelper& operator<<(LogHelper& lh, std::chrono::minutes value);
257LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
258LogHelper& operator<<(LogHelper& lh, std::chrono::hours value);
261void LogHelper::PutRangeElement(
const T& value) {
262 if constexpr (std::is_constructible_v<std::string_view, T>) {
263 *
this << Quoted{value};
269template <
typename T,
typename U>
270void LogHelper::PutMapElement(
const std::pair<
const T, U>& value) {
271 PutRangeElement(value.first);
273 PutRangeElement(value.second);
277void LogHelper::PutRange(
const T& range) {
278 static_assert(meta::kIsRange<T>);
282 constexpr std::string_view kSeparator =
", ";
285 bool is_first =
true;
286 auto curr = begin(range);
287 const auto end_iter = end(range);
289 while (curr != end_iter) {
290 if (IsLimitReached()) {
299 if constexpr (meta::kIsMap<T>) {
300 PutMapElement(*curr);
302 PutRangeElement(*curr);
307 const auto extra_elements = std::distance(curr, end_iter);
309 if (extra_elements != 0) {
313 *
this <<
"..." << extra_elements <<
" more";