trace.cpp
Go to the documentation of this file.
1#include "trace.h"
2
3#include <cmath>
4#include <deque>
5#include <iomanip>
6#include <iostream>
7#include <memory>
8
9// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
10// /////////////////////////////////////////////// debug /////////////////////////////////////////////// //
11// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
12#define ACTIVATE_TRACE_LIB_TERMINATE_ON_INTERNAL_ERROR
13#ifdef ACTIVATE_TRACE_LIB_TERMINATE_ON_INTERNAL_ERROR
14#define TerminateIf(...) \
15 { \
16 if (__VA_ARGS__) \
17 { \
18 std::cerr << "TERMINATING!:\n (" << #__VA_ARGS__ << ") == true\n " \
19 << "'" << BOOST_CURRENT_FUNCTION << "' @ " << __LINE__ << " in '" \
20 << __FILE__ << "'\n " \
21 << "Stack Trace:\n"; \
22 Trace::PrintStackTrace(std::cerr, " "); \
23 std::cerr << std::flush; \
24 std::terminate(); \
25 } \
26 } \
27 do \
28 { \
29 } while (false)
30#else
31#define TerminateIf(...) \
32 do \
33 { \
34 } while (false)
35#endif
36// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
37// /////////////////////////////////////////////// types /////////////////////////////////////////////// //
38// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
39namespace armarx::detail
40{
42 {
43 static void PrintExceptionBacktrace(std::ostream& out, const std::string& pre);
44 static void ClearExceptionBacktrace();
45
46 static thread_local ExceptionBacktraceTree* Active;
47 static thread_local std::deque<ExceptionBacktraceTree> All;
48
49 friend class Trace;
50
57
59 const std::size_t parentEntryOffset;
60
61 std::size_t currentStackSize;
62 std::deque<ExceptionBacktraceTree> children;
63 std::deque<LocationProvider> entries;
64
65 void
66 addEntry(const Trace* t) noexcept
67 {
68 entries.emplace_back(t->location);
70 }
71
72 void print(std::ostream& out, const std::string& prefix = "", std::size_t levelOffset = 0);
73 };
74} // namespace armarx::detail
75
76// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
77// //////////////////////////////////////////////// data /////////////////////////////////////////////// //
78// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
79namespace armarx::detail
80{
81 thread_local const Trace* Trace::Top = nullptr;
82 thread_local std::uintmax_t Trace::Size = 0;
83 thread_local ExceptionBacktraceTree* ExceptionBacktraceTree::Active = nullptr;
84 thread_local std::deque<ExceptionBacktraceTree> ExceptionBacktraceTree::All;
85} // namespace armarx::detail
86
87// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
88// ///////////////////////////////////////////// management //////////////////////////////////////////// //
89// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
90namespace armarx::detail
91{
92 void
98
99 void
104
106 {
107 TerminateIf(Top != this);
108 if (exceptional())
109 {
111 {
112 if (Size > ExceptionBacktraceTree::Active->currentStackSize)
113 {
114 //add subtree
115 ExceptionBacktraceTree::Active->children.emplace_back(
118 &(ExceptionBacktraceTree::Active->children.back());
119 }
121 ? ExceptionBacktraceTree::Active->parent->currentStackSize
122 : 0))
123 {
124 //go to parent tree
126 }
127 }
128 else
129 {
130 //add new root tree
131 ExceptionBacktraceTree::All.emplace_back(nullptr);
133 }
134 //add entry to curent tree
135 ExceptionBacktraceTree::Active->addEntry(this);
138 ? ExceptionBacktraceTree::Active->parent->currentStackSize
139 : 0))
140 {
141 //go to parent tree
143 }
144 }
146 {
147 auto p = ExceptionBacktraceTree::Active->parent;
148 auto& deque = p ? p->children : ExceptionBacktraceTree::All;
150 deque.pop_back();
152 }
153 Top = parent;
154 --Size;
155 }
156} // namespace armarx::detail
157
158// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
159// /////////////////////////////////////////////// output ////////////////////////////////////////////// //
160// ///////////////////////////////////////////////////////////////////////////////////////////////////// //
161namespace armarx::detail
162{
163 std::ostream&
164 operator<<(std::ostream& out, const LocationProvider::Location& l)
165 {
166 return out << l.file << ":" << l.line << " : " << l.func;
167 }
168
169 std::ostream&
170 operator<<(std::ostream& out, const LocationProvider& t)
171 {
172 return out << t.location();
173 }
174
175 std::ostream&
176 operator<<(std::ostream& out, const Trace& t)
177 {
178 return out << t.location;
179 }
180
181 void
182 Trace::PrintStackTrace(std::ostream& out, const std::string& pre)
183 {
184 const Trace* trace = Top;
185
186 const auto numW = Size ? std::log10(Size) + 1 : 1;
187
188 for (std::uintmax_t cnt = 0; trace; ++cnt, trace = trace->parent)
189 {
190 out << pre << std::setw(numW) << cnt << std::setw(0) << ": " << *trace << "\n";
191 }
192 }
193
194 void
195 ExceptionBacktraceTree::PrintExceptionBacktrace(std::ostream& out, const std::string& pre)
196 {
197 const auto numW = ExceptionBacktraceTree::All.size()
198 ? std::log10(ExceptionBacktraceTree::All.size()) + 1
199 : 1;
200 for (std::size_t i = 0; i < ExceptionBacktraceTree::All.size(); ++i)
201 {
202 if (i)
203 {
204 out << "--------------------------" << std::string(numW, '-') << "\n";
205 }
206 if (ExceptionBacktraceTree::All.size() > 1)
207 {
208 out << "Exception Backtrace Tree " << std::setw(numW) << i << std::setw(0) << ":\n";
209 }
210 ExceptionBacktraceTree::All.at(i).print(out, pre);
211 Trace::PrintStackTrace(out, pre + "* ");
212 }
213 }
214
215 void
216 Trace::PrintExceptionBacktrace(std::ostream& out, const std::string& pre)
217 {
219 }
220
221 void
223 const std::string& prefix,
224 std::size_t levelOffset)
225 {
226 TerminateIf(entries.empty());
227 const auto numW = std::log10(entries.size()) + 1;
228
229 std::size_t nextChildParentEntryOffset = std::numeric_limits<std::size_t>::max();
230
231 std::size_t nextChildIndex = 0;
232 auto updateNextChildEntryOffset = [&]
233 {
234 nextChildParentEntryOffset = std::numeric_limits<std::size_t>::max();
235 if (nextChildIndex < children.size())
236 {
237 nextChildParentEntryOffset = children.at(nextChildIndex).parentEntryOffset;
238 }
239 };
240 updateNextChildEntryOffset();
241
242 for (std::size_t entryIdx = 0; entryIdx < entries.size(); ++entryIdx)
243 {
244 const std::size_t level =
245 /*parentEntryOffset +*/ levelOffset + entries.size() - entryIdx;
246 while (entryIdx >= nextChildParentEntryOffset && nextChildIndex < children.size())
247 {
248 children.at(nextChildIndex).print(out, prefix + "| ", level);
249 out << prefix << "|/\n";
250 ++nextChildIndex;
251 updateNextChildEntryOffset();
252 }
253 out << prefix << "* -" << std::setw(numW) << level << std::setw(0) << ": "
254 << entries.at(entryIdx) << "\n";
255 }
256 //print children after this branch
257 for (; nextChildIndex < children.size(); ++nextChildIndex)
258 {
259 children.at(nextChildIndex).print(out, prefix + "| ");
260 out << prefix << "|/\n";
261 }
262 }
263} // namespace armarx::detail
std::ostream & operator<<(std::ostream &strm, const AbstractInterface &a)
static void PrintExceptionBacktrace(std::ostream &out, const std::string &pre)
Definition trace.cpp:195
const std::size_t parentEntryOffset
Definition trace.cpp:59
std::deque< LocationProvider > entries
Definition trace.cpp:63
ExceptionBacktraceTree *const parent
Definition trace.cpp:58
static thread_local ExceptionBacktraceTree * Active
Definition trace.cpp:46
std::deque< ExceptionBacktraceTree > children
Definition trace.cpp:62
void addEntry(const Trace *t) noexcept
Definition trace.cpp:66
static thread_local std::deque< ExceptionBacktraceTree > All
Definition trace.cpp:47
ExceptionBacktraceTree(ExceptionBacktraceTree *parent)
Definition trace.cpp:51
void print(std::ostream &out, const std::string &prefix="", std::size_t levelOffset=0)
Definition trace.cpp:222
const Trace * parent
Definition trace.h:32
Trace(LocationProvider::FncLoc l)
Definition trace.h:59
const LocationProvider location
Definition trace.h:34
bool exceptional() const
Definition trace.h:70
static void PrintExceptionBacktrace(std::ostream &out, const std::string &pre="")
Definition trace.cpp:216
static void ClearExceptionBacktrace()
Definition trace.cpp:100
static void PrintStackTrace(std::ostream &out, const std::string &pre="")
Definition trace.cpp:182
#define TerminateIf(...)
Definition trace.cpp:14