1 /*
2  *  Copyright (c) 2022, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes logging related  definitions.
32  */
33 
34 #ifndef LOG_HPP_
35 #define LOG_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/logging.h>
40 #include <openthread/platform/logging.h>
41 #include <openthread/platform/toolchain.h>
42 
43 namespace ot {
44 
45 /**
46  * @def OT_SHOULD_LOG
47  *
48  * This definition indicates whether or not logging is enabled.
49  *
50  */
51 #define OT_SHOULD_LOG (OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE)
52 
53 /**
54  * This macro indicates whether the OpenThread logging is enabled at a given log level.
55  *
56  * @param[in] aLevel   The log level to check.
57  *
58  * @returns TRUE if logging is enabled at @p aLevel, FALSE otherwise.
59  *
60  */
61 #define OT_SHOULD_LOG_AT(aLevel) (OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL >= (aLevel)))
62 
63 /**
64  * This enumeration represents the log level.
65  *
66  */
67 enum LogLevel : uint8_t
68 {
69     kLogLevelNone = OT_LOG_LEVEL_NONE, ///< None (disable logs)
70     kLogLevelCrit = OT_LOG_LEVEL_CRIT, ///< Critical log level
71     kLogLevelWarn = OT_LOG_LEVEL_WARN, ///< Warning log level
72     kLogLevelNote = OT_LOG_LEVEL_NOTE, ///< Note log level
73     kLogLevelInfo = OT_LOG_LEVEL_INFO, ///< Info log level
74     kLogLevelDebg = OT_LOG_LEVEL_DEBG, ///< Debug log level
75 };
76 
77 constexpr uint8_t kMaxLogModuleNameLength = 14; ///< Maximum module name length
78 
79 #if OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL != OT_LOG_LEVEL_NONE)
80 /**
81  * This macro registers log module name.
82  *
83  * This macro is used in a `cpp` file to register the log module name for that file before using any other logging
84  * functions or macros (e.g., `LogInfo()` or `DumpInfo()`, ...) in the file.
85  *
86  * @param[in] aName  The log module name string (MUST be shorter than `kMaxLogModuleNameLength`).
87  *
88  */
89 #define RegisterLogModule(aName)                                     \
90     constexpr char kLogModuleName[] = aName;                         \
91     namespace {                                                      \
92     /* Defining this type to silence "unused constant" warning/error \
93      * for `kLogModuleName` under any log level config.              \
94      */                                                              \
95     using DummyType = char[sizeof(kLogModuleName)];                  \
96     }                                                                \
97     static_assert(sizeof(kLogModuleName) <= kMaxLogModuleNameLength + 1, "Log module name is too long")
98 
99 #else
100 #define RegisterLogModule(aName) static_assert(true, "Consume the required semi-colon at the end of macro")
101 #endif
102 
103 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT)
104 /**
105  * This macro emits a log message at critical log level.
106  *
107  * @param[in]  ...   Arguments for the format specification.
108  *
109  */
110 #define LogCrit(...) Logger::LogAtLevel<kLogLevelCrit>(kLogModuleName, __VA_ARGS__)
111 #else
112 #define LogCrit(...)
113 #endif
114 
115 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
116 /**
117  * This macro emits a log message at warning log level.
118  *
119  * @param[in]  ...   Arguments for the format specification.
120  *
121  */
122 #define LogWarn(...) Logger::LogAtLevel<kLogLevelWarn>(kLogModuleName, __VA_ARGS__)
123 #else
124 #define LogWarn(...)
125 #endif
126 
127 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
128 /**
129  * This macro emits a log message at note log level.
130  *
131  * @param[in]  ...   Arguments for the format specification.
132  *
133  */
134 #define LogNote(...) Logger::LogAtLevel<kLogLevelNote>(kLogModuleName, __VA_ARGS__)
135 #else
136 #define LogNote(...)
137 #endif
138 
139 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
140 /**
141  * This macro emits a log message at info log level.
142  *
143  * @param[in]  ...   Arguments for the format specification.
144  *
145  */
146 #define LogInfo(...) Logger::LogAtLevel<kLogLevelInfo>(kLogModuleName, __VA_ARGS__)
147 #else
148 #define LogInfo(...)
149 #endif
150 
151 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG)
152 /**
153  * This macro emits a log message at debug log level.
154  *
155  * @param[in]  ...   Arguments for the format specification.
156  *
157  */
158 #define LogDebg(...) Logger::LogAtLevel<kLogLevelDebg>(kLogModuleName, __VA_ARGS__)
159 #else
160 #define LogDebg(...)
161 #endif
162 
163 #if OT_SHOULD_LOG
164 /**
165  * This macro emits a log message at a given log level.
166  *
167  * @param[in] aLogLevel  The log level to use.
168  * @param[in] ...        Argument for the format specification.
169  *
170  */
171 #define LogAt(aLogLevel, ...) Logger::LogInModule(kLogModuleName, aLogLevel, __VA_ARGS__)
172 #else
173 #define LogAt(aLogLevel, ...)
174 #endif
175 
176 #if OT_SHOULD_LOG
177 /**
178  * This macro emits a log message independent of the configured log level.
179  *
180  * @param[in]  ...   Arguments for the format specification.
181  *
182  */
183 #define LogAlways(...) Logger::LogInModule("", kLogLevelNone, __VA_ARGS__)
184 #else
185 #define LogAlways(...)
186 #endif
187 
188 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
189 /**
190  * This macro emit a log message for the certification test.
191  *
192  * @param[in]  ...  Arguments for the format specification.
193  *
194  */
195 #define LogCert(...) LogAlways(__VA_ARGS__)
196 #else
197 #define LogCert(...)
198 #endif
199 
200 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
201 /**
202  * This macro generates a memory dump at log level critical.
203  *
204  * @param[in]  aText         A string that is printed before the bytes.
205  * @param[in]  aData         A pointer to the data buffer.
206  * @param[in]  aDataLength   Number of bytes in @p aData.
207  *
208  */
209 #define DumpCrit(aText, aData, aDataLength) Logger::Dump<kLogLevelCrit, kLogModuleName>(aText, aData, aDataLength)
210 #else
211 #define DumpCrit(aText, aData, aDataLength)
212 #endif
213 
214 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
215 /**
216  * This macro generates a memory dump at log level warning.
217  *
218  * @param[in]  aText         A string that is printed before the bytes.
219  * @param[in]  aData         A pointer to the data buffer.
220  * @param[in]  aDataLength   Number of bytes in @p aData.
221  *
222  */
223 #define DumpWarn(aText, aData, aDataLength) Logger::Dump<kLogLevelWarn, kLogModuleName>(aText, aData, aDataLength)
224 #else
225 #define DumpWarn(aText, aData, aDataLength)
226 #endif
227 
228 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
229 /**
230  * This macro generates a memory dump at log level note.
231  *
232  * @param[in]  aText         A string that is printed before the bytes.
233  * @param[in]  aData         A pointer to the data buffer.
234  * @param[in]  aDataLength   Number of bytes in @p aData.
235  *
236  */
237 #define DumpNote(aText, aData, aDataLength) Logger::Dump<kLogLevelNote, kLogModuleName>(aText, aData, aDataLength)
238 #else
239 #define DumpNote(aText, aData, aDataLength)
240 #endif
241 
242 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
243 /**
244  * This macro generates a memory dump at log level info.
245  *
246  * @param[in]  aText         A string that is printed before the bytes.
247  * @param[in]  aData         A pointer to the data buffer.
248  * @param[in]  aDataLength   Number of bytes in @p aData.
249  *
250  */
251 #define DumpInfo(aText, aData, aDataLength) Logger::Dump<kLogLevelInfo, kLogModuleName>(aText, aData, aDataLength)
252 #else
253 #define DumpInfo(aText, aData, aDataLength)
254 #endif
255 
256 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
257 /**
258  * This macro generates a memory dump at log level debug.
259  *
260  * @param[in]  aText         A string that is printed before the bytes.
261  * @param[in]  aData         A pointer to the data buffer.
262  * @param[in]  aDataLength   Number of bytes in @p aData.
263  *
264  */
265 #define DumpDebg(aText, aData, aDataLength) Logger::Dump<kLogLevelDebg, kLogModuleName>(aText, aData, aDataLength)
266 #else
267 #define DumpDebg(aText, aData, aDataLength)
268 #endif
269 
270 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_PKT_DUMP
271 /**
272  * This macro generates a memory dump independent of the configured log level.
273  *
274  * @param[in]  aText         A string that is printed before the bytes.
275  * @param[in]  aData         A pointer to the data buffer.
276  * @param[in]  aDataLength   Number of bytes in @p aData.
277  *
278  */
279 #define DumpAlways(aText, aData, aDataLength) Logger::DumpInModule("", kLogLevelNone, aText, aData, aDataLength)
280 #endif
281 
282 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && OPENTHREAD_CONFIG_LOG_PKT_DUMP
283 /**
284  * This macro generates a memory dump for certification test.
285  *
286  * @param[in]  aText         A string that is printed before the bytes.
287  * @param[in]  aData         A pointer to the data buffer.
288  * @param[in]  aDataLength   Number of bytes in @p aData.
289  *
290  */
291 #define DumpCert(aText, aData, aDataLength) DumpAlways(aText, aData, aDataLength)
292 #else
293 #define DumpCert(aText, aData, aDataLength)
294 #endif
295 
296 //----------------------------------------------------------------------------------------------------------------------
297 
298 #if OT_SHOULD_LOG
299 
300 class Logger
301 {
302     // The `Logger` class implements the logging methods.
303     //
304     // The `Logger` methods are not intended to be directly used
305     // and instead the logging macros should be used.
306 
307 public:
308     static void LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...)
309         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
310 
311     template <LogLevel kLogLevel>
312     static void LogAtLevel(const char *aModuleName, const char *aFormat, ...)
313         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
314 
315     static void LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs);
316 
317 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
318     static constexpr uint8_t kStringLineLength = 80;
319     static constexpr uint8_t kDumpBytesPerLine = 16;
320 
321     template <LogLevel kLogLevel, const char *kModuleName>
Dump(const char * aText,const void * aData,uint16_t aDataLength)322     static void Dump(const char *aText, const void *aData, uint16_t aDataLength)
323     {
324         DumpAtLevel<kLogLevel>(kModuleName, aText, aData, aDataLength);
325     }
326 
327     static void DumpInModule(const char *aModuleName,
328                              LogLevel    aLogLevel,
329                              const char *aText,
330                              const void *aData,
331                              uint16_t    aDataLength);
332 
333     template <LogLevel kLogLevel>
334     static void DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength);
335 
336     static void DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, uint16_t aDataLength);
337 #endif
338 };
339 
340 extern template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...);
341 extern template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...);
342 extern template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...);
343 extern template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...);
344 extern template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...);
345 extern template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...);
346 
347 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
348 extern template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName,
349                                                         const char *aText,
350                                                         const void *aData,
351                                                         uint16_t    aDataLength);
352 extern template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName,
353                                                         const char *aText,
354                                                         const void *aData,
355                                                         uint16_t    aDataLength);
356 extern template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName,
357                                                         const char *aText,
358                                                         const void *aData,
359                                                         uint16_t    aDataLength);
360 extern template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName,
361                                                         const char *aText,
362                                                         const void *aData,
363                                                         uint16_t    aDataLength);
364 extern template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName,
365                                                         const char *aText,
366                                                         const void *aData,
367                                                         uint16_t    aDataLength);
368 extern template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName,
369                                                         const char *aText,
370                                                         const void *aData,
371                                                         uint16_t    aDataLength);
372 #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP
373 #endif // OT_SHOULD_LOG
374 
375 } // namespace ot
376 
377 #endif // LOG_HPP_
378