Coverage Report

Created: 2025-06-13 06:46

/src/Fast-DDS/include/fastdds/dds/log/Log.hpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
#ifndef FASTDDS_DDS_LOG__LOG_HPP
16
#define FASTDDS_DDS_LOG__LOG_HPP
17
18
#include <regex>
19
#include <sstream>
20
21
#include <fastdds/rtps/attributes/ThreadSettings.hpp>
22
#include <fastdds/fastdds_dll.hpp>
23
24
/**
25
 * eProsima log layer. Logging categories and verbosity can be specified dynamically at runtime.
26
 * However, even on a category not covered by the current verbosity level,
27
 * there is some overhead on calling a log macro. For maximum performance, you can
28
 * opt out of logging any particular level by defining the following symbols:
29
 *
30
 * * define LOG_NO_ERROR
31
 * * define LOG_NO_WARNING
32
 * * define LOG_NO_INFO
33
 *
34
 * Additionally. the lowest level (Info) is disabled by default on release branches.
35
 */
36
37
// Logging API:
38
39
// EPROSIMA LOG MACROS
40
//! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch
41
#define EPROSIMA_LOG_INFO(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg)
42
//! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING
43
4.21k
#define EPROSIMA_LOG_WARNING(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg)
44
//! Logs an error. Disable reporting through define LOG_NO_ERROR
45
1.32M
#define EPROSIMA_LOG_ERROR(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg)
46
47
#if ENABLE_OLD_LOG_MACROS_
48
// Compile old eProsima macros for compatibility shake.
49
// However, these macros will be deprecated in future releases, so please do not use them.
50
51
//! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch
52
#define logInfo(cat, msg) logInfo_(cat, msg)
53
//! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING
54
0
#define logWarning(cat, msg) logWarning_(cat, msg)
55
//! Logs an error. Disable reporting through define LOG_NO_ERROR
56
#define logError(cat, msg) logError_(cat, msg)
57
58
//! Old internal macros. Just kept them in case some crazy bastard thoughtlessly used them
59
#define logInfo_(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg);
60
0
#define logWarning_(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg);
61
#define logError_(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg);
62
63
#endif  // ENABLE_OLD_LOG_MACROS_
64
65
namespace eprosima {
66
namespace fastdds {
67
namespace dds {
68
69
class LogConsumer;
70
71
/**
72
 * Logging utilities.
73
 * Logging is accessed through the three macros above, and configuration on the log output
74
 * can be achieved through static methods on the class. Logging at various levels can be
75
 * disabled dynamically (through the Verbosity level) or statically (through the LOG_NO_[VERB]
76
 * macros) for maximum performance.
77
 * @ingroup COMMON_MODULE
78
 */
79
class Log
80
{
81
public:
82
83
    /**
84
     * Types of log entry.
85
     * * Error: Maximum priority. Can only be disabled statically through LOG_NO_ERROR.
86
     * * Warning: Medium priority.  Can be disabled statically and dynamically.
87
     * * Info: Low priority. Useful for debugging. Disabled by default on release branches.
88
     */
89
    enum Kind
90
    {
91
        Error,
92
        Warning,
93
        Info,
94
    };
95
96
    /**
97
     * Registers an user defined consumer to route log output.
98
     * There is a default stdout consumer active as default.
99
     * @param consumer r-value to a consumer unique_ptr. It will be invalidated after the call.
100
     */
101
    FASTDDS_EXPORTED_API static void RegisterConsumer(
102
            std::unique_ptr<LogConsumer>&& consumer);
103
104
    //! Removes all registered consumers, including the default stdout.
105
    FASTDDS_EXPORTED_API static void ClearConsumers();
106
107
    //! Enables the reporting of filenames in log entries. Disabled by default.
108
    FASTDDS_EXPORTED_API static void ReportFilenames(
109
            bool);
110
111
    //! Enables the reporting of function names in log entries. Enabled by default when supported.
112
    FASTDDS_EXPORTED_API static void ReportFunctions(
113
            bool);
114
115
    //! Sets the verbosity level, allowing for messages equal or under that priority to be logged.
116
    FASTDDS_EXPORTED_API static void SetVerbosity(
117
            Log::Kind);
118
119
    //! Returns the current verbosity level.
120
    FASTDDS_EXPORTED_API static Log::Kind GetVerbosity();
121
122
    //! Sets a filter that will pattern-match against log categories, dropping any unmatched categories.
123
    FASTDDS_EXPORTED_API static void SetCategoryFilter(
124
            const std::regex&);
125
126
    //! Unset the category filter.
127
    FASTDDS_EXPORTED_API static void UnsetCategoryFilter();
128
129
    //! Returns whether a category filter was set or not.
130
    FASTDDS_EXPORTED_API static bool HasCategoryFilter();
131
132
    //! Returns a copy of the current category filter or an empty object otherwise
133
    FASTDDS_EXPORTED_API static std::regex GetCategoryFilter();
134
135
    //! Sets a filter that will pattern-match against filenames, dropping any unmatched categories.
136
    FASTDDS_EXPORTED_API static void SetFilenameFilter(
137
            const std::regex&);
138
139
    //! Returns a copy of the current filename filter or an empty object otherwise
140
    FASTDDS_EXPORTED_API static std::regex GetFilenameFilter();
141
142
    //! Sets a filter that will pattern-match against the provided error string, dropping any unmatched categories.
143
    FASTDDS_EXPORTED_API static void SetErrorStringFilter(
144
            const std::regex&);
145
146
    //! Sets thread configuration for the logging thread.
147
    FASTDDS_EXPORTED_API static void SetThreadConfig(
148
            const rtps::ThreadSettings&);
149
150
    //! Returns a copy of the current error string filter or an empty object otherwise
151
    FASTDDS_EXPORTED_API static std::regex GetErrorStringFilter();
152
153
    //! Returns the logging engine to configuration defaults.
154
    FASTDDS_EXPORTED_API static void Reset();
155
156
    //! Waits until all info logged up to the call time is consumed
157
    FASTDDS_EXPORTED_API static void Flush();
158
159
    //! Stops the logging thread. It will re-launch on the next call to a successful log macro.
160
    FASTDDS_EXPORTED_API static void KillThread();
161
162
    // Note: In VS2013, if you're linking this class statically, you will have to call KillThread before leaving
163
    // main, due to an unsolved MSVC bug.
164
165
    struct Context
166
    {
167
        const char* filename;
168
        int line;
169
        const char* function;
170
        const char* category;
171
    };
172
173
    struct Entry
174
    {
175
        std::string message;
176
        Log::Context context;
177
        Log::Kind kind;
178
        std::string timestamp;
179
    };
180
181
    /**
182
     * Not recommended to call this method directly! Use the following macros:
183
     *  * EPROSIMA_LOG_INFO(cat, msg);
184
     *  * EPROSIMA_LOG_WARNING(cat, msg);
185
     *  * EPROSIMA_LOG_ERROR(cat, msg);
186
     *
187
     * This is a very high sensible point of the code and it should be refactored to be as efficient as possible.
188
     */
189
    FASTDDS_EXPORTED_API static void QueueLog(
190
            const std::string& message,
191
            const Log::Context&,
192
            Log::Kind);
193
};
194
195
//! Streams Log::Kind serialization
196
inline std::ostream& operator <<(
197
        std::ostream& output,
198
        const Log::Kind& kind)
199
1.32M
{
200
1.32M
    switch (kind){
201
0
        case Log::Kind::Info:
202
0
            output << "Info";
203
0
            break;
204
205
0
        case Log::Kind::Warning:
206
0
            output << "Warning";
207
0
            break;
208
209
1.32M
        case Log::Kind::Error:
210
1.32M
            output << "Error";
211
1.32M
            break;
212
213
0
        default:
214
0
            output << "Invalid Verbosity Kind.";
215
0
            break;
216
1.32M
    }
217
218
1.32M
    return output;
219
1.32M
}
220
221
/**
222
 * Consumes a log entry to output it somewhere.
223
 */
224
class LogConsumer
225
{
226
public:
227
228
2
    virtual ~LogConsumer() = default;
229
230
    virtual void Consume(
231
            const Log::Entry&) = 0;
232
233
protected:
234
235
    FASTDDS_EXPORTED_API void print_timestamp(
236
            std::ostream& stream,
237
            const Log::Entry&,
238
            bool color) const;
239
240
    FASTDDS_EXPORTED_API void print_header(
241
            std::ostream& stream,
242
            const Log::Entry&,
243
            bool color) const;
244
245
    FASTDDS_EXPORTED_API void print_context(
246
            std::ostream& stream,
247
            const Log::Entry&,
248
            bool color) const;
249
250
    FASTDDS_EXPORTED_API void print_message(
251
            std::ostream& stream,
252
            const Log::Entry&,
253
            bool color) const;
254
255
    FASTDDS_EXPORTED_API void print_new_line(
256
            std::ostream& stream,
257
            bool color) const;
258
};
259
260
#if defined(WIN32)
261
#define __func__ __FUNCTION__
262
#endif // if defined(WIN32)
263
264
/********************
265
* Implementation of the log macros depending on the defined macros:
266
* HAVE_LOG_NO_<level> disable completly a verbosity level
267
* _INTERNALDEBUG || __INTERNALDEBUG  force to compile the log macro call even when it would not be added to queue
268
* EPROSIMA_LOG_INFO_IMPL_ would only be compiled if HAVE_LOG_NO_INFO is OFF and
269
* - FASTDDS_ENFORCE_LOG_INFO or (DEBUG and INTERNALDEBUG) are defined
270
*
271
* There are 3 implementations for each level:
272
* 1. Compile and add log to queue
273
* 2. Compile but do not add it to queue (with INTERNALDEBUG)
274
* 3. Do not compile
275
*
276
* Every macro (with implementation) occurs inside a code block so after call every internal variable is destroyed.
277
* Every macro declared has a do while(0).
278
* This will not generate an assembler instruction and forces the user of the macro to use ";" after calling it.
279
* https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
280
* NOTE: some compilation cases do not use do while loop and so they do not force ";".
281
* It is a risk that a user takes in exchange of a perfect way of non generating code in such cases.
282
********************/
283
284
/*********
285
* ERROR *
286
*********/
287
// Name of variables inside macros must be unique, or it could produce an error with external variables
288
#if !HAVE_LOG_NO_ERROR
289
290
#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)                                                                             \
291
1.32M
    do {                                                                                                               \
292
1.32M
        std::stringstream fastdds_log_ss_tmp__;                                                                        \
293
1.32M
        fastdds_log_ss_tmp__ << msg;                                                                                   \
294
1.32M
        eprosima::fastdds::dds::Log::QueueLog(                                                                         \
295
1.32M
            fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat},      \
296
1.32M
            eprosima::fastdds::dds::Log::Kind::Error);                                                                 \
297
1.32M
    } while (0)
298
299
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
300
301
#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)                      \
302
    do {                                                        \
303
        auto fastdds_log_lambda_tmp__ = [&]()                   \
304
                {                                               \
305
                    std::stringstream fastdds_log_ss_tmp__;     \
306
                    fastdds_log_ss_tmp__ << msg;                \
307
                };                                              \
308
        (void)fastdds_log_lambda_tmp__;                         \
309
    } while (0)
310
#else
311
312
#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)
313
314
#endif // ifndef LOG_NO_ERROR
315
316
/***********
317
* WARNING *
318
***********/
319
#if !HAVE_LOG_NO_WARNING
320
321
#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)                                                                          \
322
4.21k
    do {                                                                                                              \
323
4.21k
        if (eprosima::fastdds::dds::Log::GetVerbosity() >= eprosima::fastdds::dds::Log::Kind::Warning)                \
324
4.21k
        {                                                                                                             \
325
0
            std::stringstream fastdds_log_ss_tmp__;                                                                   \
326
0
            fastdds_log_ss_tmp__ << msg;                                                                              \
327
0
            eprosima::fastdds::dds::Log::QueueLog(                                                                    \
328
0
                fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat}, \
329
0
                eprosima::fastdds::dds::Log::Kind::Warning);                                                          \
330
0
        }                                                                                                             \
331
4.21k
    } while (0)
332
333
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
334
335
#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)                    \
336
    do {                                                        \
337
        auto fastdds_log_lambda_tmp__ = [&]()                   \
338
                {                                               \
339
                    std::stringstream fastdds_log_ss_tmp__;     \
340
                    fastdds_log_ss_tmp__ << msg;                \
341
                };                                              \
342
        (void)fastdds_log_lambda_tmp__;                         \
343
    } while (0)
344
345
#else
346
347
#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)
348
349
#endif // ifndef LOG_NO_WARNING
350
351
/********
352
* INFO *
353
********/
354
// Allow multiconfig platforms like windows to disable info queueing on Release and other non-debug configs
355
#if !HAVE_LOG_NO_INFO &&  \
356
    (defined(FASTDDS_ENFORCE_LOG_INFO) || \
357
    ((defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG)) && (defined(_DEBUG) || defined(__DEBUG) || \
358
    !defined(NDEBUG))))
359
360
#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)                                                                             \
361
    do {                                                                                                              \
362
        if (eprosima::fastdds::dds::Log::GetVerbosity() >= eprosima::fastdds::dds::Log::Kind::Info)                   \
363
        {                                                                                                             \
364
            std::stringstream fastdds_log_ss_tmp__;                                                                   \
365
            fastdds_log_ss_tmp__ << msg;                                                                              \
366
            eprosima::fastdds::dds::Log::QueueLog(                                                                    \
367
                fastdds_log_ss_tmp__.str(), eprosima::fastdds::dds::Log::Context{__FILE__, __LINE__, __func__, #cat}, \
368
                eprosima::fastdds::dds::Log::Kind::Info);                                                             \
369
        }                                                                                                             \
370
    } while (0)
371
372
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
373
374
#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)                       \
375
    do {                                                    \
376
        auto fastdds_log_lambda_tmp__ = [&]()               \
377
                {                                           \
378
                    std::stringstream fastdds_log_ss_tmp__; \
379
                    fastdds_log_ss_tmp__ << msg;            \
380
                };                                          \
381
        (void)fastdds_log_lambda_tmp__;                     \
382
    } while (0)
383
384
#else
385
386
#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)
387
388
#endif // ifndef LOG_NO_INFO
389
390
391
} // namespace dds
392
} // namespace fastdds
393
} // namespace eprosima
394
395
#endif // FASTDDS_DDS_LOG__LOG_HPP