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.
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