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,
typename = std::enable_if_t<std::is_unsigned_v<Unsigned>>>
37 explicit constexpr HexBase(Unsigned value)
noexcept : value(value) {
38 static_assert(
sizeof(Unsigned) <=
sizeof(value));
42 explicit HexBase(T* pointer)
noexcept : HexBase(
reinterpret_cast<std::uintptr_t>(pointer)) {
43 static_assert(
sizeof(std::uintptr_t) <=
sizeof(value));
50struct Hex
final : impl::HexBase {
51 using impl::HexBase::HexBase;
56struct HexShort
final : impl::HexBase {
57 using impl::HexBase::HexBase;
62 std::string_view string;
70class LogHelper
final {
87 const LoggerPtr& logger,
94 LogHelper(LogHelper&&) =
delete;
95 LogHelper(
const LogHelper&) =
delete;
96 LogHelper& operator=(LogHelper&&) =
delete;
97 LogHelper& operator=(
const LogHelper&) =
delete;
100 LogHelper& AsLvalue()
noexcept {
return *
this; }
102 bool IsLimitReached()
const noexcept;
104 template <
typename T>
105 LogHelper& operator<<(
const T& value) {
106 if constexpr (std::is_constructible_v<std::string_view, T>) {
108 *
this << std::string_view{value};
109 }
else if constexpr (std::is_signed_v<T>) {
110 using LongLong =
long long;
111 *
this << LongLong{value};
112 }
else if constexpr (std::is_unsigned_v<T>) {
113 using UnsignedLongLong =
unsigned long long;
114 *
this << UnsignedLongLong{value};
115 }
else if constexpr (std::is_base_of_v<std::exception, T>) {
116 *
this <<
static_cast<
const std::exception&>(value);
117 }
else if constexpr (meta::kIsOstreamWritable<T>) {
121 }
else if constexpr (meta::kIsRange<T> && !formats::
common::kIsFormatValue<T>) {
127 "Please implement logging for your type: "
128 "logging::LogHelper& operator<<(logging::LogHelper& lh, "
136 LogHelper& operator<<(
char value)
noexcept;
137 LogHelper& operator<<(std::string_view value)
noexcept;
138 LogHelper& operator<<(
float value)
noexcept;
139 LogHelper& operator<<(
double value)
noexcept;
140 LogHelper& operator<<(
long double value)
noexcept;
141 LogHelper& operator<<(
unsigned long long value)
noexcept;
142 LogHelper& operator<<(
long long value)
noexcept;
143 LogHelper& operator<<(
bool value)
noexcept;
144 LogHelper& operator<<(
const std::exception& value)
noexcept;
147 LogHelper& operator<<(
const LogExtra& extra)
noexcept;
150 LogHelper& operator<<(LogExtra&& extra)
noexcept;
152 LogHelper& operator<<(
const LogExtra::Value& value)
noexcept;
154 LogHelper& operator<<(Hex hex)
noexcept;
156 LogHelper& operator<<(HexShort hex)
noexcept;
158 LogHelper& operator<<(Quoted value)
noexcept;
162 operator impl::Noop()
const noexcept {
return {}; }
167 impl::TagWriter GetTagWriterAfterText(InternalTag);
169 void MarkAsTrace(InternalTag);
173 friend class impl::TagWriter;
177 void DoLog()
noexcept;
179 void InternalLoggingError(std::string_view message)
noexcept;
181 impl::TagWriter GetTagWriter();
183 void PutFloatingPoint(
float value);
184 void PutFloatingPoint(
double value);
185 void PutFloatingPoint(
long double value);
186 void PutUnsigned(
unsigned long long value);
187 void PutSigned(
long long value);
188 void PutBoolean(
bool value);
189 void Put(std::string_view value);
190 void Put(
char value);
192 void PutRaw(std::string_view value_needs_no_escaping);
193 void PutException(
const std::exception& ex);
194 void PutQuoted(std::string_view value);
196 template <
typename T>
197 void PutRangeElement(
const T& value);
199 template <
typename T,
typename U>
200 void PutMapElement(
const std::pair<
const T, U>& value);
202 template <
typename T>
203 void PutRange(
const T& range);
205 std::ostream& Stream();
209 std::unique_ptr<Impl> pimpl_;
212inline LogHelper& operator<<(LogHelper& lh, std::error_code ec) {
213 lh << ec.category().name() <<
':' << ec.value() <<
" (" << ec.message() <<
')';
218LogHelper& operator<<(LogHelper& lh,
const std::atomic<T>& value) {
219 return lh << value.load();
223LogHelper& operator<<(LogHelper& lh,
const T* value)
noexcept {
224 if (value ==
nullptr) {
225 lh << std::string_view{
"(null)"};
226 }
else if constexpr (std::is_same_v<T,
char>) {
227 lh << std::string_view{value};
235LogHelper& operator<<(LogHelper& lh, T* value) {
236 return lh <<
static_cast<
const T*>(value);
240LogHelper& operator<<(LogHelper& lh,
const std::optional<T>& value) {
248template <
class Result,
class... Args>
249LogHelper& operator<<(LogHelper& lh, Result (*)(Args...)) {
250 static_assert(!
sizeof(Result),
"Outputting functions or std::ostream formatters is forbidden");
254LogHelper& operator<<(LogHelper& lh, std::chrono::system_clock::time_point tp);
255LogHelper& operator<<(LogHelper& lh, std::chrono::seconds value);
256LogHelper& operator<<(LogHelper& lh, std::chrono::milliseconds value);
257LogHelper& operator<<(LogHelper& lh, std::chrono::microseconds value);
258LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
259LogHelper& operator<<(LogHelper& lh, std::chrono::minutes value);
260LogHelper& operator<<(LogHelper& lh, std::chrono::nanoseconds value);
261LogHelper& operator<<(LogHelper& lh, std::chrono::hours value);
264void LogHelper::PutRangeElement(
const T& value) {
265 if constexpr (std::is_constructible_v<std::string_view, T>) {
266 *
this << Quoted{value};
272template <
typename T,
typename U>
273void LogHelper::PutMapElement(
const std::pair<
const T, U>& value) {
274 PutRangeElement(value.first);
276 PutRangeElement(value.second);
280void LogHelper::PutRange(
const T& range) {
281 static_assert(meta::kIsRange<T>);
286 !std::is_same_v<meta::RangeValueType<T>,
char>,
287 "You should either manually convert type to 'std::string_view' "
288 "or provide 'operator<<' specialization for your type: "
289 "'logging::LogHelper& operator<<(logging::LogHelper& lh, const "
291 "or make your type convertible to 'std::string_view'"
294 constexpr std::string_view kSeparator =
", ";
297 bool is_first =
true;
298 auto curr = begin(range);
299 const auto end_iter = end(range);
301 while (curr != end_iter) {
302 if (IsLimitReached()) {
311 if constexpr (meta::kIsMap<T>) {
312 PutMapElement(*curr);
314 PutRangeElement(*curr);
319 const auto extra_elements = std::distance(curr, end_iter);
321 if (extra_elements != 0) {
325 *
this <<
"..." << extra_elements <<
" more";