jaulib v1.5.0
Jau Support Library (C++, Java, ..)
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 void dbgPrint1_prefix(FILE *out, const char *msg, const char *msgsep) noexcept;
53
54 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
55 template <typename... Args>
56 inline __attribute__((always_inline))
57 void dbgPrint0(FILE *out, bool addErrno, bool addBacktrace, std::string_view format, const Args &...args) noexcept {
58 ::fputs(jau::format_string(format, args...).c_str(), out);
59 jau::impl::dbgPrint0_tail(out, addErrno, addBacktrace);
60 }
61
62 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
63 template <typename... Args>
64 inline __attribute__((always_inline))
65 void dbgPrint1(FILE *out, bool printPrefix, const char *msg, std::string_view format, const Args &...args) noexcept {
66 if (printPrefix) {
67 jau::impl::dbgPrint1_prefix(out, msg, ": ");
68 }
69 jau::impl::dbgPrint0(out, false, false, format, args...);
70 }
71
72 /// This function is a possible cancellation point and therefore marked with noexcept (not marked with __THROW like ::fprintf).
73 template <typename... Args>
74 inline __attribute__((always_inline))
75 void dbgPrint2(FILE *out, const char *msg, bool addErrno, bool addBacktrace, const char *func, const char *file, const int line,
76 std::string_view format, const Args &...args) noexcept {
77 jau::impl::dbgPrint1_prefix(out, msg, " ");
78 ::fprintf(stderr, "@ %s:%d %s: ", file, line, func);
79 jau::impl::dbgPrint0(out, addErrno, addBacktrace, format, args...);
80 }
81} // namespace jau::impl
82
83#define jau_dbgPrint1(out, printPrefix, msg, fmt, ...) \
84 jau::impl::dbgPrint1((out), (printPrefix), (msg), (fmt) __VA_OPT__(,) __VA_ARGS__); \
85 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
86
87#define jau_dbgPrint1Line(out, printPrefix, msg, fmt, ...) \
88 jau::impl::dbgPrint1((out), (printPrefix), (msg), (fmt) __VA_OPT__(,) __VA_ARGS__); \
89 static_assert(0 == jau::cfmt::check2Line< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
90
91#define jau_dbgPrint2(out, msg, addErrno, addBacktrace, func, file, line, fmt, ...) \
92 jau::impl::dbgPrint2((out), (msg), (addErrno), (addBacktrace), (func), (file), (line), (fmt) __VA_OPT__(,) __VA_ARGS__); \
93 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
94
95#define jau_dbgPrint2Line(out, msg, addErrno, addBacktrace, func, file, line, fmt, ...) \
96 jau::impl::dbgPrint2((out), (msg), (addErrno), (addBacktrace), (func), (file), (line), (fmt) __VA_OPT__(,) __VA_ARGS__); \
97 static_assert(0 == jau::cfmt::check2Line< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
98
99/** Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] Debug: '. */
100#define jau_DBG_PRINT(fmt, ...) { if( jau::environment::get().debug ) { jau_dbgPrint1(stderr, true, "Debug", fmt __VA_OPT__(,) __VA_ARGS__); } }
101#define jau_DBG_PRINT_LINE(fmt, ...) { if( jau::environment::get().debug ) { jau_dbgPrint1Line(stderr, true, "Debug", fmt __VA_OPT__(,) __VA_ARGS__); } }
102
103/** Use for environment-variable environment::DEBUG_JNI conditional debug messages, prefix '[elapsed_time] Debug: '. */
104#define jau_DBG_JNI_PRINT(...) { if( jau::environment::get().debug_jni ) { jau_dbgPrint1(stderr, true, "Debug", __VA_ARGS__); } }
105
106/** Use for environment-variable environment::DEBUG conditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: ' */
107#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)
108
109/** 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*/
110#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)
111
112/**
113 * Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time] Wordy: '.
114 * <p>
115 * 'Wordy' is the shorter English form of the Latin word 'verbosus', from which the word 'verbosity' is sourced.
116 * </p>
117 */
118#define jau_WORDY_PRINT(...) { if( jau::environment::get().verbose ) { jau_dbgPrint1(stderr, true, "Wordy", __VA_ARGS__); } }
119
120#define jau_PERF_TS_T0_BASE() const uint64_t _t0 = jau::getCurrentMilliseconds()
121
122#define jau_PERF_TS_TD_BASE(m) { const uint64_t _td = jau::getCurrentMilliseconds() - _t0; \
123 fprintf(stderr, "[%s] PERF %s done in %d ms,\n", jau::to_decstring(jau::environment::getElapsedMillisecond(), ',', 9).c_str(), (m), (int)_td); }
124#ifdef PERF_PRINT_ON
125 #define jau_PERF_TS_T0() jau_PERF_TS_T0_BASE()
126 #define jau_PERF_TS_TD(m) jau_PERF_TS_TD_BASE(m)
127#else
128 #define jau_PERF_TS_T0()
129 #define jau_PERF_TS_TD(m)
130#endif
131#ifdef PERF2_PRINT_ON
132 #define jau_PERF2_TS_T0() jau_PERF_TS_T0_BASE()
133 #define jau_PERF2_TS_TD(m) jau_PERF_TS_TD_BASE(m)
134#else
135 #define jau_PERF2_TS_T0()
136 #define jau_PERF2_TS_TD(m)
137#endif
138#ifdef PERF3_PRINT_ON
139 #define jau_PERF3_TS_T0() jau_PERF_TS_T0_BASE()
140 #define jau_PERF3_TS_TD(m) jau_PERF_TS_TD_BASE(m)
141#else
142 #define jau_PERF3_TS_T0()
143 #define jau_PERF3_TS_TD(m)
144#endif
145
146/** Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line func: '. Function also appends last errno and strerror(errno). */
147#define jau_ABORT(...) { jau_dbgPrint2(stderr, "ABORT", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); abort(); } // NOLINT(bugprone-lambda-function-name)
148
149/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno, strerror(errno) and full backtrace*/
150#define jau_ERR_PRINT(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
151
152/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). No backtrace. */
153#define jau_ERR_PRINT2(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
154
155/** Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). Full backtrace. */
156#define jau_ERR_PRINT3(...) { jau_dbgPrint2(stderr, "Error", true /* errno */, true /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
157
158/** Use for unconditional interruption messages, prefix '[elapsed_time] Interrupted @ FILE:LINE FUNC: '. Function also appends last errno and strerror(errno). */
159#define jau_IRQ_PRINT(...) { jau_dbgPrint2(stderr, "Interrupted", true /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
160
161/** Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE FUNC: ' */
162#define jau_WARN_PRINT(...) { jau_dbgPrint2(stderr, "Warning", false /* errno */, false /* backtrace */, __func__, __FILE__, __LINE__, __VA_ARGS__); } // NOLINT(bugprone-lambda-function-name)
163
164/** Use for unconditional informal messages, prefix '[elapsed_time] Info: '. */
165#define jau_INFO_PRINT(fmt, ...) { jau_dbgPrint1(stderr, true, "Info", fmt __VA_OPT__(,) __VA_ARGS__); }
166#define jau_INFO_PRINT_LINE(fmt, ...) { jau_dbgPrint1Line(stderr, true, "Info", fmt __VA_OPT__(,) __VA_ARGS__); }
167
168/** Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true. */
169#define jau_PLAIN_PRINT(printPrefix, fmt, ...) { jau_dbgPrint1(stderr, (printPrefix), nullptr, fmt __VA_OPT__(,) __VA_ARGS__); }
170
171/** Use for conditional plain messages, prefix '[elapsed_time] '. */
172#define jau_COND_PRINT(C, ...) { if( C ) { jau::impl::dbgPrint0(stderr, false, false, __VA_ARGS__); } }
173
174namespace jau {
175 /**
176 * Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
177 * @param elapsed_ms the given elapsed time in milliseconds
178 * @param stream the output stream
179 * @param format the format
180 * @param args the optional arguments
181 */
182 template <typename... Args>
183 inline __attribute__((always_inline))
184 int fprintf_td(const uint64_t elapsed_ms, FILE* stream, std::string_view format, const Args &...args) noexcept {
185 int res = ::fprintf(stream, "[%s] ", jau::to_decstring(elapsed_ms, ',', 9).c_str());
186 const int r = ::fputs(jau::format_string(format, args...).c_str(), stream);
187 if (r >= 0) {
188 res += r;
189 }
190 return res;
191 }
192
193 /**
194 * Convenient fprintf() invocation, prepending the environment::getElapsedMillisecond() timestamp.
195 * @param stream the output stream
196 * @param format the format
197 * @param args the optional arguments
198 */
199 template <typename... Args>
200 inline __attribute__((always_inline))
201 int fprintf_td(FILE* stream, std::string_view format, const Args &...args) noexcept {
202 return fprintf_td(environment::getElapsedMillisecond(), stream, format, args...);
203 }
204
205 template<class List>
206 void printSharedPtrList(const std::string& prefix, List & list) noexcept {
207 ::fprintf(stderr, "%s: Start: %zu elements\n", prefix.c_str(), (size_t)list.size());
208 int idx = 0;
209 for (auto it = list.begin(); it != list.end(); idx++) {
210 typename List::value_type & e = *it;
211 if ( nullptr != e ) {
212 ::fprintf(stderr, "%s[%d]: useCount %zu, mem %p\n", prefix.c_str(), idx, (size_t)e.use_count(), e.get());
213 } else {
214 ::fprintf(stderr, "%s[%d]: NULL\n", prefix.c_str(), idx);
215 }
216 ++it;
217 }
218 }
219} // namespace jau
220
221#define jau_fprintf_td2(elapsed_ms, stream, fmt, ...) \
222 jau::fprintf_td((elapsed_ms), (stream), (fmt) __VA_OPT__(,) __VA_ARGS__); \
223 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
224
225#define jau_fprintf_td(stream, fmt, ...) \
226 jau::fprintf_td((stream), (fmt) __VA_OPT__(,) __VA_ARGS__); \
227 static_assert(0 <= jau::cfmt::check2< JAU_FOR_EACH1_LIST(JAU_NOREF_DECLTYPE_VALUE, __VA_ARGS__) >(fmt)); // compile time validation!
228
229#endif /* JAU_DEBUG_HPP_ */
static uint64_t getElapsedMillisecond() noexcept
Returns current elapsed monotonic time in milliseconds since module startup, see startupTimeMilliseco...
std::string to_decstring(const value_type &v, const char separator='\'', const nsize_t min_width=0) noexcept
Produces a decimal integer string representation of an integral integer value with given radix.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
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...
int fprintf_td(const uint64_t elapsed_ms, FILE *stream, std::string_view format, const Args &...args) noexcept
Convenient fprintf() invocation, prepending the given elapsed_ms timestamp.
Definition debug.hpp:184
void printSharedPtrList(const std::string &prefix, List &list) noexcept
Definition debug.hpp:206
STL namespace.