GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* BSD 3-Clause License |
||
2 |
* |
||
3 |
* Copyright ©2022, Autonomous Systems Lab, ETH Zurich, 4c3y (https://github.com/4c3y) |
||
4 |
* All rights reserved. |
||
5 |
* |
||
6 |
* Redistribution and use in source and binary forms, with or without |
||
7 |
* modification, are permitted provided that the following conditions are met: |
||
8 |
* |
||
9 |
* 1. Redistributions of source code must retain the above copyright notice, this |
||
10 |
* list of conditions and the following disclaimer. |
||
11 |
* |
||
12 |
* 2. Redistributions in binary form must reproduce the above copyright notice, |
||
13 |
* this list of conditions and the following disclaimer in the documentation |
||
14 |
* and/or other materials provided with the distribution. |
||
15 |
* |
||
16 |
* 3. Neither the name of the copyright holder nor the names of its |
||
17 |
* contributors may be used to endorse or promote products derived from |
||
18 |
* this software without specific prior written permission. |
||
19 |
* |
||
20 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
21 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
22 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
23 |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
||
24 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
25 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||
26 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||
27 |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||
28 |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
29 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
30 |
*/ |
||
31 |
|||
32 |
#ifndef LOG__LOG_H_ |
||
33 |
#define LOG__LOG_H_ |
||
34 |
|||
35 |
#include <algorithm> |
||
36 |
#include <utility> |
||
37 |
#include <set> |
||
38 |
#include <sstream> |
||
39 |
#include <unordered_map> |
||
40 |
#include <iostream> |
||
41 |
#include <chrono> |
||
42 |
#include <mutex> |
||
43 |
#include <functional> |
||
44 |
#include <memory> |
||
45 |
|||
46 |
#if !defined MODE_LPP && !defined MODE_GLOG && !defined MODE_ROSLOG && !defined MODE_DEFAULT && !defined MODE_NOLOG |
||
47 |
#define MODE_DEFAULT |
||
48 |
#warning "No mode defined. Selected MODE_DEFAULT"; |
||
49 |
#endif |
||
50 |
|||
51 |
/** |
||
52 |
* @brief Terminates compilation if more than one mode is defined |
||
53 |
* |
||
54 |
* To suppress potentially multiple thousands lines of errors, |
||
55 |
* all modes except MODE_DEFAULT gets undefined in this case. |
||
56 |
* |
||
57 |
* Defining MODE_DEFAULT will prevent errors from being generated for each logging function that is called. |
||
58 |
*/ |
||
59 |
#if defined(MODE_LPP) + defined(MODE_GLOG) + defined(MODE_ROSLOG) + defined(MODE_DEFAULT) + defined(MODE_NOLOG) > 1 |
||
60 |
#undef MODE_LPP |
||
61 |
#undef MODE_GLOG |
||
62 |
#undef MODE_ROSLOG |
||
63 |
#undef MODE_NOLOG |
||
64 |
#define MODE_DEFAULT |
||
65 |
#error "More than one mode is defined" |
||
66 |
#endif |
||
67 |
|||
68 |
//! Check if libraries are available at compile time and include required headers |
||
69 |
#if __has_include(<glog/logging.h>) |
||
70 |
#include <glog/logging.h> |
||
71 |
#define LPP_GLOG_SUPPORTED |
||
72 |
#endif |
||
73 |
|||
74 |
#if __has_include(<ros/console.h>) |
||
75 |
#include <ros/console.h> |
||
76 |
#define LPP_ROSLOG_SUPPORTED |
||
77 |
#endif |
||
78 |
|||
79 |
//! Debug flag, If LPP_DEBUG is enabled, debug output should be printed. |
||
80 |
#ifndef NDEBUG |
||
81 |
#define LPP_DEBUG |
||
82 |
#endif |
||
83 |
|||
84 |
//! Can't use namespaces in macros, used to increase readability |
||
85 |
#define LPP_INTL lpp::internal |
||
86 |
|||
87 |
|||
88 |
#pragma clang diagnostic push |
||
89 |
#pragma ide diagnostic ignored "modernize-concat-nested-namespaces" // Keep compatibility with C++11 |
||
90 |
|||
91 |
namespace lpp { |
||
92 |
namespace internal { |
||
93 |
enum class BaseSeverity { |
||
94 |
DEBUG, |
||
95 |
INFO, |
||
96 |
WARN, |
||
97 |
ERROR, |
||
98 |
FATAL |
||
99 |
}; |
||
100 |
|||
101 |
//! Initialization logic |
||
102 |
class Init { |
||
103 |
public: |
||
104 |
bool lpp_initialized = false; |
||
105 |
bool glog_initialized = false; |
||
106 |
}; |
||
107 |
|||
108 |
class Logging { |
||
109 |
public: |
||
110 |
486 |
inline void call(BaseSeverity severity, const std::string& str) { |
|
111 |
486 |
fn_(severity, str); |
|
112 |
486 |
} |
|
113 |
|||
114 |
67 |
inline void setLoggingFunction(const std::function<void(BaseSeverity, const std::string &)> &fn) { |
|
115 |
67 |
fn_ = fn; |
|
116 |
67 |
} |
|
117 |
|||
118 |
private: |
||
119 |
379 |
std::function<void(BaseSeverity, const std::string &)> fn_ = [](BaseSeverity severity, const std::string &str) { |
|
120 |
✓✓✓✓ ✓✗ |
379 |
switch (severity) { |
121 |
77 |
case BaseSeverity::DEBUG:std::cout << "DEBUG " << str << std::endl; |
|
122 |
77 |
return; |
|
123 |
80 |
case BaseSeverity::INFO:std::cout << "INFO " << str << std::endl; |
|
124 |
80 |
return; |
|
125 |
74 |
case BaseSeverity::WARN:std::cout << "WARN " << str << std::endl; |
|
126 |
74 |
return; |
|
127 |
74 |
case BaseSeverity::ERROR:std::cout << "ERROR " << str << std::endl; |
|
128 |
74 |
return; |
|
129 |
74 |
case BaseSeverity::FATAL:std::cout << "FATAL " << str << std::endl; |
|
130 |
74 |
return; |
|
131 |
} |
||
132 |
}; |
||
133 |
}; |
||
134 |
|||
135 |
inline static Logging logging; |
||
136 |
inline static Init lppInit; |
||
137 |
} |
||
138 |
} |
||
139 |
|||
140 |
//! assert if mode is supported by the libraries available |
||
141 |
#if defined MODE_GLOG && !defined LPP_GLOG_SUPPORTED |
||
142 |
#error Logging Mode is set to glog but glog was not found |
||
143 |
#endif |
||
144 |
|||
145 |
#if defined MODE_ROSLOG && !defined LPP_ROSLOG_SUPPORTED |
||
146 |
#error Logging Mode is set to roslog but roslog was not found |
||
147 |
#endif |
||
148 |
|||
149 |
|||
150 |
//! Un-define glog`s LOG macro to avoid conflicts |
||
151 |
#ifdef LPP_GLOG_SUPPORTED |
||
152 |
#undef LOG |
||
153 |
#endif |
||
154 |
|||
155 |
|||
156 |
//! Un-define log methods for redefinition |
||
157 |
#if defined LPP_GLOG_SUPPORTED && !defined MODE_GLOG && !defined MODE_DEFAULT |
||
158 |
#undef LOG_IF |
||
159 |
#undef LOG_EVERY_N |
||
160 |
#undef LOG_FIRST_N |
||
161 |
#undef LOG_IF_EVERY_N |
||
162 |
#undef VLOG |
||
163 |
#undef VLOG_EVERY_N |
||
164 |
#undef VLOG_IF |
||
165 |
#undef VLOG_IF_EVERY_N |
||
166 |
#undef DLOG |
||
167 |
#undef DLOG_EVERY_N |
||
168 |
#undef DLOG_IF_EVERY_N |
||
169 |
#undef LOG_STRING |
||
170 |
#endif |
||
171 |
|||
172 |
#if defined LPP_ROSLOG_SUPPORTED && !defined MODE_ROSLOG && !defined MODE_DEFAULT |
||
173 |
#undef ROS_DEBUG |
||
174 |
#undef ROS_DEBUG_STREAM |
||
175 |
#undef ROS_INFO |
||
176 |
#undef ROS_INFO_STREAM |
||
177 |
#undef ROS_WARN |
||
178 |
#undef ROS_WARN_STREAM |
||
179 |
#undef ROS_ERROR |
||
180 |
#undef ROS_ERROR_STREAM |
||
181 |
#undef ROS_FATAL |
||
182 |
#undef ROS_FATAL_STREAM |
||
183 |
|||
184 |
#undef ROS_DEBUG_COND |
||
185 |
#undef ROS_DEBUG_STREAM_COND |
||
186 |
#undef ROS_INFO_COND |
||
187 |
#undef ROS_INFO_STREAM_COND |
||
188 |
#undef ROS_WARN_COND |
||
189 |
#undef ROS_WARN_STREAM_COND |
||
190 |
#undef ROS_ERROR_COND |
||
191 |
#undef ROS_ERROR_STREAM_COND |
||
192 |
#undef ROS_FATAL_COND |
||
193 |
#undef ROS_FATAL_STREAM_COND |
||
194 |
|||
195 |
#undef ROS_DEBUG_ONCE |
||
196 |
#undef ROS_INFO_ONCE |
||
197 |
#undef ROS_WARN_ONCE |
||
198 |
#undef ROS_ERROR_ONCE |
||
199 |
#undef ROS_FATAL_ONCE |
||
200 |
|||
201 |
#undef ROS_DEBUG_THROTTLE |
||
202 |
#undef ROS_DEBUG_STREAM_THROTTLE |
||
203 |
#undef ROS_INFO_THROTTLE |
||
204 |
#undef ROS_INFO_STREAM_THROTTLE |
||
205 |
#undef ROS_WARN_THROTTLE |
||
206 |
#undef ROS_WARN_STREAM_THROTTLE |
||
207 |
#undef ROS_ERROR_THROTTLE |
||
208 |
#undef ROS_ERROR_STREAM_THROTTLE |
||
209 |
#undef ROS_FATAL_THROTTLE |
||
210 |
#undef ROS_FATAL_STREAM_THROTTLE |
||
211 |
#endif |
||
212 |
|||
213 |
using namespace lpp::internal; |
||
214 |
|||
215 |
/** |
||
216 |
* Used to initialize Log++ |
||
217 |
* |
||
218 |
* If called more than once, all further calls will be ignored. |
||
219 |
* @param argv is used if MODE_GLOG is defined, otherwise unused. |
||
220 |
* @param callback is used if MODE_LPP is defined, otherwise unused. |
||
221 |
*/ |
||
222 |
551 |
inline void LOG_INIT([[maybe_unused]] char *argv, [[maybe_unused]] const std::function<void(BaseSeverity, const std::string&)>& callback = nullptr) { |
|
223 |
// If LOG_INIT is called more than once, do nothing. |
||
224 |
✓✓✗✓ |
551 |
if (!lppInit.glog_initialized || !lppInit.lpp_initialized) { |
225 |
|||
226 |
#if defined MODE_LPP |
||
227 |
✓✓ | 161 |
if (callback != nullptr) { |
228 |
67 |
logging.setLoggingFunction(callback); |
|
229 |
} |
||
230 |
#endif |
||
231 |
|||
232 |
#if defined LPP_DEBUG && (defined MODE_ROSLOG || defined MODE_DEFAULT) |
||
233 |
✓✗✓✗ ✓✗ |
108 |
if (ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug)) { |
234 |
108 |
ros::console::notifyLoggerLevelsChanged(); |
|
235 |
} |
||
236 |
#endif |
||
237 |
|||
238 |
#if defined MODE_GLOG || defined MODE_DEFAULT |
||
239 |
#ifdef LPP_GLOG_SUPPORTED |
||
240 |
2 |
google::InitGoogleLogging(argv); |
|
241 |
2 |
FLAGS_logtostderr = true; |
|
242 |
2 |
lppInit.glog_initialized = true; |
|
243 |
#endif |
||
244 |
#endif |
||
245 |
367 |
lppInit.lpp_initialized = true; |
|
246 |
} |
||
247 |
551 |
} |
|
248 |
|||
249 |
#define LPP_ASSERT_LPP(x) static_assert((x) == LPP_INTL::LppSeverity::D || (x) == LPP_INTL::LppSeverity::I || (x) == LPP_INTL::LppSeverity::W || (x) == LPP_INTL::LppSeverity::E || (x) == LPP_INTL::LppSeverity::F, "Unknown severity level") |
||
250 |
#define LPP_ASSERT_GLOG(x) static_assert((x) == LPP_INTL::GlogSeverity::INFO || (x) == LPP_INTL::GlogSeverity::WARNING || (x) == LPP_INTL::GlogSeverity::ERROR || (x) == LPP_INTL::GlogSeverity::FATAL, "Unknown severity level") |
||
251 |
|||
252 |
//! Hack to enable macro overloading. Used to overload glog's LOG() macro. |
||
253 |
#define LPP_CAT(A, B) A ## B |
||
254 |
#define LPP_SELECT(NAME, NUM) LPP_CAT( NAME ## _, NUM ) |
||
255 |
|||
256 |
#define LPP_GET_COUNT(_1, _2, _3, _4, _5, _6, COUNT, ...) COUNT |
||
257 |
#define LPP_VA_SIZE(...) LPP_GET_COUNT( __VA_ARGS__, 6, 5, 4, 3, 2, 1 ) |
||
258 |
#define LPP_VA_SELECT(NAME, ...) LPP_SELECT( NAME, LPP_VA_SIZE(__VA_ARGS__) )(__VA_ARGS__) |
||
259 |
|||
260 |
//! Helper macros to generate warnings |
||
261 |
#define LPP_PRAGMA(x) _Pragma (#x) |
||
262 |
#define LPP_WARN(x) LPP_PRAGMA(message (#x)) |
||
263 |
|||
264 |
//! Overloads |
||
265 |
#pragma clang diagnostic push |
||
266 |
#pragma ide diagnostic ignored "OCUnusedMacroInspection" |
||
267 |
#define LOG(...) LPP_VA_SELECT( LOG, __VA_ARGS__ ) |
||
268 |
#pragma clang diagnostic pop |
||
269 |
|||
270 |
/** |
||
271 |
* LOG_1 = Google logging syntax |
||
272 |
* LOG_2 = LPP logging syntax |
||
273 |
* LOG_3 = LPP conditional syntax |
||
274 |
*/ |
||
275 |
|||
276 |
//! MODE_GLOG |
||
277 |
#if defined MODE_GLOG || defined MODE_DEFAULT |
||
278 |
#define LOG_1(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() |
||
279 |
|||
280 |
#ifndef LOG_EVERY_T |
||
281 |
#define LPP_INTL_LOG_EVERY_T(severity, t) LPP_WARN("LOG_EVERY_T is only defined in GLOG v0.6 or newer. File name and line numbers will be invalid in the log output.") \ |
||
282 |
LPP_INTL::InternalPolicyLog<float>(LPP_GET_KEY(), t, toBase(severity), LPP_INTL::PolicyType::TIMED) |
||
283 |
|||
284 |
#define LOG_EVERY_T(severity, t) LPP_WARN("LOG_EVERY_T is only defined in GLOG v0.6 or newer.") \ |
||
285 |
LPP_INTL::InternalPolicyLog<float>(LPP_GET_KEY(), t, toBase(LPP_INTL::GlogSeverity::severity), LPP_INTL::PolicyType::TIMED) |
||
286 |
#endif |
||
287 |
|||
288 |
#define LPP_INTL_DLOG_EVERY_T(severity, t) LPP_WARN("File name and line numbers will be invalid in the log output.") LOG_EVERY_T(severity, t) |
||
289 |
|||
290 |
#ifndef DLOG_EVERY_T |
||
291 |
#define DLOG_EVERY_T(severity, t) LPP_WARN("DLOG_EVERY_T is a Log++ extension") \ |
||
292 |
LPP_INTL::LppGlogExtensionLog(LPP_GET_KEY(), t, LPP_INTL::GlogSeverity::severity, LPP_INTL::PolicyType::TIMED, [](const std::string& str) {LOG_1(severity) << str;}) |
||
293 |
#endif |
||
294 |
|||
295 |
#ifndef DLOG_FIRST_N |
||
296 |
#define DLOG_FIRST_N(severity, n) LPP_WARN("DLOG_FIRST_N is a Log++ extension") \ |
||
297 |
LPP_INTL::LppGlogExtensionLog(LPP_GET_KEY(), n, LPP_INTL::GlogSeverity::severity, LPP_INTL::PolicyType::FIRST_N, [](const std::string& str) {LOG_1(severity) << str;}) |
||
298 |
#endif |
||
299 |
#endif |
||
300 |
|||
301 |
#ifdef MODE_GLOG |
||
302 |
#pragma clang diagnostic push |
||
303 |
#pragma ide diagnostic ignored "bugprone-macro-parentheses" |
||
304 |
|||
305 |
#define LOG_2(severity, x) LPP_ASSERT_LPP(LPP_INTL::LppSeverity::severity); do {\ |
||
306 |
if constexpr (LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::I || LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::D) {LOG_1(INFO) << x;} \ |
||
307 |
else if constexpr (LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::W) {LOG_1(WARNING) << x;} \ |
||
308 |
else if constexpr (LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::E) {LOG_1(ERROR) << x;} \ |
||
309 |
else if constexpr (LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::F) {LOG_1(FATAL) << x;} \ |
||
310 |
} while(0) |
||
311 |
|||
312 |
//Add true at the end to make semicolons mandatory. Compiles to nothing. |
||
313 |
#define LOG_3(severity, cond, x) if (cond) { LOG_2(severity, x);} true |
||
314 |
#define LOG_EVERY(severity, n, x) LPP_ASSERT_LPP(LPP_INTL::LppSeverity::severity); do {\ |
||
315 |
if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::I) {LOG_EVERY_N(INFO, n) << x;} \ |
||
316 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::W) {LOG_EVERY_N(WARNING, n) << x;} \ |
||
317 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::E) {LOG_EVERY_N(ERROR, n) << x;} \ |
||
318 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::F) {LOG_EVERY_N(FATAL, n) << x;} \ |
||
319 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::D) {DLOG_EVERY_N(INFO, n) << x;} \ |
||
320 |
} while(0) |
||
321 |
|||
322 |
#define LOG_FIRST(severity, n, x) LPP_ASSERT_LPP(LPP_INTL::LppSeverity::severity); do {\ |
||
323 |
if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::I || LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::D) {LOG_FIRST_N(INFO, n) << x;} \ |
||
324 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::W) {LOG_FIRST_N(WARNING, n) << x;} \ |
||
325 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::E) {LOG_FIRST_N(ERROR, n) << x;} \ |
||
326 |
else if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::F) {LOG_FIRST_N(FATAL, n) << x;} \ |
||
327 |
} while(0) |
||
328 |
|||
329 |
#define LOG_TIMED(severity, t, x) do { \ |
||
330 |
if constexpr(LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::I \ |
||
331 |
|| LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::W \ |
||
332 |
|| LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::E \ |
||
333 |
|| LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::F \ |
||
334 |
|| LPP_INTL::LppSeverity::severity == LPP_INTL::LppSeverity::D \ |
||
335 |
){LPP_INTL_LOG_EVERY_T(LppSeverity::severity, t) << x;} \ |
||
336 |
} while(0) |
||
337 |
|||
338 |
#ifndef MODE_DEFAULT |
||
339 |
#define ROS_DEBUG(...) DLOG(INFO) << LPP_INTL::formatToString(__VA_ARGS__) |
||
340 |
#define ROS_DEBUG_STREAM(x) DLOG(INFO) << x |
||
341 |
#define ROS_INFO(...) LOG(INFO) << LPP_INTL::formatToString(__VA_ARGS__) |
||
342 |
#define ROS_INFO_STREAM(x) LOG(INFO) << x |
||
343 |
#define ROS_WARN(...) LOG(WARNING) << LPP_INTL::formatToString(__VA_ARGS__) |
||
344 |
#define ROS_WARN_STREAM(x) LOG(WARNING) << x |
||
345 |
#define ROS_ERROR(...) LOG(ERROR) << LPP_INTL::formatToString(__VA_ARGS__) |
||
346 |
#define ROS_ERROR_STREAM(x) LOG(ERROR) << x |
||
347 |
#define ROS_FATAL(...) LOG(FATAL) << LPP_INTL::formatToString(__VA_ARGS__) |
||
348 |
#define ROS_FATAL_STREAM(x) LOG(FATAL) << x |
||
349 |
|||
350 |
#define ROS_DEBUG_COND(cond, x) DLOG_IF(INFO, cond) << x |
||
351 |
#define ROS_DEBUG_STREAM_COND DLOG_IF(INFO, cond) << x; |
||
352 |
#define ROS_INFO_COND(cond, x) LOG_IF(INFO, cond) << x |
||
353 |
#define ROS_INFO_STREAM_COND(cond, x) LOG_IF(INFO, cond) << x |
||
354 |
#define ROS_WARN_COND(cond, x) LOG_IF(WARNING, cond) << x |
||
355 |
#define ROS_WARN_STREAM_COND(cond, x) LOG_IF(WARNING, cond) << x |
||
356 |
#define ROS_ERROR_COND(cond, x) LOG_IF(ERROR, cond) << x |
||
357 |
#define ROS_ERROR_STREAM_COND(cond, x) LOG_IF(ERROR, cond) << x |
||
358 |
#define ROS_FATAL_COND(cond, x) LOG_IF(ERROR, cond) << x |
||
359 |
#define ROS_FATAL_STREAM_COND(cond, x) LOG_IF(ERROR, cond) << x |
||
360 |
|||
361 |
#define ROS_DEBUG_ONCE(...) LOG_FIRST_N(INFO, 1) << LPP_INTL::formatToString(__VA_ARGS__) |
||
362 |
#define ROS_INFO_ONCE(...) LOG_FIRST_N(INFO, 1) << LPP_INTL::formatToString(__VA_ARGS__) |
||
363 |
#define ROS_WARN_ONCE(...) LOG_FIRST_N(WARNING, 1) << LPP_INTL::formatToString(__VA_ARGS__) |
||
364 |
#define ROS_ERROR_ONCE(...) LOG_FIRST_N(ERROR, 1) << LPP_INTL::formatToString(__VA_ARGS__) |
||
365 |
#define ROS_FATAL_ONCE(...) LOG_FIRST_N(FATAL, 1) << LPP_INTL::formatToString(__VA_ARGS__) |
||
366 |
|||
367 |
#define ROS_DEBUG_THROTTLE(n, ...) LPP_INTL_DLOG_EVERY_T(INFO, n) << LPP_INTL::formatToString(__VA_ARGS__); |
||
368 |
#define ROS_DEBUG_STREAM_THROTTLE(n, x) LPP_INTL_DLOG_EVERY_T(INFO, n) << x |
||
369 |
#define ROS_INFO_THROTTLE(n, ...) LPP_INTL_LOG_EVERY_T(LppSeverity::I, n) << LPP_INTL::formatToString(__VA_ARGS__); |
||
370 |
#define ROS_INFO_STREAM_THROTTLE(n, x) LPP_INTL_LOG_EVERY_T(LppSeverity::I, n) << x |
||
371 |
#define ROS_WARN_THROTTLE(n, ...) LPP_INTL_LOG_EVERY_T(LppSeverity::W, n) << LPP_INTL::formatToString(__VA_ARGS__); |
||
372 |
#define ROS_WARN_STREAM_THROTTLE(n, x) LPP_INTL_LOG_EVERY_T(LppSeverity::W, n) << x |
||
373 |
#define ROS_ERROR_THROTTLE(n, ...) LPP_INTL_LOG_EVERY_T(LppSeverity::E, n) << LPP_INTL::formatToString(__VA_ARGS__); |
||
374 |
#define ROS_ERROR_STREAM_THROTTLE(n, x) LPP_INTL_LOG_EVERY_T(LppSeverity::E, n) << x |
||
375 |
#define ROS_FATAL_THROTTLE(n, ...) LPP_INTL_LOG_EVERY_T(LppSeverity::F, n) << LPP_INTL::formatToString(__VA_ARGS__); |
||
376 |
#define ROS_FATAL_STREAM_THROTTLE(n, x) LPP_INTL_LOG_EVERY_T(LppSeverity::F, n) << x |
||
377 |
#endif |
||
378 |
|||
379 |
#pragma clang diagnostic pop |
||
380 |
#endif |
||
381 |
|||
382 |
|||
383 |
//! MODE_ROSLOG |
||
384 |
#ifdef MODE_ROSLOG |
||
385 |
#define LOG_IF(severity, cond) if (cond) InternalLog(GlogSeverity::severity) |
||
386 |
|||
387 |
#define LOG_1(severity) LPP_INTL::InternalLog(LPP_INTL::GlogSeverity::severity) |
||
388 |
#define LOG_2(severity, x) LPP_INTL::InternalLog(LPP_INTL::LppSeverity::severity) << x |
||
389 |
#define LOG_3(severity, cond, x) if (cond) LPP_INTL::InternalLog(LppSeverity::severity) << x |
||
390 |
#endif |
||
391 |
|||
392 |
#if defined MODE_ROSLOG || defined MODE_LPP || defined MODE_DEFAULT |
||
393 |
#define LOG_EVERY(severity, n, x) LPP_INTL::InternalLogCount::getInstance().update<unsigned int, LPP_INTL::PolicyType::EVERY_N>(LPP_GET_KEY(), n, LPP_INTL::InternalLog() << x, toBase(LPP_INTL::LppSeverity::severity)) // NOLINT(bugprone-macro-parentheses) |
||
394 |
#define LOG_FIRST(severity, n, x) LPP_INTL::InternalLogCount::getInstance().update<unsigned int, LPP_INTL::PolicyType::FIRST_N>(LPP_GET_KEY(), n, LPP_INTL::InternalLog() << x, toBase(LPP_INTL::LppSeverity::severity)) // NOLINT(bugprone-macro-parentheses) |
||
395 |
#define LOG_TIMED(severity, t, x) LPP_INTL::InternalLogCount::getInstance().update<float, LPP_INTL::PolicyType::TIMED>(LPP_GET_KEY(), t, LPP_INTL::InternalLog() << x, toBase(LPP_INTL::LppSeverity::severity)) // NOLINT(bugprone-macro-parentheses) |
||
396 |
#endif |
||
397 |
|||
398 |
#if defined MODE_ROSLOG || defined MODE_LPP || MODE_NOLOG |
||
399 |
/** |
||
400 |
* Replace glog's FLAGS_v and VLOG_IS_ON to avoid linker errors |
||
401 |
* if glog is installed but not linked to lpp. |
||
402 |
*/ |
||
403 |
[[maybe_unused]] inline static int32_t LPP_FLAGS_v; |
||
404 |
|||
405 |
#ifdef LPP_GLOG_SUPPORTED |
||
406 |
#define FLAGS_v LPP_FLAGS_v |
||
407 |
#endif //LPP_GLOG_SUPPORTED |
||
408 |
#endif //defined MODE_ROSLOG || defined MODE_LPP || MODE_NOLOG |
||
409 |
|||
410 |
#if defined MODE_ROSLOG || defined MODE_LPP |
||
411 |
#define LOG_EVERY_N(severity, n) LPP_INTL::InternalPolicyLog<unsigned int>(LPP_GET_KEY(), n, LPP_INTL::toBase(LPP_INTL::GlogSeverity::severity), LPP_INTL::PolicyType::EVERY_N) |
||
412 |
#define LOG_EVERY_T(severity, t) LPP_WARN("LOG_EVERY_T is only defined in GLOG v0.6 or newer.") LPP_INTL::InternalPolicyLog<float>(LPP_GET_KEY(), t, LPP_INTL::toBase(LPP_INTL::GlogSeverity::severity), LPP_INTL::PolicyType::TIMED) |
||
413 |
#define LOG_IF_EVERY_N(severity, condition, n) if (condition) LOG_EVERY_N(severity, n) |
||
414 |
#define LOG_FIRST_N(severity, n) LPP_INTL::InternalPolicyLog<unsigned int>(LPP_GET_KEY(), n, LPP_INTL::toBase(LPP_INTL::GlogSeverity::severity), LPP_INTL::PolicyType::FIRST_N) |
||
415 |
|||
416 |
#define DLOG(severity) LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); LPP_INTL::InternalLog(LPP_INTL::BaseSeverity::DEBUG) |
||
417 |
#define DLOG_EVERY_N(severity, n) LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); LPP_INTL::InternalPolicyLog<unsigned int>(LPP_GET_KEY(), n, LPP_INTL::BaseSeverity::DEBUG, LPP_INTL::PolicyType::EVERY_N) |
||
418 |
#define DLOG_EVERY_T(severity, t) LPP_WARN("DLOG_FIRST_N is a Log++ extension"); LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); LPP_INTL::InternalPolicyLog<float>(LPP_GET_KEY(), t, LPP_INTL::BaseSeverity::DEBUG, LPP_INTL::PolicyType::TIMED) |
||
419 |
#define DLOG_FIRST_N(severity, n) LPP_WARN("DLOG_FIRST_N is a Log++ extension"); LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); \ |
||
420 |
LPP_INTL::InternalPolicyLog<unsigned int>(LPP_GET_KEY(), n, LPP_INTL::BaseSeverity::DEBUG, LPP_INTL::PolicyType::FIRST_N) |
||
421 |
#define DLOG_IF_EVERY_N(severity, condition, n) LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); if (condition) LPP_INTL::InternalPolicyLog<unsigned int>(LPP_GET_KEY(), n, LPP_INTL::BaseSeverity::DEBUG, LPP_INTL::PolicyType::EVERY_N) |
||
422 |
#define LOG_STRING(severity, ptr) LPP_ASSERT_GLOG(LPP_INTL::GlogSeverity::severity); LPP_INTL::InternalGlogLogStringLog(toBase(LPP_INTL::GlogSeverity::severity), ptr) |
||
423 |
|||
424 |
#undef VLOG_IS_ON |
||
425 |
#define VLOG_IS_ON(verboselevel) LPP_FLAGS_v >= (verboselevel) ? true : false |
||
426 |
#define VLOG(verboselevel) LPP_INTL::InternalCondLog(LPP_INTL::BaseSeverity::DEBUG, VLOG_IS_ON(verboselevel)) |
||
427 |
#define VLOG_EVERY_N(verboselevel, n) if (VLOG_IS_ON(verboselevel)) LOG_EVERY_N(DEBUG, n) |
||
428 |
#define VLOG_IF(verboselevel, condition) if (condition) VLOG(verboselevel) |
||
429 |
#define VLOG_IF_EVERY_N(verboselevel, condition, n) if (VLOG_IS_ON(verboselevel) && condition) LOG_EVERY_N(DEBUG, n) |
||
430 |
#endif |
||
431 |
|||
432 |
//! MODE_LPP |
||
433 |
#ifdef MODE_LPP |
||
434 |
#define ROS_DEBUG(...) LOG_2(D, LPP_INTL::formatToString(__VA_ARGS__)) |
||
435 |
#define ROS_DEBUG_STREAM(x) LOG_2(D, x) |
||
436 |
#define ROS_INFO(...) LOG_2(I, LPP_INTL::formatToString(__VA_ARGS__)) |
||
437 |
#define ROS_INFO_STREAM(x) LOG_2(I, x) |
||
438 |
#define ROS_WARN(...) LOG_2(W, LPP_INTL::formatToString(__VA_ARGS__)) |
||
439 |
#define ROS_WARN_STREAM(x) LOG_2(W, x) |
||
440 |
#define ROS_ERROR(...) LOG_2(E, LPP_INTL::formatToString(__VA_ARGS__)) |
||
441 |
#define ROS_ERROR_STREAM(x) LOG_2(E, x) |
||
442 |
#define ROS_FATAL(...) LOG_2(F, LPP_INTL::formatToString(__VA_ARGS__)) |
||
443 |
#define ROS_FATAL_STREAM(x) LOG_2(F, x) |
||
444 |
|||
445 |
#define ROS_DEBUG_COND(cond, x) LOG_3(D, cond, x) |
||
446 |
#define ROS_DEBUG_STREAM_COND(cond, x) LOG_3(D, cond, x) |
||
447 |
#define ROS_INFO_COND(cond, x) LOG_3(I, cond, x) |
||
448 |
#define ROS_INFO_STREAM_COND(cond, x) LOG_3(I, cond, x) |
||
449 |
#define ROS_WARN_COND(cond, x) LOG_3(W, cond, x) |
||
450 |
#define ROS_WARN_STREAM_COND(cond, x) LOG_3(W, cond, x) |
||
451 |
#define ROS_ERROR_COND(cond, x) LOG_3(E, cond, x) |
||
452 |
#define ROS_ERROR_STREAM_COND(cond, x) LOG_3(E, cond, x) |
||
453 |
#define ROS_FATAL_COND(cond, x) LOG_3(F, cond, x) |
||
454 |
#define ROS_FATAL_STREAM_COND(cond, x) LOG_3(F, cond, x) |
||
455 |
|||
456 |
#define ROS_DEBUG_ONCE(...) LOG_FIRST(D, 1, LPP_INTL::formatToString(__VA_ARGS__)) |
||
457 |
#define ROS_INFO_ONCE(...) LOG_FIRST(I, 1, LPP_INTL::formatToString(__VA_ARGS__)) |
||
458 |
#define ROS_WARN_ONCE(...) LOG_FIRST(W, 1, LPP_INTL::formatToString(__VA_ARGS__)) |
||
459 |
#define ROS_ERROR_ONCE(...) LOG_FIRST(E, 1, LPP_INTL::formatToString(__VA_ARGS__)) |
||
460 |
#define ROS_FATAL_ONCE(...) LOG_FIRST(F, 1, LPP_INTL::formatToString(__VA_ARGS__)) |
||
461 |
|||
462 |
#define ROS_DEBUG_THROTTLE(period, ...) LOG_TIMED(D, period, LPP_INTL::formatToString(__VA_ARGS__)) |
||
463 |
#define ROS_DEBUG_STREAM_THROTTLE(period, x) LOG_TIMED(D, period, x) |
||
464 |
#define ROS_INFO_THROTTLE(period, ...) LOG_TIMED(I, period, LPP_INTL::formatToString(__VA_ARGS__)) |
||
465 |
#define ROS_INFO_STREAM_THROTTLE(period, x) LOG_TIMED(I, period, x) |
||
466 |
#define ROS_WARN_THROTTLE(period, ...) LOG_TIMED(W, period, LPP_INTL::formatToString(__VA_ARGS__)) |
||
467 |
#define ROS_WARN_STREAM_THROTTLE(period, x) LOG_TIMED(W, period, x) |
||
468 |
#define ROS_ERROR_THROTTLE(period, ...) LOG_TIMED(E, period, LPP_INTL::formatToString(__VA_ARGS__)) |
||
469 |
#define ROS_ERROR_STREAM_THROTTLE(period, x) LOG_TIMED(E, period, x) |
||
470 |
#define ROS_FATAL_THROTTLE(period, ...) LOG_TIMED(F, period, LPP_INTL::formatToString(__VA_ARGS__)) |
||
471 |
#define ROS_FATAL_STREAM_THROTTLE(period, x) LOG_TIMED(F, period, x) |
||
472 |
|||
473 |
#define LOG_IF(severity, cond) if (cond) LPP_INTL::InternalLog(GlogSeverity::severity) |
||
474 |
#define LOG_1(severity) LPP_INTL::InternalLog(LPP_INTL::GlogSeverity::severity) |
||
475 |
#endif |
||
476 |
|||
477 |
#if defined MODE_LPP || defined MODE_DEFAULT |
||
478 |
#define LOG_2(severity, x) LPP_INTL::InternalLog(LPP_INTL::LppSeverity::severity) << x // NOLINT(bugprone-macro-parentheses) |
||
479 |
#define LOG_3(severity, cond, x) if (cond) LPP_INTL::InternalLog(LPP_INTL::LppSeverity::severity) << x // NOLINT(bugprone-macro-parentheses) |
||
480 |
#endif |
||
481 |
|||
482 |
|||
483 |
//! MODE_NOLOG |
||
484 |
|||
485 |
#ifdef MODE_NOLOG |
||
486 |
//lpp |
||
487 |
#define LOG_2(severity, x) (void) LPP_INTL::LppSeverity::severity; InternalLog() << x |
||
488 |
#define LOG_EVERY(severity, n, x) (void) LPP_INTL::LppSeverity::severity; static_assert(std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
489 |
#define LOG_FIRST(severity, n, x) (void) LPP_INTL::LppSeverity::severity; static_assert(std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
490 |
#define LOG_TIMED(severity, t, x) (void) LPP_INTL::LppSeverity::severity; static_assert(std::is_integral<decltype(t)>::value, ""); InternalLog() |
||
491 |
|||
492 |
//glog |
||
493 |
#define LOG_1(severity) (void) LPP_INTL::GlogSeverity::severity; InternalLog() |
||
494 |
#define DLOG(severity) (void) LPP_INTL::GlogSeverity::severity; InternalLog() |
||
495 |
#define DLOG_EVERY_N(severity, n) (void) LPP_INTL::GlogSeverity::severity; InternalLog() |
||
496 |
#define LOG_EVERY_N(severity, n) (void) LPP_INTL::GlogSeverity::severity; InternalLog() |
||
497 |
#define DLOG_FIRST_N(severity, n) (void) LPP_INTL::GlogSeverity::severity; static_assert(std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
498 |
#define LOG_FIRST_N(severity, n) (void) LPP_INTL::GlogSeverity::severity; static_assert(std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
499 |
#define DLOG_IF_EVERY_N(severity, cond, n) (void) LPP_INTL::GlogSeverity::severity; static_assert(std::is_same<decltype(cond), bool>::value && std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
500 |
#define LOG_IF_EVERY_N(severity, cond, n) DLOG_IF_EVERY_N(severity, cond, n) |
||
501 |
#define LOG_STRING(severity, ptr) (void) LPP_INTL::GlogSeverity::severity; static_assert(std::is_same<decltype(ptr), std::vector<std::string>*>::value || std::is_same<decltype(ptr), std::nullptr_t>::value, ""); InternalLog() |
||
502 |
#define VLOG(verboselevel) static_assert(std::is_integral<decltype(verboselevel)>::value, ""); InternalLog() |
||
503 |
#define VLOG_IF(verboselevel, condition) static_assert(std::is_integral<decltype(verboselevel)>::value && std::is_same<decltype(condition), bool>::value, ""); InternalLog() |
||
504 |
#define VLOG_EVERY_N(verboselevel, n) static_assert(std::is_integral<decltype(verboselevel)>::value && std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
505 |
#define VLOG_IF_EVERY_N(verboselevel, condition, n) static_assert(std::is_integral<decltype(verboselevel)>::value && std::is_same<decltype(condition), bool>::value && std::is_integral<decltype(n)>::value, ""); InternalLog() |
||
506 |
#define DLOG_EVERY_T(severity, t) (void) LPP_INTL::GlogSeverity::severity; static_assert(std::is_integral<decltype(t)>::value, ""); InternalLog() |
||
507 |
#define LOG_EVERY_T(severity, t) DLOG_EVERY_T(severity, t) |
||
508 |
|||
509 |
//ros |
||
510 |
#define ROS_DEBUG(...) LOG_2(D, LPP_INTL::emptyString(__VA_ARGS__)) |
||
511 |
#define ROS_INFO(...) LOG_2(I, LPP_INTL::emptyString(__VA_ARGS__)) |
||
512 |
#define ROS_WARN(...) LOG_2(W, LPP_INTL::emptyString(__VA_ARGS__)) |
||
513 |
#define ROS_ERROR(...) LOG_2(E, LPP_INTL::emptyString(__VA_ARGS__)) |
||
514 |
#define ROS_FATAL(...) LOG_2(F, LPP_INTL::emptyString(__VA_ARGS__)) |
||
515 |
|||
516 |
#define ROS_DEBUG_STREAM(x) LPP_INTL::emptyString(x) |
||
517 |
#define ROS_INFO_STREAM(x) LPP_INTL::emptyString(x) |
||
518 |
#define ROS_WARN_STREAM(x) LPP_INTL::emptyString(x) |
||
519 |
#define ROS_ERROR_STREAM(x) LPP_INTL::emptyString(x) |
||
520 |
#define ROS_FATAL_STREAM(x) LPP_INTL::emptyString(x) |
||
521 |
|||
522 |
#define ROS_DEBUG_ONCE(...) LOG_2(D, std::string(LPP_INTL::emptyString(__VA_ARGS__))) |
||
523 |
#define ROS_INFO_ONCE(...) LOG_2(I, std::string(LPP_INTL::emptyString(__VA_ARGS__))) |
||
524 |
#define ROS_WARN_ONCE(...) LOG_2(W, std::string(LPP_INTL::emptyString(__VA_ARGS__))) |
||
525 |
#define ROS_ERROR_ONCE(...) LOG_2(E, std::string(LPP_INTL::emptyString(__VA_ARGS__))) |
||
526 |
#define ROS_FATAL_ONCE(...) LOG_2(F, std::string(LPP_INTL::emptyString(__VA_ARGS__))) |
||
527 |
|||
528 |
#define ROS_DEBUG_THROTTLE(t, x) static_assert(std::is_integral<decltype(t)>::value, ""); LPP_INTL::emptyString(x) |
||
529 |
#define ROS_DEBUG_STREAM_THROTTLE(t, x) static_assert(std::is_integral<decltype(t)>::value, ""); InternalLog() |
||
530 |
#define ROS_INFO_THROTTLE(t, x) ROS_DEBUG_THROTTLE(t, x) |
||
531 |
#define ROS_INFO_STREAM_THROTTLE(t, x) ROS_DEBUG_STREAM_THROTTLE(t, x) |
||
532 |
#define ROS_WARN_THROTTLE(t, x) ROS_DEBUG_THROTTLE(t, x) |
||
533 |
#define ROS_WARN_STREAM_THROTTLE(t, x) ROS_DEBUG_STREAM_THROTTLE(t, x) |
||
534 |
#define ROS_ERROR_THROTTLE(t, x) ROS_DEBUG_THROTTLE(t, x) |
||
535 |
#define ROS_ERROR_STREAM_THROTTLE(t, x) ROS_DEBUG_STREAM_THROTTLE(t, x) |
||
536 |
#define ROS_FATAL_THROTTLE(t, x) ROS_DEBUG_THROTTLE(t, x) |
||
537 |
#define ROS_FATAL_STREAM_THROTTLE(t, x) ROS_DEBUG_STREAM_THROTTLE(t, x) |
||
538 |
#endif |
||
539 |
|||
540 |
namespace lpp { |
||
541 |
namespace internal { |
||
542 |
#ifdef MODE_NOLOG |
||
543 |
//! Used to disable logging for printf(3) like syntax |
||
544 |
template<typename... Args> |
||
545 |
10 |
constexpr inline const char* emptyString([[maybe_unused]] const char *f, [[maybe_unused]] Args... args) { |
|
546 |
10 |
return ""; |
|
547 |
} |
||
548 |
|||
549 |
180 |
[[maybe_unused]] constexpr const char* emptyString([[maybe_unused]] const char *str) { |
|
550 |
180 |
return ""; |
|
551 |
} |
||
552 |
|||
553 |
[[maybe_unused]] constexpr const char* emptyString([[maybe_unused]] const std::string& str) { |
||
554 |
return ""; |
||
555 |
} |
||
556 |
#endif |
||
557 |
//! Composes a string with the same text that would be printed if format was used on printf(3) |
||
558 |
template<typename... Args> |
||
559 |
24 |
inline std::string formatToString(const char *f, Args... args) { |
|
560 |
24 |
size_t sz = snprintf(nullptr, 0, f, args...); |
|
561 |
✗✓ | 24 |
if (sz == 0) { |
562 |
return ""; |
||
563 |
} |
||
564 |
24 |
char *buf = (char *) malloc(sz + 1); |
|
565 |
24 |
snprintf(buf, sz + 1, f, args...); |
|
566 |
✓✗ | 24 |
return buf; |
567 |
} |
||
568 |
|||
569 |
338 |
inline std::string formatToString(const char *str) { |
|
570 |
✓✗ | 338 |
return str; |
571 |
} |
||
572 |
|||
573 |
enum class LppSeverity { |
||
574 |
D, |
||
575 |
I, |
||
576 |
W, |
||
577 |
E, |
||
578 |
F |
||
579 |
}; |
||
580 |
|||
581 |
enum class GlogSeverity { |
||
582 |
DEBUG, |
||
583 |
INFO, |
||
584 |
WARNING, |
||
585 |
ERROR, |
||
586 |
FATAL |
||
587 |
}; |
||
588 |
|||
589 |
1381 |
inline BaseSeverity toBase(LppSeverity lpp_severity) { |
|
590 |
1381 |
return (BaseSeverity) lpp_severity; |
|
591 |
} |
||
592 |
|||
593 |
849 |
inline BaseSeverity toBase(GlogSeverity glog_severity) { |
|
594 |
849 |
return (BaseSeverity) glog_severity; |
|
595 |
} |
||
596 |
|||
597 |
//! Internal log class |
||
598 |
class InternalLog { |
||
599 |
public: |
||
600 |
1690 |
InternalLog() { |
|
601 |
1690 |
should_print_ = false; |
|
602 |
1690 |
}; |
|
603 |
|||
604 |
1951 |
explicit InternalLog(BaseSeverity base_severity) : severity_(base_severity) {} |
|
605 |
48 |
explicit InternalLog(LppSeverity lpp_severity) : severity_(toBase(lpp_severity)) {} |
|
606 |
12 |
explicit InternalLog(GlogSeverity glog_severity) : severity_(toBase(glog_severity)) {} |
|
607 |
|||
608 |
InternalLog(InternalLog const &log) : severity_(log.severity_) { |
||
609 |
ss << log.ss.str(); |
||
610 |
} |
||
611 |
|||
612 |
BaseSeverity severity_{}; |
||
613 |
std::stringstream ss{}; |
||
614 |
|||
615 |
✓✓ | 7402 |
virtual ~InternalLog() { |
616 |
✓✓ | 7402 |
if (!should_print_) { |
617 |
5846 |
return; |
|
618 |
} |
||
619 |
#if defined MODE_ROSLOG |
||
620 |
✓✓✓✓ ✓✗ |
338 |
switch (severity_) { |
621 |
✗✓✓✓ ✗✓✓✗ |
84 |
case BaseSeverity::DEBUG:ROS_DEBUG_STREAM(ss.str()); |
622 |
84 |
break; |
|
623 |
✗✓✓✓ ✗✓✓✗ |
68 |
case BaseSeverity::INFO:ROS_INFO_STREAM(ss.str()); |
624 |
68 |
break; |
|
625 |
✗✓✓✓ ✗✓✓✗ |
62 |
case BaseSeverity::WARN:ROS_WARN_STREAM(ss.str()); |
626 |
62 |
break; |
|
627 |
✗✓✓✓ ✗✓✓✗ |
62 |
case BaseSeverity::ERROR:ROS_ERROR_STREAM(ss.str()); |
628 |
62 |
break; |
|
629 |
✗✓✓✓ ✗✓✓✗ |
62 |
case BaseSeverity::FATAL:ROS_FATAL_STREAM(ss.str()); |
630 |
62 |
break; |
|
631 |
} |
||
632 |
#endif |
||
633 |
#if defined MODE_LPP || defined MODE_DEFAULT |
||
634 |
972 |
lpp::internal::logging.call(severity_, ss.str()); |
|
635 |
#endif |
||
636 |
#if defined MODE_GLOG |
||
637 |
✓✓✓✓ ✗✗ |
246 |
switch (severity_) { |
638 |
16 |
case BaseSeverity::DEBUG: |
|
639 |
16 |
LOG(INFO) << ss.str(); |
|
640 |
16 |
break; |
|
641 |
102 |
case BaseSeverity::INFO: |
|
642 |
102 |
LOG(INFO) << ss.str(); |
|
643 |
102 |
break; |
|
644 |
64 |
case BaseSeverity::WARN: |
|
645 |
64 |
LOG(WARNING) << ss.str(); |
|
646 |
64 |
break; |
|
647 |
64 |
case BaseSeverity::ERROR: |
|
648 |
64 |
LOG(ERROR) << ss.str(); |
|
649 |
64 |
break; |
|
650 |
case BaseSeverity::FATAL: |
||
651 |
LOG(FATAL) << ss.str(); |
||
652 |
break; |
||
653 |
} |
||
654 |
#endif |
||
655 |
} |
||
656 |
|||
657 |
protected: |
||
658 |
bool should_print_{true}; |
||
659 |
}; |
||
660 |
|||
661 |
template<typename T> |
||
662 |
7118 |
InternalLog &&operator<<(InternalLog &&wrap, T const &whatever) { |
|
663 |
7118 |
wrap.ss << whatever; |
|
664 |
7118 |
return std::move(wrap); |
|
665 |
} |
||
666 |
|||
667 |
//! Used for glog's VLOG macro |
||
668 |
class InternalCondLog : public InternalLog { |
||
669 |
public: |
||
670 |
18 |
explicit InternalCondLog(BaseSeverity severity, bool cond) |
|
671 |
18 |
: InternalLog(severity) { |
|
672 |
18 |
should_print_ = cond; |
|
673 |
18 |
} |
|
674 |
36 |
~InternalCondLog() override = default; |
|
675 |
}; |
||
676 |
|||
677 |
|||
678 |
class LogPolicyBase { |
||
679 |
public: |
||
680 |
virtual void update() = 0; |
||
681 |
[[nodiscard]] virtual bool shouldLog() const = 0; |
||
682 |
253 |
virtual void onLog() {}; |
|
683 |
354 |
virtual ~LogPolicyBase() = default; |
|
684 |
}; |
||
685 |
|||
686 |
template<typename T> |
||
687 |
class LogPolicy : public LogPolicyBase { |
||
688 |
public: |
||
689 |
354 |
explicit LogPolicy(T max) : max_(max) {} |
|
690 |
177 |
~LogPolicy() override = default; |
|
691 |
protected: |
||
692 |
T max_{0}; |
||
693 |
}; |
||
694 |
|||
695 |
class CountableLogPolicy : public LogPolicy<unsigned int> { |
||
696 |
public: |
||
697 |
117 |
explicit CountableLogPolicy(unsigned int max) : LogPolicy(max) {} |
|
698 |
protected: |
||
699 |
unsigned int counter_{0}; |
||
700 |
}; |
||
701 |
|||
702 |
class OccasionPolicy : public CountableLogPolicy { |
||
703 |
public: |
||
704 |
62 |
explicit OccasionPolicy(unsigned int max) : CountableLogPolicy(max) { |
|
705 |
62 |
counter_ = max_; |
|
706 |
62 |
} |
|
707 |
|||
708 |
295 |
inline void update() override { |
|
709 |
295 |
should_log_ = false; |
|
710 |
|||
711 |
✓✓ | 295 |
if (counter_ % max_ == 0) { |
712 |
124 |
should_log_ = true; |
|
713 |
124 |
counter_ = 0; |
|
714 |
} |
||
715 |
295 |
counter_++; |
|
716 |
295 |
} |
|
717 |
|||
718 |
295 |
[[nodiscard]] inline bool shouldLog() const override { |
|
719 |
295 |
return should_log_; |
|
720 |
} |
||
721 |
|||
722 |
124 |
~OccasionPolicy() override = default; |
|
723 |
private: |
||
724 |
bool should_log_{false}; |
||
725 |
}; |
||
726 |
|||
727 |
class FirstNOccurrencesPolicy : public CountableLogPolicy { |
||
728 |
public: |
||
729 |
55 |
explicit FirstNOccurrencesPolicy(unsigned int max) : CountableLogPolicy(max) {} |
|
730 |
243 |
inline void update() override { |
|
731 |
✓✓ | 243 |
if (!is_n_occurences_reached) { |
732 |
176 |
counter_++; |
|
733 |
} |
||
734 |
|||
735 |
✓✓ | 243 |
if (counter_ > max_) { |
736 |
114 |
is_n_occurences_reached = true; |
|
737 |
} |
||
738 |
243 |
} |
|
739 |
|||
740 |
243 |
[[nodiscard]] inline bool shouldLog() const override { |
|
741 |
243 |
return !is_n_occurences_reached; |
|
742 |
} |
||
743 |
|||
744 |
110 |
~FirstNOccurrencesPolicy() override = default; |
|
745 |
private: |
||
746 |
bool is_n_occurences_reached = false; |
||
747 |
}; |
||
748 |
|||
749 |
using namespace std::chrono; |
||
750 |
|||
751 |
class TimePolicy : public LogPolicy<float> { |
||
752 |
public: |
||
753 |
60 |
explicit TimePolicy(float max) : LogPolicy(max) {}; |
|
754 |
|||
755 |
1700 |
inline void update() override { |
|
756 |
✓✗ | 1700 |
now_ = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count(); |
757 |
1700 |
} |
|
758 |
|||
759 |
1700 |
[[nodiscard]] inline bool shouldLog() const override { |
|
760 |
✓✓ | 1700 |
if (now_ >= last_ + static_cast<long>(max_ * 1000000.f)) { |
761 |
460 |
return true; |
|
762 |
} |
||
763 |
1240 |
return false; |
|
764 |
} |
||
765 |
|||
766 |
460 |
void onLog() override { |
|
767 |
460 |
last_ = now_; |
|
768 |
460 |
} |
|
769 |
|||
770 |
120 |
~TimePolicy() override = default; |
|
771 |
private: |
||
772 |
long now_{0}; |
||
773 |
long last_{0}; |
||
774 |
}; |
||
775 |
|||
776 |
enum PolicyType { |
||
777 |
FIRST_N, |
||
778 |
EVERY_N, |
||
779 |
TIMED |
||
780 |
}; |
||
781 |
|||
782 |
typedef std::shared_ptr<LogPolicyBase> LogPolicyPtr; |
||
783 |
|||
784 |
class LogPolicyFactory { |
||
785 |
public: |
||
786 |
template<typename T> |
||
787 |
203 |
static LogPolicyPtr create(PolicyType policy_type, T max) { |
|
788 |
✓✓✓✗ |
203 |
switch (policy_type) { |
789 |
55 |
case FIRST_N: return std::make_shared<FirstNOccurrencesPolicy>(max); |
|
790 |
62 |
case EVERY_N: return std::make_shared<OccasionPolicy>(max); |
|
791 |
86 |
case TIMED: return std::make_shared<TimePolicy>(max); |
|
792 |
default:abort(); |
||
793 |
} |
||
794 |
} |
||
795 |
}; |
||
796 |
|||
797 |
struct LogStatementData { |
||
798 |
177 |
LogStatementData(LogPolicyPtr log_policy, BaseSeverity severity_type) |
|
799 |
177 |
: log_policy_(std::move(log_policy)), severity_type_(severity_type) {} |
|
800 |
LogPolicyPtr log_policy_; |
||
801 |
std::string msg{}; |
||
802 |
BaseSeverity severity_type_; |
||
803 |
}; |
||
804 |
|||
805 |
class InternalLogCount { |
||
806 |
public: |
||
807 |
2330 |
static InternalLogCount &getInstance() { |
|
808 |
✓✓✓✗ |
2330 |
static InternalLogCount instance; |
809 |
2330 |
return instance; |
|
810 |
} |
||
811 |
|||
812 |
template<typename T, PolicyType policyType> |
||
813 |
1023 |
inline void update(const std::string &key, |
|
814 |
T max, |
||
815 |
const InternalLog &internal_log, |
||
816 |
const BaseSeverity base_severity) { |
||
817 |
//Check if T is a float and only allow it for PolicyType::TIMED |
||
818 |
static_assert(std::is_same<T, unsigned int>::value || std::is_same<T, float>::value, "Only int or float is allowed for T"); |
||
819 |
|||
820 |
if constexpr (std::is_same<T, float>::value) { |
||
821 |
static_assert(policyType == PolicyType::TIMED, "Only PolicyType::TIMED can be used with float"); |
||
822 |
} |
||
823 |
✓✗ | 1023 |
update(key, max, internal_log.ss.str(), base_severity, policyType); |
824 |
1023 |
} |
|
825 |
|||
826 |
template<typename T> |
||
827 |
2898 |
inline void update(const std::string &key, |
|
828 |
T max, |
||
829 |
const std::string &log_msg, |
||
830 |
const BaseSeverity base_severity, |
||
831 |
PolicyType policy_type) { |
||
832 |
|||
833 |
2898 |
updatePolicy(key, max, log_msg, base_severity, policy_type); |
|
834 |
2898 |
mtx_.lock(); |
|
835 |
2898 |
logIfReady(key, log_msg); |
|
836 |
2898 |
mtx_.unlock(); |
|
837 |
2898 |
} |
|
838 |
|||
839 |
template<typename T> |
||
840 |
2968 |
inline void updatePolicy(const std::string &key, |
|
841 |
T max, |
||
842 |
const std::string &log_msg, |
||
843 |
BaseSeverity base_severity, |
||
844 |
PolicyType policy_type) { |
||
845 |
2968 |
mtx_.lock(); |
|
846 |
✓✓ | 2968 |
if (!keyExists(key)) { |
847 |
✓✗ | 203 |
LogStatementData data(LogPolicyFactory::create(policy_type, max), base_severity); |
848 |
✓✗ | 203 |
data.msg = log_msg; |
849 |
✓✗ | 203 |
updateLogPolicyData(&data); |
850 |
✓✗✓✗ |
203 |
occurences_.insert({key, data}); |
851 |
} else { |
||
852 |
2765 |
LogStatementData *data = &occurences_.at(key); |
|
853 |
2765 |
updateLogPolicyData(data); |
|
854 |
} |
||
855 |
2968 |
mtx_.unlock(); |
|
856 |
2968 |
} |
|
857 |
|||
858 |
70 |
inline bool shouldLog(const std::string &key) { |
|
859 |
70 |
mtx_.lock(); |
|
860 |
70 |
bool res = occurences_.at(key).log_policy_->shouldLog(); |
|
861 |
70 |
mtx_.unlock(); |
|
862 |
70 |
return res; |
|
863 |
} |
||
864 |
|||
865 |
22 |
inline void log(const std::string &key) { |
|
866 |
22 |
mtx_.lock(); |
|
867 |
22 |
occurences_.at(key).log_policy_->onLog(); |
|
868 |
22 |
mtx_.unlock(); |
|
869 |
22 |
} |
|
870 |
|||
871 |
private: |
||
872 |
2238 |
inline bool keyExists(const std::string &key) { |
|
873 |
✓✗ | 2238 |
return occurences_.find(key) != occurences_.end(); |
874 |
} |
||
875 |
|||
876 |
2238 |
static inline void updateLogPolicyData(LogStatementData *data) { |
|
877 |
2238 |
data->log_policy_->update(); |
|
878 |
2238 |
} |
|
879 |
|||
880 |
2168 |
inline void logIfReady(const std::string &key, const std::string &log_msg) { |
|
881 |
2168 |
LogStatementData *data = &occurences_.at(key); |
|
882 |
✓✓ | 2168 |
if (data->log_policy_->shouldLog()) { |
883 |
691 |
data->log_policy_->onLog(); |
|
884 |
691 |
data->msg = log_msg; |
|
885 |
✓✗ | 691 |
InternalLog(data->severity_type_) << data->msg; |
886 |
} |
||
887 |
2168 |
} |
|
888 |
|||
889 |
5 |
InternalLogCount() = default; |
|
890 |
std::unordered_map<std::string, LogStatementData> occurences_{}; |
||
891 |
std::mutex mtx_{}; |
||
892 |
}; |
||
893 |
|||
894 |
/** |
||
895 |
* @extends InternalLog |
||
896 |
* Class to process LOG_STRING() macro. |
||
897 |
* |
||
898 |
* LOG_STRING() should log if the vector pointer is NULL, |
||
899 |
* otherwise the message must not be logged and the string |
||
900 |
* is stored in the vector. |
||
901 |
*/ |
||
902 |
class InternalGlogLogStringLog : public InternalLog { |
||
903 |
public: |
||
904 |
24 |
InternalGlogLogStringLog(BaseSeverity base_severity, std::vector<std::string>* vecptr): |
|
905 |
24 |
InternalLog(base_severity), vecptr_(vecptr) { |
|
906 |
✓✓ | 24 |
if (vecptr != nullptr) { |
907 |
12 |
should_print_ = false; |
|
908 |
} |
||
909 |
24 |
}; |
|
910 |
|||
911 |
48 |
~InternalGlogLogStringLog() override { |
|
912 |
✓✓ | 48 |
if (vecptr_ != nullptr) { |
913 |
24 |
vecptr_->push_back(ss.str()); |
|
914 |
} |
||
915 |
} |
||
916 |
|||
917 |
private: |
||
918 |
std::vector<std::string>* vecptr_; |
||
919 |
}; |
||
920 |
|||
921 |
template<typename T> |
||
922 |
class InternalPolicyLog : public InternalLog { |
||
923 |
public: |
||
924 |
1790 |
InternalPolicyLog(std::string key, T n, BaseSeverity base_severity, PolicyType policy_type) : |
|
925 |
1790 |
InternalLog(base_severity), key_(std::move(key)), n_(n), |
|
926 |
1790 |
policy_type_(policy_type) { |
|
927 |
1790 |
should_print_ = false; |
|
928 |
1790 |
}; |
|
929 |
|||
930 |
2430 |
~InternalPolicyLog() override { |
|
931 |
2430 |
if (should_update_) { |
|
932 |
2290 |
InternalLogCount::getInstance().update(key_, n_, ss.str(), severity_, policy_type_); |
|
933 |
} |
||
934 |
} |
||
935 |
|||
936 |
protected: |
||
937 |
bool should_update_{true}; |
||
938 |
std::string key_{}; |
||
939 |
T n_{}; |
||
940 |
PolicyType policy_type_{}; |
||
941 |
}; |
||
942 |
|||
943 |
class LppGlogExtensionLog : public InternalPolicyLog<unsigned int> { |
||
944 |
public: |
||
945 |
70 |
LppGlogExtensionLog(std::string key, unsigned int n, GlogSeverity glog_severity, PolicyType policy_type, |
|
946 |
70 |
std::function<void(const std::string &str)> fn) : |
|
947 |
✓✗ | 70 |
InternalPolicyLog(std::move(key), n, toBase(glog_severity), policy_type), fn_(std::move(fn)) { |
948 |
70 |
should_print_ = false; |
|
949 |
70 |
should_update_ = false; //Disable update in InternalPolicyLog destructor |
|
950 |
70 |
} |
|
951 |
|||
952 |
140 |
~LppGlogExtensionLog() override { |
|
953 |
140 |
InternalLogCount::getInstance().updatePolicy(key_, n_, ss.str(), severity_, policy_type_); |
|
954 |
✓✓ | 140 |
if (InternalLogCount::getInstance().shouldLog(key_)) { |
955 |
44 |
InternalLogCount::getInstance().log(key_); |
|
956 |
44 |
fn_(ss.str()); |
|
957 |
} |
||
958 |
} |
||
959 |
|||
960 |
private: |
||
961 |
std::function<void(const std::string &str)> fn_; |
||
962 |
}; |
||
963 |
} |
||
964 |
} |
||
965 |
|||
966 |
#define LPP_GET_KEY() std::string(__FILE__) + std::to_string(__LINE__) |
||
967 |
#pragma clang diagnostic pop |
||
968 |
|||
969 |
// Undefine macros that are only needed in this file |
||
970 |
#undef LPP_GLOG_SUPPORTED |
||
971 |
#undef LPP_ROSLOG_SUPPORTED |
||
972 |
|||
973 |
#endif //LOG__LOG_H_ |
Generated by: GCOVR (Version 4.2) |