Skip to content

Commit ceb2142

Browse files
committed
Initial work on trace formatting setup
1 parent 9077430 commit ceb2142

File tree

6 files changed

+382
-107
lines changed

6 files changed

+382
-107
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ target_sources(
113113
src/ctrace.cpp
114114
src/exceptions.cpp
115115
src/from_current.cpp
116+
src/formatting.cpp
116117
src/options.cpp
117118
src/utils.cpp
118119
src/demangle/demangle_with_cxxabi.cpp

include/cpptrace/basic.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,6 @@ namespace cpptrace {
182182
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
183183
inline const_iterator cend() const noexcept { return frames.cend(); }
184184
private:
185-
void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
186-
void print_with_snippets(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
187185
friend void print_terminate_trace();
188186
};
189187

include/cpptrace/formatting.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef CPPTRACE_FORMATTING_HPP
2+
#define CPPTRACE_FORMATTING_HPP
3+
4+
#include <cpptrace/basic.hpp>
5+
6+
#include <memory>
7+
#include <string>
8+
#include <functional>
9+
10+
namespace cpptrace {
11+
class CPPTRACE_EXPORT formatter {
12+
class impl;
13+
std::unique_ptr<impl> pimpl;
14+
15+
public:
16+
formatter();
17+
~formatter();
18+
19+
formatter(formatter&&) = default;
20+
formatter(const formatter&);
21+
formatter& operator=(formatter&&) = default;
22+
formatter& operator=(const formatter&);
23+
24+
formatter& set_header(std::string);
25+
enum class color_mode {
26+
always,
27+
none,
28+
automatic,
29+
};
30+
formatter& set_color_mode(color_mode);
31+
enum class address_mode {
32+
raw,
33+
object,
34+
none,
35+
};
36+
formatter& set_address_mode(address_mode);
37+
formatter& set_snippets(bool);
38+
formatter& set_snippet_context(int);
39+
formatter& include_column(bool);
40+
formatter& set_filter(std::function<bool(const stacktrace_frame&)>);
41+
42+
std::string format(const stacktrace_frame&) const;
43+
std::string format(const stacktrace_frame&, bool color) const;
44+
45+
std::string format(const stacktrace&) const;
46+
std::string format(const stacktrace&, bool color) const;
47+
48+
void print(const stacktrace_frame&) const;
49+
void print(const stacktrace_frame&, bool color) const;
50+
void print(std::ostream&, const stacktrace_frame&) const;
51+
void print(std::ostream&, const stacktrace_frame&, bool color) const;
52+
void print(std::FILE*, const stacktrace_frame&) const;
53+
void print(std::FILE*, const stacktrace_frame&, bool color) const;
54+
55+
void print(const stacktrace&) const;
56+
void print(const stacktrace&, bool color) const;
57+
void print(std::ostream&, const stacktrace&) const;
58+
void print(std::ostream&, const stacktrace&, bool color) const;
59+
void print(std::FILE*, const stacktrace&) const;
60+
void print(std::FILE*, const stacktrace&, bool color) const;
61+
};
62+
63+
CPPTRACE_EXPORT const formatter& get_default_formatter();
64+
}
65+
66+
#endif

src/cpptrace.cpp

Lines changed: 17 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <cpptrace/cpptrace.hpp>
2+
#include <cpptrace/formatting.hpp>
23

34
#include <cstddef>
45
#include <cstdint>
@@ -9,6 +10,7 @@
910
#include <string>
1011
#include <vector>
1112

13+
#include "cpptrace/basic.hpp"
1214
#include "symbols/symbols.hpp"
1315
#include "unwind/unwind.hpp"
1416
#include "demangle/demangle.hpp"
@@ -129,41 +131,13 @@ namespace cpptrace {
129131
return detail::get_frame_object_info(raw_address);
130132
}
131133

132-
static std::string frame_to_string(
133-
bool color,
134-
const stacktrace_frame& frame
135-
) {
136-
const auto reset = color ? RESET : "";
137-
const auto green = color ? GREEN : "";
138-
const auto yellow = color ? YELLOW : "";
139-
const auto blue = color ? BLUE : "";
140-
std::string str;
141-
if(frame.is_inline) {
142-
str += microfmt::format("{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)");
143-
} else {
144-
str += microfmt::format("{}0x{>{}:0h}{}", blue, 2 * sizeof(frame_ptr), frame.raw_address, reset);
145-
}
146-
if(!frame.symbol.empty()) {
147-
str += microfmt::format(" in {}{}{}", yellow, frame.symbol, reset);
148-
}
149-
if(!frame.filename.empty()) {
150-
str += microfmt::format(" at {}{}{}", green, frame.filename, reset);
151-
if(frame.line.has_value()) {
152-
str += microfmt::format(":{}{}{}", blue, frame.line.value(), reset);
153-
if(frame.column.has_value()) {
154-
str += microfmt::format(":{}{}{}", blue, frame.column.value(), reset);
155-
}
156-
}
157-
}
158-
return str;
159-
}
160-
161134
std::string stacktrace_frame::to_string() const {
162135
return to_string(false);
163136
}
164137

165138
std::string stacktrace_frame::to_string(bool color) const {
166-
return frame_to_string(color, *this);
139+
// return frame_to_string(color, *this);
140+
return get_default_formatter().format(*this, color);
167141
}
168142

169143
std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) {
@@ -195,89 +169,34 @@ namespace cpptrace {
195169
}
196170

197171
void stacktrace::print() const {
198-
print(std::cerr, true);
172+
get_default_formatter().print(*this);
199173
}
200174

201175
void stacktrace::print(std::ostream& stream) const {
202-
print(stream, true);
176+
get_default_formatter().print(stream, *this);
203177
}
204178

205179
void stacktrace::print(std::ostream& stream, bool color) const {
206-
print(stream, color, true, nullptr);
207-
}
208-
209-
static void print_frame(
210-
std::ostream& stream,
211-
bool color,
212-
unsigned frame_number_width,
213-
std::size_t counter,
214-
const stacktrace_frame& frame
215-
) {
216-
std::string line = microfmt::format("#{<{}} {}", frame_number_width, counter, frame.to_string(color));
217-
stream << line;
180+
get_default_formatter().print(stream, *this, color);
218181
}
219182

220-
void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const {
221-
if(
222-
color && (
223-
(&stream == &std::cout && isatty(stdout_fileno)) || (&stream == &std::cerr && isatty(stderr_fileno))
224-
)
225-
) {
226-
detail::enable_virtual_terminal_processing_if_needed();
227-
}
228-
stream << (header ? header : "Stack trace (most recent call first):") << '\n';
229-
std::size_t counter = 0;
230-
if(frames.empty()) {
231-
stream << "<empty trace>\n";
232-
return;
233-
}
234-
const auto frame_number_width = detail::n_digits(static_cast<int>(frames.size()) - 1);
235-
for(const auto& frame : frames) {
236-
print_frame(stream, color, frame_number_width, counter, frame);
237-
if(newline_at_end || &frame != &frames.back()) {
238-
stream << '\n';
239-
}
240-
counter++;
183+
namespace detail {
184+
const formatter& get_default_snippet_formatter() {
185+
static formatter snippet_formatter = formatter{}.set_snippets(true);
186+
return snippet_formatter;
241187
}
242188
}
243189

244190
void stacktrace::print_with_snippets() const {
245-
print_with_snippets(std::cerr, true);
191+
detail::get_default_snippet_formatter().print(*this);
246192
}
247193

248194
void stacktrace::print_with_snippets(std::ostream& stream) const {
249-
print_with_snippets(stream, true);
195+
detail::get_default_snippet_formatter().print(stream, *this);
250196
}
251197

252198
void stacktrace::print_with_snippets(std::ostream& stream, bool color) const {
253-
print_with_snippets(stream, color, true, nullptr);
254-
}
255-
256-
void stacktrace::print_with_snippets(std::ostream& stream, bool color, bool newline_at_end, const char* header) const {
257-
if(
258-
color && (
259-
(&stream == &std::cout && isatty(stdout_fileno)) || (&stream == &std::cerr && isatty(stderr_fileno))
260-
)
261-
) {
262-
detail::enable_virtual_terminal_processing_if_needed();
263-
}
264-
stream << (header ? header : "Stack trace (most recent call first):") << '\n';
265-
std::size_t counter = 0;
266-
if(frames.empty()) {
267-
stream << "<empty trace>" << '\n';
268-
return;
269-
}
270-
const auto frame_number_width = detail::n_digits(static_cast<int>(frames.size()) - 1);
271-
for(const auto& frame : frames) {
272-
print_frame(stream, color, frame_number_width, counter, frame);
273-
if(newline_at_end || &frame != &frames.back()) {
274-
stream << '\n';
275-
}
276-
if(frame.line.has_value() && !frame.filename.empty()) {
277-
stream << detail::get_snippet(frame.filename, frame.line.value(), 2, color);
278-
}
279-
counter++;
280-
}
199+
detail::get_default_snippet_formatter().print(stream, *this, color);
281200
}
282201

283202
void stacktrace::clear() {
@@ -289,13 +208,12 @@ namespace cpptrace {
289208
}
290209

291210
std::string stacktrace::to_string(bool color) const {
292-
std::ostringstream oss;
293-
print(oss, color, false, nullptr);
294-
return std::move(oss).str();
211+
return get_default_formatter().format(*this, color);
295212
}
296213

297214
std::ostream& operator<<(std::ostream& stream, const stacktrace& trace) {
298-
return stream << trace.to_string();
215+
get_default_formatter().print(stream, trace);
216+
return stream;
299217
}
300218

301219
CPPTRACE_FORCE_NO_INLINE

0 commit comments

Comments
 (0)