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