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