userver: userver/utils/traceful_exception.hpp Source File
Loading...
Searching...
No Matches
traceful_exception.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/traceful_exception.hpp
4/// @brief @copybrief utils::TracefulException
5
6#include <exception>
7#include <iterator>
8#include <string>
9#include <type_traits>
10
11#include <fmt/format.h>
12#include <boost/stacktrace/stacktrace_fwd.hpp>
13
14#include <userver/compiler/select.hpp>
15#include <userver/utils/fast_pimpl.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace utils {
20
21/// @brief Base class implementing backtrace storage and message builder,
22/// published only for documentation purposes, please inherit from
23/// utils::TracefulException instead.
24class TracefulExceptionBase {
25public:
26 enum class TraceMode {
27 kAlways,
28 kIfLoggingIsEnabled,
29 };
30
31 static constexpr size_t kInlineBufferSize = 100;
32 using MemoryBuffer = fmt::basic_memory_buffer<char, kInlineBufferSize>;
33
34 TracefulExceptionBase();
35
36 explicit TracefulExceptionBase(std::string_view what);
37
38 explicit TracefulExceptionBase(TraceMode trace_mode);
39
40 TracefulExceptionBase(TracefulExceptionBase&&) noexcept;
41 virtual ~TracefulExceptionBase() = 0;
42
43 const MemoryBuffer& MessageBuffer() const noexcept;
44 const boost::stacktrace::basic_stacktrace<>& Trace() const noexcept;
45
46 /// Stream-like interface for message extension
47 template <typename Exception, typename T>
48 requires std::is_base_of_v<TracefulExceptionBase, std::remove_reference_t<Exception>>
49 friend Exception&& operator<<(Exception&& ex, const T& data) {
50 fmt::format_to(std::back_inserter(ex.GetMessageBuffer()), "{}", data);
51 ex.EnsureNullTerminated();
52 return std::forward<Exception>(ex);
53 }
54
55private:
56 void EnsureNullTerminated();
57
58 MemoryBuffer& GetMessageBuffer();
59
60 struct Impl;
61 static constexpr std::size_t kSize = sizeof(MemoryBuffer) + compiler::SelectSize().For64Bit(24).For32Bit(12);
62 utils::FastPimpl<Impl, kSize, alignof(void*)> impl_;
63};
64
65/// @ingroup userver_universal userver_base_classes
66///
67/// @brief Exception that remembers the backtrace at the point of its
68/// construction
69// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
70class TracefulException : public std::exception, public TracefulExceptionBase {
71public:
72 using TracefulExceptionBase::TracefulExceptionBase;
73
74 const char* what() const noexcept override;
75};
76
77namespace impl {
78
79template <typename PlainException>
80// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
81class ExceptionWithAttachedTrace final : public PlainException, public TracefulExceptionBase {
82public:
83 explicit ExceptionWithAttachedTrace(const PlainException& ex)
84 : PlainException(ex),
85 TracefulExceptionBase(ex.what())
86 {}
87};
88
89template <typename Exception>
90requires std::is_base_of_v<std::exception, Exception>
91ExceptionWithAttachedTrace<Exception> AttachTraceToException(const Exception& ex) {
92 static_assert(!std::is_base_of_v<TracefulExceptionBase, Exception>, "This exception already contains trace");
93 return ExceptionWithAttachedTrace<Exception>(ex);
94}
95
96} // namespace impl
97} // namespace utils
98
99USERVER_NAMESPACE_END