userver: userver/utils/traceful_exception.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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.
24 public:
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,
49 typename std::remove_reference<Exception>::type>::value,
50 Exception&&>::type
51 operator<<(Exception&& ex, const T& data) {
52 fmt::format_to(std::back_inserter(ex.GetMessageBuffer()), "{}", data);
53 ex.EnsureNullTerminated();
54 return std::forward<Exception>(ex);
55 }
56
57 private:
58 void EnsureNullTerminated();
59
60 MemoryBuffer& GetMessageBuffer();
61
62 struct Impl;
63 static constexpr std::size_t kSize =
65 utils::FastPimpl<Impl, kSize, alignof(void*)> impl_;
66};
67
68/// @ingroup userver_universal userver_base_classes
69///
70/// @brief Exception that remembers the backtrace at the point of its
71/// construction
72// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
73class TracefulException : public std::exception, public TracefulExceptionBase {
74 public:
75 using TracefulExceptionBase::TracefulExceptionBase;
76
77 const char* what() const noexcept override;
78};
79
80namespace impl {
81
82template <typename PlainException>
83// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
84class ExceptionWithAttachedTrace final : public PlainException,
86 public:
87 explicit ExceptionWithAttachedTrace(const PlainException& ex)
88 : PlainException(ex), TracefulExceptionBase(ex.what()) {}
89};
90
91template <typename Exception>
92std::enable_if_t<std::is_base_of<std::exception, Exception>::value,
93 ExceptionWithAttachedTrace<Exception>>
94AttachTraceToException(const Exception& ex) {
95 static_assert(!std::is_base_of<TracefulExceptionBase, Exception>::value,
96 "This exception already contains trace");
97 return ExceptionWithAttachedTrace<Exception>(ex);
98}
99
100} // namespace impl
101} // namespace utils
102
103USERVER_NAMESPACE_END