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 #include "common/error.hpp"
44 
45 namespace ot {
46 
47 /**
48  * @def OT_SHOULD_LOG
49  *
50  * This definition indicates whether or not logging is enabled.
51  *
52  */
53 #define OT_SHOULD_LOG (OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE)
54 
55 /**
56  * Indicates whether the OpenThread logging is enabled at a given log level.
57  *
58  * @param[in] aLevel   The log level to check.
59  *
60  * @returns TRUE if logging is enabled at @p aLevel, FALSE otherwise.
61  *
62  */
63 #define OT_SHOULD_LOG_AT(aLevel) (OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL >= (aLevel)))
64 
65 /**
66  * Represents the log level.
67  *
68  */
69 enum LogLevel : uint8_t
70 {
71     kLogLevelNone = OT_LOG_LEVEL_NONE, ///< None (disable logs)
72     kLogLevelCrit = OT_LOG_LEVEL_CRIT, ///< Critical log level
73     kLogLevelWarn = OT_LOG_LEVEL_WARN, ///< Warning log level
74     kLogLevelNote = OT_LOG_LEVEL_NOTE, ///< Note log level
75     kLogLevelInfo = OT_LOG_LEVEL_INFO, ///< Info log level
76     kLogLevelDebg = OT_LOG_LEVEL_DEBG, ///< Debug log level
77 };
78 
79 constexpr uint8_t kMaxLogModuleNameLength = 14; ///< Maximum module name length
80 
81 #if OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL != OT_LOG_LEVEL_NONE)
82 /**
83  * Registers log module name.
84  *
85  * Is used in a `cpp` file to register the log module name for that file before using any other logging
86  * functions or macros (e.g., `LogInfo()` or `DumpInfo()`, ...) in the file.
87  *
88  * @param[in] aName  The log module name string (MUST be shorter than `kMaxLogModuleNameLength`).
89  *
90  */
91 #define RegisterLogModule(aName)                                     \
92     constexpr char kLogModuleName[] = aName;                         \
93     namespace {                                                      \
94     /* Defining this type to silence "unused constant" warning/error \
95      * for `kLogModuleName` under any log level config.              \
96      */                                                              \
97     using DummyType = char[sizeof(kLogModuleName)];                  \
98     }                                                                \
99     static_assert(sizeof(kLogModuleName) <= kMaxLogModuleNameLength + 1, "Log module name is too long")
100 
101 #else
102 #define RegisterLogModule(aName) static_assert(true, "Consume the required semi-colon at the end of macro")
103 #endif
104 
105 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT)
106 /**
107  * Emits a log message at critical log level.
108  *
109  * @param[in]  ...   Arguments for the format specification.
110  *
111  */
112 #define LogCrit(...) Logger::LogAtLevel<kLogLevelCrit>(kLogModuleName, __VA_ARGS__)
113 #else
114 #define LogCrit(...)
115 #endif
116 
117 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
118 /**
119  * Emits a log message at warning log level.
120  *
121  * @param[in]  ...   Arguments for the format specification.
122  *
123  */
124 #define LogWarn(...) Logger::LogAtLevel<kLogLevelWarn>(kLogModuleName, __VA_ARGS__)
125 #else
126 #define LogWarn(...)
127 #endif
128 
129 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
130 /**
131  * Emits a log message at note log level.
132  *
133  * @param[in]  ...   Arguments for the format specification.
134  *
135  */
136 #define LogNote(...) Logger::LogAtLevel<kLogLevelNote>(kLogModuleName, __VA_ARGS__)
137 #else
138 #define LogNote(...)
139 #endif
140 
141 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
142 /**
143  * Emits a log message at info log level.
144  *
145  * @param[in]  ...   Arguments for the format specification.
146  *
147  */
148 #define LogInfo(...) Logger::LogAtLevel<kLogLevelInfo>(kLogModuleName, __VA_ARGS__)
149 #else
150 #define LogInfo(...)
151 #endif
152 
153 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG)
154 /**
155  * Emits a log message at debug log level.
156  *
157  * @param[in]  ...   Arguments for the format specification.
158  *
159  */
160 #define LogDebg(...) Logger::LogAtLevel<kLogLevelDebg>(kLogModuleName, __VA_ARGS__)
161 #else
162 #define LogDebg(...)
163 #endif
164 
165 #if OT_SHOULD_LOG
166 /**
167  * Emits a log message at a given log level.
168  *
169  * @param[in] aLogLevel  The log level to use.
170  * @param[in] ...        Argument for the format specification.
171  *
172  */
173 #define LogAt(aLogLevel, ...) Logger::LogInModule(kLogModuleName, aLogLevel, __VA_ARGS__)
174 #else
175 #define LogAt(aLogLevel, ...)
176 #endif
177 
178 #if OT_SHOULD_LOG
179 /**
180  * Emits a log message independent of the configured log level.
181  *
182  * @param[in]  ...   Arguments for the format specification.
183  *
184  */
185 #define LogAlways(...) Logger::LogInModule("", kLogLevelNone, __VA_ARGS__)
186 #else
187 #define LogAlways(...)
188 #endif
189 
190 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
191 /**
192  * Emit a log message for the certification test.
193  *
194  * @param[in]  ...  Arguments for the format specification.
195  *
196  */
197 #define LogCert(...) LogAlways(__VA_ARGS__)
198 #else
199 #define LogCert(...)
200 #endif
201 
202 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
203 /**
204  * Generates a memory dump at log level critical.
205  *
206  * @param[in]  aText         A string that is printed before the bytes.
207  * @param[in]  aData         A pointer to the data buffer.
208  * @param[in]  aDataLength   Number of bytes in @p aData.
209  *
210  */
211 #define DumpCrit(aText, aData, aDataLength) Logger::Dump<kLogLevelCrit, kLogModuleName>(aText, aData, aDataLength)
212 #else
213 #define DumpCrit(aText, aData, aDataLength)
214 #endif
215 
216 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
217 /**
218  * Generates a memory dump at log level warning.
219  *
220  * @param[in]  aText         A string that is printed before the bytes.
221  * @param[in]  aData         A pointer to the data buffer.
222  * @param[in]  aDataLength   Number of bytes in @p aData.
223  *
224  */
225 #define DumpWarn(aText, aData, aDataLength) Logger::Dump<kLogLevelWarn, kLogModuleName>(aText, aData, aDataLength)
226 #else
227 #define DumpWarn(aText, aData, aDataLength)
228 #endif
229 
230 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
231 /**
232  * Generates a memory dump at log level note.
233  *
234  * @param[in]  aText         A string that is printed before the bytes.
235  * @param[in]  aData         A pointer to the data buffer.
236  * @param[in]  aDataLength   Number of bytes in @p aData.
237  *
238  */
239 #define DumpNote(aText, aData, aDataLength) Logger::Dump<kLogLevelNote, kLogModuleName>(aText, aData, aDataLength)
240 #else
241 #define DumpNote(aText, aData, aDataLength)
242 #endif
243 
244 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
245 /**
246  * Generates a memory dump at log level info.
247  *
248  * @param[in]  aText         A string that is printed before the bytes.
249  * @param[in]  aData         A pointer to the data buffer.
250  * @param[in]  aDataLength   Number of bytes in @p aData.
251  *
252  */
253 #define DumpInfo(aText, aData, aDataLength) Logger::Dump<kLogLevelInfo, kLogModuleName>(aText, aData, aDataLength)
254 #else
255 #define DumpInfo(aText, aData, aDataLength)
256 #endif
257 
258 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
259 /**
260  * Generates a memory dump at log level debug.
261  *
262  * @param[in]  aText         A string that is printed before the bytes.
263  * @param[in]  aData         A pointer to the data buffer.
264  * @param[in]  aDataLength   Number of bytes in @p aData.
265  *
266  */
267 #define DumpDebg(aText, aData, aDataLength) Logger::Dump<kLogLevelDebg, kLogModuleName>(aText, aData, aDataLength)
268 #else
269 #define DumpDebg(aText, aData, aDataLength)
270 #endif
271 
272 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_PKT_DUMP
273 /**
274  * Generates a memory dump independent of the configured log level.
275  *
276  * @param[in]  aText         A string that is printed before the bytes.
277  * @param[in]  aData         A pointer to the data buffer.
278  * @param[in]  aDataLength   Number of bytes in @p aData.
279  *
280  */
281 #define DumpAlways(aText, aData, aDataLength) Logger::DumpInModule("", kLogLevelNone, aText, aData, aDataLength)
282 #endif
283 
284 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && OPENTHREAD_CONFIG_LOG_PKT_DUMP
285 /**
286  * Generates a memory dump for certification test.
287  *
288  * @param[in]  aText         A string that is printed before the bytes.
289  * @param[in]  aData         A pointer to the data buffer.
290  * @param[in]  aDataLength   Number of bytes in @p aData.
291  *
292  */
293 #define DumpCert(aText, aData, aDataLength) DumpAlways(aText, aData, aDataLength)
294 #else
295 #define DumpCert(aText, aData, aDataLength)
296 #endif
297 
298 //----------------------------------------------------------------------------------------------------------------------
299 
300 #if OT_SHOULD_LOG
301 
302 class Logger
303 {
304     // The `Logger` class implements the logging methods.
305     //
306     // The `Logger` methods are not intended to be directly used
307     // and instead the logging macros should be used.
308 
309 public:
310     static void LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...)
311         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
312 
313     template <LogLevel kLogLevel>
314     static void LogAtLevel(const char *aModuleName, const char *aFormat, ...)
315         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
316 
317     static void LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs);
318 
319 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
320     static constexpr uint8_t kStringLineLength = 80;
321     static constexpr uint8_t kDumpBytesPerLine = 16;
322 
323     template <LogLevel kLogLevel, const char *kModuleName>
Dump(const char * aText,const void * aData,uint16_t aDataLength)324     static void Dump(const char *aText, const void *aData, uint16_t aDataLength)
325     {
326         DumpAtLevel<kLogLevel>(kModuleName, aText, aData, aDataLength);
327     }
328 
329     static void DumpInModule(const char *aModuleName,
330                              LogLevel    aLogLevel,
331                              const char *aText,
332                              const void *aData,
333                              uint16_t    aDataLength);
334 
335     template <LogLevel kLogLevel>
336     static void DumpAtLevel(const char *aModuleName, const char *aText, const void *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 typedef otLogHexDumpInfo HexDumpInfo; ///< Represents the hex dump info.
376 
377 /**
378  * Generates the next hex dump line.
379  *
380  * Can call this method back-to-back to generate the hex dump output line by line. On the first call the `mIterator`
381  * field in @p aInfo MUST be set to zero.
382  *
383  * Here is an example of the generated hex dump output:
384  *
385  *  "==========================[{mTitle} len=070]============================"
386  *  "| 41 D8 87 34 12 FF FF 25 | 4C 57 DA F2 FB 2F 62 7F | A..4...%LW.../b. |"
387  *  "| 3B 01 F0 4D 4C 4D 4C 54 | 4F 00 15 15 00 00 00 00 | ;..MLMLTO....... |"
388  *  "| 00 00 00 01 80 DB 60 82 | 7E 33 72 3B CC B3 A1 84 | ......`.~3r;.... |"
389  *  "| 3B E6 AD B2 0B 45 E7 45 | C5 B9 00 1A CB 2D 6D 1C | ;....E.E.....-m. |"
390  *  "| 10 3E 3C F5 D3 70       |                         | .><..p           |"
391  *  "------------------------------------------------------------------------"
392  *
393  * @param[in,out] aInfo    A reference to a `LogHexDumpInfo` to use to generate hex dump.
394  *
395  * @retval kErrorNone      Successfully generated the next line, `mLine` field in @p aInfo is updated.
396  * @retval kErrorNotFound  Reached the end and no more line to generate.
397  *
398  */
399 Error GenerateNextHexDumpLine(HexDumpInfo &aInfo);
400 
401 } // namespace ot
402 
403 #endif // LOG_HPP_
404