Coverage Report

Created: 2022-08-24 06:19

/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 <fastrtps/fastrtps_dll.h>
19
#include <thread>
20
#include <sstream>
21
#include <atomic>
22
#include <regex>
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
//! Logs an info message. Disable it through Log::SetVerbosity, define LOG_NO_INFO, or being in a release branch
40
#define logInfo(cat, msg) logInfo_(cat, msg)
41
//! Logs a warning. Disable reporting through Log::SetVerbosity or define LOG_NO_WARNING
42
2.95k
#define logWarning(cat, msg) logWarning_(cat, msg)
43
//! Logs an error. Disable reporting through define LOG_NO_ERROR
44
1.23M
#define logError(cat, msg) logError_(cat, msg)
45
46
namespace eprosima {
47
namespace fastdds {
48
namespace dds {
49
50
class LogConsumer;
51
52
/**
53
 * Logging utilities.
54
 * Logging is accessed through the three macros above, and configuration on the log output
55
 * can be achieved through static methods on the class. Logging at various levels can be
56
 * disabled dynamically (through the Verbosity level) or statically (through the LOG_NO_[VERB]
57
 * macros) for maximum performance.
58
 * @ingroup COMMON_MODULE
59
 */
60
class Log
61
{
62
public:
63
64
    /**
65
     * Types of log entry.
66
     * * Error: Maximum priority. Can only be disabled statically through LOG_NO_ERROR.
67
     * * Warning: Medium priority.  Can be disabled statically and dynamically.
68
     * * Info: Low priority. Useful for debugging. Disabled by default on release branches.
69
     */
70
    enum Kind
71
    {
72
        Error,
73
        Warning,
74
        Info,
75
    };
76
77
    /**
78
     * Registers an user defined consumer to route log output.
79
     * There is a default stdout consumer active as default.
80
     * @param consumer r-value to a consumer unique_ptr. It will be invalidated after the call.
81
     */
82
    RTPS_DllAPI static void RegisterConsumer(
83
            std::unique_ptr<LogConsumer>&& consumer);
84
85
    //! Removes all registered consumers, including the default stdout.
86
    RTPS_DllAPI static void ClearConsumers();
87
88
    //! Enables the reporting of filenames in log entries. Disabled by default.
89
    RTPS_DllAPI static void ReportFilenames(
90
            bool);
91
92
    //! Enables the reporting of function names in log entries. Enabled by default when supported.
93
    RTPS_DllAPI static void ReportFunctions(
94
            bool);
95
96
    //! Sets the verbosity level, allowing for messages equal or under that priority to be logged.
97
    RTPS_DllAPI static void SetVerbosity(
98
            Log::Kind);
99
100
    //! Returns the current verbosity level.
101
    RTPS_DllAPI static Log::Kind GetVerbosity();
102
103
    //! Sets a filter that will pattern-match against log categories, dropping any unmatched categories.
104
    RTPS_DllAPI static void SetCategoryFilter(
105
            const std::regex&);
106
107
    //! Sets a filter that will pattern-match against filenames, dropping any unmatched categories.
108
    RTPS_DllAPI static void SetFilenameFilter(
109
            const std::regex&);
110
111
    //! Sets a filter that will pattern-match against the provided error string, dropping any unmatched categories.
112
    RTPS_DllAPI static void SetErrorStringFilter(
113
            const std::regex&);
114
115
    //! Returns the logging engine to configuration defaults.
116
    RTPS_DllAPI static void Reset();
117
118
    //! Waits until all info logged up to the call time is consumed
119
    RTPS_DllAPI static void Flush();
120
121
    //! Stops the logging thread. It will re-launch on the next call to a successful log macro.
122
    RTPS_DllAPI static void KillThread();
123
124
    // Note: In VS2013, if you're linking this class statically, you will have to call KillThread before leaving
125
    // main, due to an unsolved MSVC bug.
126
127
    struct Context
128
    {
129
        const char* filename;
130
        int line;
131
        const char* function;
132
        const char* category;
133
    };
134
135
    struct Entry
136
    {
137
        std::string message;
138
        Log::Context context;
139
        Log::Kind kind;
140
        std::string timestamp;
141
    };
142
143
    /**
144
     * Not recommended to call this method directly! Use the following macros:
145
     *  * logInfo(cat, msg);
146
     *  * logWarning(cat, msg);
147
     *  * logError(cat, msg);
148
     */
149
    RTPS_DllAPI static void QueueLog(
150
            const std::string& message,
151
            const Log::Context&,
152
            Log::Kind);
153
154
private:
155
156
    // Applies transformations to the entries compliant with the options selected (such as
157
    // erasure of certain context information, or filtering by category. Returns false
158
    // if the log entry is blacklisted.
159
    static bool preprocess(
160
            Entry&);
161
162
    static void run();
163
};
164
165
/**
166
 * Consumes a log entry to output it somewhere.
167
 */
168
class LogConsumer
169
{
170
public:
171
172
0
    virtual ~LogConsumer() = default;
173
174
    virtual void Consume(
175
            const Log::Entry&) = 0;
176
177
protected:
178
179
    RTPS_DllAPI void print_timestamp(
180
            std::ostream& stream,
181
            const Log::Entry&,
182
            bool color) const;
183
184
    RTPS_DllAPI void print_header(
185
            std::ostream& stream,
186
            const Log::Entry&,
187
            bool color) const;
188
189
    RTPS_DllAPI void print_context(
190
            std::ostream& stream,
191
            const Log::Entry&,
192
            bool color) const;
193
194
    RTPS_DllAPI void print_message(
195
            std::ostream& stream,
196
            const Log::Entry&,
197
            bool color) const;
198
199
    RTPS_DllAPI void print_new_line(
200
            std::ostream& stream,
201
            bool color) const;
202
};
203
204
#if defined(WIN32)
205
#define __func__ __FUNCTION__
206
#endif // if defined(WIN32)
207
208
// Name of variables inside macros must be unique, or it could produce an error with external variables
209
#if !HAVE_LOG_NO_ERROR
210
#define logError_(cat, msg)                                                                                            \
211
1.23M
    {                                                                                                                  \
212
1.23M
        using namespace eprosima::fastdds::dds;                                                                        \
213
1.23M
        std::stringstream fastdds_log_ss_tmp__;                                                                        \
214
1.23M
        fastdds_log_ss_tmp__ << msg;                                                                                   \
215
1.23M
        Log::QueueLog(fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Error); \
216
1.23M
    }
217
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
218
#define logError_(cat, msg)                                     \
219
    {                                                           \
220
        auto fastdds_log_lambda_tmp__ = [&]()                   \
221
                {                                               \
222
                    std::stringstream fastdds_log_ss_tmp__;     \
223
                    fastdds_log_ss_tmp__ << msg;                \
224
                };                                              \
225
        (void)fastdds_log_lambda_tmp__;                         \
226
    }
227
#else
228
#define logError_(cat, msg)
229
#endif // ifndef LOG_NO_ERROR
230
231
#if !HAVE_LOG_NO_WARNING
232
#define logWarning_(cat, msg)                                                                                       \
233
2.95k
    {                                                                                                               \
234
2.95k
        using namespace eprosima::fastdds::dds;                                                                     \
235
2.95k
        if (Log::GetVerbosity() >= Log::Kind::Warning)                                                              \
236
2.95k
        {                                                                                                           \
237
0
            std::stringstream fastdds_log_ss_tmp__;                                                                 \
238
0
            fastdds_log_ss_tmp__ << msg;                                                                            \
239
0
            Log::QueueLog(                                                                                          \
240
0
                fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Warning);  \
241
0
        }                                                                                                           \
242
2.95k
    }
243
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
244
#define logWarning_(cat, msg)                                   \
245
    {                                                           \
246
        auto fastdds_log_lambda_tmp__ = [&]()                   \
247
                {                                               \
248
                    std::stringstream fastdds_log_ss_tmp__;     \
249
                    fastdds_log_ss_tmp__ << msg;                \
250
                };                                              \
251
        (void)fastdds_log_lambda_tmp__;                         \
252
    }
253
#else
254
#define logWarning_(cat, msg)
255
#endif // ifndef LOG_NO_WARNING
256
257
// Allow multiconfig platforms like windows to disable info queueing on Release and other non-debug configs
258
#if !HAVE_LOG_NO_INFO &&  \
259
    (defined(FASTDDS_ENFORCE_LOG_INFO) || \
260
    ((defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG)) && (defined(_DEBUG) || defined(__DEBUG) || \
261
    !defined(NDEBUG))))
262
#define logInfo_(cat, msg)                                                                              \
263
    {                                                                                                   \
264
        using namespace eprosima::fastdds::dds;                                                         \
265
        if (Log::GetVerbosity() >= Log::Kind::Info)                                                     \
266
        {                                                                                               \
267
            std::stringstream fastdds_log_ss_tmp__;                                                     \
268
            fastdds_log_ss_tmp__ << msg;                                                                \
269
            Log::QueueLog(fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, \
270
                    Log::Kind::Info);                                                                   \
271
        }                                                                                               \
272
    }
273
#elif (__INTERNALDEBUG || _INTERNALDEBUG)
274
#define logInfo_(cat, msg)                                  \
275
    {                                                       \
276
        auto fastdds_log_lambda_tmp__ = [&]()               \
277
                {                                           \
278
                    std::stringstream fastdds_log_ss_tmp__; \
279
                    fastdds_log_ss_tmp__ << msg;            \
280
                };                                          \
281
        (void)fastdds_log_lambda_tmp__;                     \
282
    }
283
#else
284
#define logInfo_(cat, msg)
285
#endif // ifndef LOG_NO_INFO
286
287
288
} // namespace dds
289
} // namespace fastdds
290
} // namespace eprosima
291
292
#endif // ifndef _FASTDDS_DDS_LOG_LOG_HPP_