Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
debug.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef JAU_DEBUG_HPP_
27#define JAU_DEBUG_HPP_
28
29#include <cstdlib>
30
31#include <cstdint>
32#include <cstring>
33#include <string>
34#include <cstdio>
35#include <cstdarg>
36#include <string_view>
37
38#include <jau/cpp_lang_util.hpp>
39#include <jau/environment.hpp>
40
41#include <jau/string_util.hpp>
42#include <jau/string_cfmt.hpp>
43
44// #define PERF_PRINT_ON 1
45
46
47
48namespace jau::impl {
49 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
50 void dbgPrint0_tail(FILE *out, bool addErrno, bool addBacktrace) noexcept;
51 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
52 ssize_t dbgPrint_td_prefix(const uint64_t elapsed_ms, FILE *out) noexcept;
53 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
54 void dbgPrint1_prefix(FILE *out, const char *msg, const char *msgsep) noexcept;
55
56 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
57 template <typename... Args>
58 inline __attribute__((always_inline))
59 void dbgPrint0(FILE *out, bool addErrno, bool addBacktrace, std::string_view format, const Args &...args) noexcept {
60 ::fputs(jau::format_string(format, args...).c_str(), out);
61 jau::impl::dbgPrint0_tail(out, addErrno, addBacktrace);
62 }
63
64 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
65 template <typename... Args>
66 inline __attribute__((always_inline))
67 void dbgPrint1(FILE *out, bool printPrefix, const char *msg, std::string_view format, const Args &...args) noexcept {
68 if (printPrefix) {
69 jau::impl::dbgPrint1_prefix(out, msg, ": ");
70 }
71 jau::impl::dbgPrint0(out, false, false, format, args...);
72 }
73
74 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
75 template <typename... Args>
76 inline __attribute__((always_inline))
77 void dbgPrint2(FILE *out, const char *msg, bool addErrno, bool addBacktrace, const char *func, const char *file, const int line,
78 std::string_view format, const Args &...args) noexcept {
79 jau::impl::dbgPrint1_prefix(out, msg, " ");
80 ::fprintf(stderr, "@ %s:%d %s: ", file, line, func);
81 jau::impl::dbgPrint0(out, addErrno, addBacktrace, format, args...);
82 }
83} // namespace jau::impl
84
85#define jau_dbgPrint1(out, printPrefix, msg, fmt, ...) \
86 jau::impl::dbgPrint1((out), (printPrefix), (msg), (fmt) __VA_OPT__(,) __VA_ARGS__); \
87 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
88
89#define jau_dbgPrint1Line(out, printPrefix, msg, fmt, ...) \
90 jau::impl::dbgPrint1((out), (printPrefix), (msg), (fmt) __VA_OPT__(,) __VA_ARGS__); \
91 static_assert(0 == jau::cfmt::check2Line< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
92
93#define jau_dbgPrint2(out, msg, addErrno, addBacktrace, func, file, line, fmt, ...) \
94 jau::impl::dbgPrint2((out), (msg), (addErrno), (addBacktrace), (func), (file), (line), (fmt) __VA_OPT__(,) __VA_ARGS__); \
95 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
96
97#define jau_dbgPrint2Line(out, msg, addErrno, addBacktrace, func, file, line, fmt, ...) \
98 jau::impl::dbgPrint2((out), (msg), (addErrno), (addBacktrace), (func), (file), (line), (fmt) __VA_OPT__(,) __VA_ARGS__); \
99 static_assert(0 == jau::cfmt::check2Line< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
100
101/** Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] Debug: '. */
102#define jau_DBG_PRINT(fmt, ...) { if( jau::environment::get().debug ) { jau_dbgPrint1(stderr, true, "Debug", fmt __VA_OPT__(,) __VA_ARGS__); } }
103#define jau_DBG_PRINT_LINE(fmt, ...) { if( jau::environment::get().debug ) { jau_dbgPrint1Line(stderr, true, "Debug", fmt __VA_OPT__(,) __VA_ARGS__); } }
104
105/** Use for environment-variable environment::DEBUG_JNI conditional debug messages, prefix '[elapsed_time] Debug: '. */
106#define jau_DBG_JNI_PRINT(...) { if( jau::environment::get().debug_jni ) { jau_dbgPrint1(stderr, true, "Debug", __VA_ARGS__); } }
107
108/** Use for environment-variable environment::DEBUG conditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: ' */
109#define jau_DBG_WARN_PRINT(...) { if( jau::environment::get().debug ) { jau_dbgPrint2(stderr, "Warning", false /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } } // NOLINT(bugprone-lambda-function-name)
110
111/** Use for environment-variable environment::DEBUG conditional error messages, prefix '[elapsed_time] Debug @ FILE:LINE FUNC: '. Function also appends last errno, strerror(errno) and full backtrace*/
112#define jau_DBG_ERR_PRINT(...) { if( jau::environment::get().debug ) { jau_dbgPrint2(stderr, "Debug", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } } // NOLINT(bugprone-lambda-function-name)
113
114/**
115 * Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time] Wordy: '.
116 * <p>
117 * 'Wordy' is the shorter English form of the Latin word 'verbosus', from which the word 'verbosity' is sourced.
118 * </p>
119 */
120#define jau_WORDY_PRINT(...) { if( jau::environment::get().verbose ) { jau_dbgPrint1(stderr, true, "Wordy", __VA_ARGS__); } }
121
122#define jau_PERF_TS_T0_BASE() const uint64_t _t0 = jau::getCurrentMilliseconds()
123
124#define jau_PERF_TS_TD_BASE(m) { const uint64_t _td = jau::getCurrentMilliseconds() - _t0; \
125 fprintf(stderr, "[%s] PERF %s done in %d ms,\n", jau::to_decstring(jau::environment::getElapsedMillisecond(), ',', 9).c_str(), (m), (int)_td); }
126#ifdef PERF_PRINT_ON
127 #define jau_PERF_TS_T0() jau_PERF_TS_T0_BASE()
128 #define jau_PERF_TS_TD(m) jau_PERF_TS_TD_BASE(m)
129#else
130 #define jau_PERF_TS_T0()
131 #define jau_PERF_TS_TD(m)
132#endif
133#ifdef PERF2_PRINT_ON
134 #define jau_PERF2_TS_T0() jau_PERF_TS_T0_BASE()
135 #define jau_PERF2_TS_TD(m) jau_PERF_TS_TD_BASE(m)
136#else
137 #define jau_PERF2_TS_T0()
138 #define jau_PERF2_TS_TD(m)
139#endif
140#ifdef PERF3_PRINT_ON
141 #define jau_PERF3_TS_T0() jau_PERF_TS_T0_BASE()
142 #define jau_PERF3_TS_TD(m) jau_PERF_TS_TD_BASE(m)
143#else
144 #define jau_PERF3_TS_T0()
145 #define jau_PERF3_TS_TD(m)
146#endif
147
148/** Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line func: '. Function also appends last errno and strerror(errno). */
149#define jau_ABORT(...) { jau_dbgPrint2(stderr, "ABORT", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); abort(); } // NOLINT(bugprone-lambda-function-name)
150
151/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno, strerror(errno) and full backtrace*/
152#define jau_ERR_PRINT(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
153
154/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). No backtrace. */
155#define jau_ERR_PRINT2(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
156
157/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). Full backtrace. */
158#define jau_ERR_PRINT3(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
159
160/** Use for unconditional interruption messages, prefix '[elapsed_time] Interrupted @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). */
161#define jau_IRQ_PRINT(...) { jau_dbgPrint2(stderr, "Interrupted", true /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
162
163/** Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: ' */
164#define jau_WARN_PRINT(...) { jau_dbgPrint2(stderr, "Warning", false /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
165
166/** Use for unconditional informal messages, prefix '[elapsed_time] Info: '. */
167#define jau_INFO_PRINT(fmt, ...) { jau_dbgPrint1(stderr, true, "Info", fmt __VA_OPT__(,) __VA_ARGS__); }
168#define jau_INFO_PRINT_LINE(fmt, ...) { jau_dbgPrint1Line(stderr, true, "Info", fmt __VA_OPT__(,) __VA_ARGS__); }
169
170/** Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true. */
171#define jau_PLAIN_PRINT(printPrefix, fmt, ...) { jau_dbgPrint1(stderr, (printPrefix), nullptr, fmt __VA_OPT__(,) __VA_ARGS__); }
172
173/** Use for conditional plain messages, prefix '[elapsed_time] '. */
174#define jau_COND_PRINT(C, ...) { if( C ) { jau::impl::dbgPrint0(stderr, false, false, __VA_ARGS__); } }
175
176namespace jau {
177 /**
178 * Convenient secure fprintf() invocation, prepending the given elapsed_ms timestamp
179 * and using `jau:format_string`.
180 * @param elapsed_ms the given elapsed time in milliseconds
181 * @param stream the output stream
182 * @param format the format
183 * @param args the optional arguments
184 * @return number of bytes printed if successful, otherwise negative
185 */
186 template <typename... Args>
187 inline __attribute__((always_inline))
188 ssize_t fprintf_td(const uint64_t elapsed_ms, FILE* stream, std::string_view format, const Args &...args) noexcept {
189 ssize_t res = jau::impl::dbgPrint_td_prefix(elapsed_ms, stream);
190 if (0>res) {
191 return res;
192 }
193 const std::string s = jau::format_string(format, args...);
194 const int r = ::fputs(s.c_str(), stream);
195 res += jau::clampCast<ssize_t, size_t>(s.length(), 0, std::numeric_limits<ssize_t>::max()-res);
196 return 0>r ? -1*res : res;
197 }
198
199 /**
200 * Convenient secure fprintf() invocation, prepending the environment::getElapsedMillisecond() timestamp,
201 * and using `jau:format_string`.
202 * @param stream the output stream
203 * @param format the format
204 * @param args the optional arguments
205 * @return number of bytes printed if successful, otherwise negative
206 */
207 template <typename... Args>
208 inline __attribute__((always_inline))
209 ssize_t fprintf_td(FILE* stream, std::string_view format, const Args &...args) noexcept {
210 return fprintf_td(environment::getElapsedMillisecond(), stream, format, args...);
211 }
212
213 /**
214 * Convenient secure fprintf() invocation using `jau:format_string`.
215 * @param stream the output stream
216 * @param format the format
217 * @param args the optional arguments
218 * @return number of bytes printed if successful, otherwise negative
219 */
220 template <typename... Args>
221 inline __attribute__((always_inline))
222 ssize_t fprintf_sc(FILE* stream, std::string_view format, const Args &...args) noexcept {
223 const std::string s = jau::format_string(format, args...);
224 const int r = ::fputs(s.c_str(), stream);
225 const ssize_t res = jau::clampCast<ssize_t, size_t>(s.length(), 0, std::numeric_limits<ssize_t>::max());
226 return 0>r ? -1*res : res;
227 }
228
229 template<class List>
230 void printSharedPtrList(const std::string& prefix, List & list) noexcept {
231 ::fprintf(stderr, "%s: Start: %zu elements\n", prefix.c_str(), (size_t)list.size());
232 int idx = 0;
233 for (auto it = list.begin(); it != list.end(); idx++) {
234 typename List::value_type & e = *it;
235 if ( nullptr != e ) {
236 ::fprintf(stderr, "%s[%d]: useCount %zu, mem %p\n", prefix.c_str(), idx, (size_t)e.use_count(), e.get());
237 } else {
238 ::fprintf(stderr, "%s[%d]: NULL\n", prefix.c_str(), idx);
239 }
240 ++it;
241 }
242 }
243} // namespace jau
244
245#define jau_fprintf_td2(elapsed_ms, stream, fmt, ...) \
246 jau::fprintf_td((elapsed_ms), (stream), (fmt) __VA_OPT__(,) __VA_ARGS__); \
247 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
248
249#define jau_fprintf_td(stream, fmt, ...) \
250 jau::fprintf_td((stream), (fmt) __VA_OPT__(,) __VA_ARGS__); \
251 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
252
253#define jau_printf(fmt, ...) \
254 jau::fprintf_sc((stdout), (fmt) __VA_OPT__(,) __VA_ARGS__); \
255 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
256
257#define jau_fprintf(stream, fmt, ...) \
258 jau::fprintf_sc((stream), (fmt) __VA_OPT__(,) __VA_ARGS__); \
259 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
260
261
262#endif /* JAU_DEBUG_HPP_ */
static uint64_t getElapsedMillisecond() noexcept
Returns current elapsed monotonic time in milliseconds since module startup, see startupTimeMilliseco...
constexpr R clampCast(const T x, const T min_val, const T max_val) noexcept
Returns constrained integral value to lie between given min- and maximum value (w/ branching) in O(1)...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
ssize_t fprintf_sc(FILE *stream, std::string_view format, const Args &...args) noexcept
Convenient secure fprintf() invocation using jau:format_string.
Definition debug.hpp:222
std::string format_string(std::string_view fmt, const Args &...args) noexcept
Safely returns a (non-truncated) string according to snprintf() formatting rules using a reserved str...
ssize_t fprintf_td(const uint64_t elapsed_ms, FILE *stream, std::string_view format, const Args &...args) noexcept
Convenient secure fprintf() invocation, prepending the given elapsed_ms timestamp and using jau:forma...
Definition debug.hpp:188
void printSharedPtrList(const std::string &prefix, List &list) noexcept
Definition debug.hpp:230
STL namespace.