GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/log++.h Lines: 207 211 98.1 %
Date: 2025-03-04 18:34:12 Branches: 90 130 69.2 %

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_