/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_ |