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