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_AT(OT_LOG_LEVEL_WARN)
166 /**
167  * Emits an error log message at warning log level if there is an error.
168  *
169  * The emitted log will use the the following format "Failed to {aText}: {ErrorToString(aError)}", and will be emitted
170  * only if there is an error, i.e., @p aError is not `kErrorNone`.
171  *
172  * @param[in] aError       The error to check and log.
173  * @param[in] aText        The text to include in the log.
174  *
175  */
176 #define LogWarnOnError(aError, aText) Logger::LogOnError(kLogModuleName, aError, aText)
177 #else
178 #define LogWarnOnError(aError, aText)
179 #endif
180 
181 #if OT_SHOULD_LOG
182 /**
183  * Emits a log message at a given log level.
184  *
185  * @param[in] aLogLevel  The log level to use.
186  * @param[in] ...        Argument for the format specification.
187  *
188  */
189 #define LogAt(aLogLevel, ...) Logger::LogInModule(kLogModuleName, aLogLevel, __VA_ARGS__)
190 #else
191 #define LogAt(aLogLevel, ...)
192 #endif
193 
194 #if OT_SHOULD_LOG
195 /**
196  * Emits a log message independent of the configured log level.
197  *
198  * @param[in]  ...   Arguments for the format specification.
199  *
200  */
201 #define LogAlways(...) Logger::LogInModule("", kLogLevelNone, __VA_ARGS__)
202 #else
203 #define LogAlways(...)
204 #endif
205 
206 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
207 /**
208  * Emit a log message for the certification test.
209  *
210  * @param[in]  ...  Arguments for the format specification.
211  *
212  */
213 #define LogCert(...) LogAlways(__VA_ARGS__)
214 #else
215 #define LogCert(...)
216 #endif
217 
218 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
219 /**
220  * Generates a memory dump at log level critical.
221  *
222  * @param[in]  aText         A string that is printed before the bytes.
223  * @param[in]  aData         A pointer to the data buffer.
224  * @param[in]  aDataLength   Number of bytes in @p aData.
225  *
226  */
227 #define DumpCrit(aText, aData, aDataLength) Logger::Dump<kLogLevelCrit, kLogModuleName>(aText, aData, aDataLength)
228 #else
229 #define DumpCrit(aText, aData, aDataLength)
230 #endif
231 
232 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
233 /**
234  * Generates a memory dump at log level warning.
235  *
236  * @param[in]  aText         A string that is printed before the bytes.
237  * @param[in]  aData         A pointer to the data buffer.
238  * @param[in]  aDataLength   Number of bytes in @p aData.
239  *
240  */
241 #define DumpWarn(aText, aData, aDataLength) Logger::Dump<kLogLevelWarn, kLogModuleName>(aText, aData, aDataLength)
242 #else
243 #define DumpWarn(aText, aData, aDataLength)
244 #endif
245 
246 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
247 /**
248  * Generates a memory dump at log level note.
249  *
250  * @param[in]  aText         A string that is printed before the bytes.
251  * @param[in]  aData         A pointer to the data buffer.
252  * @param[in]  aDataLength   Number of bytes in @p aData.
253  *
254  */
255 #define DumpNote(aText, aData, aDataLength) Logger::Dump<kLogLevelNote, kLogModuleName>(aText, aData, aDataLength)
256 #else
257 #define DumpNote(aText, aData, aDataLength)
258 #endif
259 
260 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
261 /**
262  * Generates a memory dump at log level info.
263  *
264  * @param[in]  aText         A string that is printed before the bytes.
265  * @param[in]  aData         A pointer to the data buffer.
266  * @param[in]  aDataLength   Number of bytes in @p aData.
267  *
268  */
269 #define DumpInfo(aText, aData, aDataLength) Logger::Dump<kLogLevelInfo, kLogModuleName>(aText, aData, aDataLength)
270 #else
271 #define DumpInfo(aText, aData, aDataLength)
272 #endif
273 
274 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
275 /**
276  * Generates a memory dump at log level debug.
277  *
278  * @param[in]  aText         A string that is printed before the bytes.
279  * @param[in]  aData         A pointer to the data buffer.
280  * @param[in]  aDataLength   Number of bytes in @p aData.
281  *
282  */
283 #define DumpDebg(aText, aData, aDataLength) Logger::Dump<kLogLevelDebg, kLogModuleName>(aText, aData, aDataLength)
284 #else
285 #define DumpDebg(aText, aData, aDataLength)
286 #endif
287 
288 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_PKT_DUMP
289 /**
290  * Generates a memory dump independent of the configured log level.
291  *
292  * @param[in]  aText         A string that is printed before the bytes.
293  * @param[in]  aData         A pointer to the data buffer.
294  * @param[in]  aDataLength   Number of bytes in @p aData.
295  *
296  */
297 #define DumpAlways(aText, aData, aDataLength) Logger::DumpInModule("", kLogLevelNone, aText, aData, aDataLength)
298 #endif
299 
300 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && OPENTHREAD_CONFIG_LOG_PKT_DUMP
301 /**
302  * Generates a memory dump for certification test.
303  *
304  * @param[in]  aText         A string that is printed before the bytes.
305  * @param[in]  aData         A pointer to the data buffer.
306  * @param[in]  aDataLength   Number of bytes in @p aData.
307  *
308  */
309 #define DumpCert(aText, aData, aDataLength) DumpAlways(aText, aData, aDataLength)
310 #else
311 #define DumpCert(aText, aData, aDataLength)
312 #endif
313 
314 //----------------------------------------------------------------------------------------------------------------------
315 
316 #if OT_SHOULD_LOG
317 
318 class Logger
319 {
320     // The `Logger` class implements the logging methods.
321     //
322     // The `Logger` methods are not intended to be directly used
323     // and instead the logging macros should be used.
324 
325 public:
326     static void LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...)
327         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(3, 4);
328 
329     template <LogLevel kLogLevel>
330     static void LogAtLevel(const char *aModuleName, const char *aFormat, ...)
331         OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
332 
333     static void LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs);
334 
335 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
336     static void LogOnError(const char *aModuleName, Error aError, const char *aText);
337 #endif
338 
339 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
340     static constexpr uint8_t kStringLineLength = 80;
341     static constexpr uint8_t kDumpBytesPerLine = 16;
342 
343     template <LogLevel kLogLevel, const char *kModuleName>
Dump(const char * aText,const void * aData,uint16_t aDataLength)344     static void Dump(const char *aText, const void *aData, uint16_t aDataLength)
345     {
346         DumpAtLevel<kLogLevel>(kModuleName, aText, aData, aDataLength);
347     }
348 
349     static void DumpInModule(const char *aModuleName,
350                              LogLevel    aLogLevel,
351                              const char *aText,
352                              const void *aData,
353                              uint16_t    aDataLength);
354 
355     template <LogLevel kLogLevel>
356     static void DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength);
357 #endif
358 };
359 
360 extern template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...);
361 extern template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...);
362 extern template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...);
363 extern template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...);
364 extern template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...);
365 extern template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...);
366 
367 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
368 extern template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName,
369                                                         const char *aText,
370                                                         const void *aData,
371                                                         uint16_t    aDataLength);
372 extern template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName,
373                                                         const char *aText,
374                                                         const void *aData,
375                                                         uint16_t    aDataLength);
376 extern template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName,
377                                                         const char *aText,
378                                                         const void *aData,
379                                                         uint16_t    aDataLength);
380 extern template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName,
381                                                         const char *aText,
382                                                         const void *aData,
383                                                         uint16_t    aDataLength);
384 extern template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName,
385                                                         const char *aText,
386                                                         const void *aData,
387                                                         uint16_t    aDataLength);
388 extern template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName,
389                                                         const char *aText,
390                                                         const void *aData,
391                                                         uint16_t    aDataLength);
392 #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP
393 #endif // OT_SHOULD_LOG
394 
395 typedef otLogHexDumpInfo HexDumpInfo; ///< Represents the hex dump info.
396 
397 /**
398  * Generates the next hex dump line.
399  *
400  * Can call this method back-to-back to generate the hex dump output line by line. On the first call the `mIterator`
401  * field in @p aInfo MUST be set to zero.
402  *
403  * Here is an example of the generated hex dump output:
404  *
405  *  "==========================[{mTitle} len=070]============================"
406  *  "| 41 D8 87 34 12 FF FF 25 | 4C 57 DA F2 FB 2F 62 7F | A..4...%LW.../b. |"
407  *  "| 3B 01 F0 4D 4C 4D 4C 54 | 4F 00 15 15 00 00 00 00 | ;..MLMLTO....... |"
408  *  "| 00 00 00 01 80 DB 60 82 | 7E 33 72 3B CC B3 A1 84 | ......`.~3r;.... |"
409  *  "| 3B E6 AD B2 0B 45 E7 45 | C5 B9 00 1A CB 2D 6D 1C | ;....E.E.....-m. |"
410  *  "| 10 3E 3C F5 D3 70       |                         | .><..p           |"
411  *  "------------------------------------------------------------------------"
412  *
413  * @param[in,out] aInfo    A reference to a `LogHexDumpInfo` to use to generate hex dump.
414  *
415  * @retval kErrorNone      Successfully generated the next line, `mLine` field in @p aInfo is updated.
416  * @retval kErrorNotFound  Reached the end and no more line to generate.
417  *
418  */
419 Error GenerateNextHexDumpLine(HexDumpInfo &aInfo);
420 
421 } // namespace ot
422 
423 #endif // LOG_HPP_
424