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 #define OT_SHOULD_LOG (OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE) 53 54 /** 55 * Indicates whether the OpenThread logging is enabled at a given log level. 56 * 57 * @param[in] aLevel The log level to check. 58 * 59 * @returns TRUE if logging is enabled at @p aLevel, FALSE otherwise. 60 */ 61 #define OT_SHOULD_LOG_AT(aLevel) (OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL >= (aLevel))) 62 63 /** 64 * Represents the log level. 65 */ 66 enum LogLevel : uint8_t 67 { 68 kLogLevelNone = OT_LOG_LEVEL_NONE, ///< None (disable logs) 69 kLogLevelCrit = OT_LOG_LEVEL_CRIT, ///< Critical log level 70 kLogLevelWarn = OT_LOG_LEVEL_WARN, ///< Warning log level 71 kLogLevelNote = OT_LOG_LEVEL_NOTE, ///< Note log level 72 kLogLevelInfo = OT_LOG_LEVEL_INFO, ///< Info log level 73 kLogLevelDebg = OT_LOG_LEVEL_DEBG, ///< Debug log level 74 }; 75 76 constexpr uint8_t kMaxLogModuleNameLength = 14; ///< Maximum module name length 77 78 constexpr uint16_t kMaxLogStringSize = OPENTHREAD_CONFIG_LOG_MAX_SIZE; ///< Max size of log string 79 80 #if OT_SHOULD_LOG 81 /** 82 * Registers log module name. 83 * 84 * Is used in a `cpp` file to register the log module name for that file before using any other logging 85 * functions or macros (e.g., `LogInfo()` or `DumpInfo()`, ...) in the file. 86 * 87 * @param[in] aName The log module name string (MUST be shorter than `kMaxLogModuleNameLength`). 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 * Emits a log message at critical log level. 106 * 107 * @param[in] ... Arguments for the format specification. 108 */ 109 #define LogCrit(...) Logger::LogAtLevel<kLogLevelCrit>(kLogModuleName, __VA_ARGS__) 110 #else 111 #define LogCrit(...) 112 #endif 113 114 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) 115 /** 116 * Emits a log message at warning log level. 117 * 118 * @param[in] ... Arguments for the format specification. 119 */ 120 #define LogWarn(...) Logger::LogAtLevel<kLogLevelWarn>(kLogModuleName, __VA_ARGS__) 121 #else 122 #define LogWarn(...) 123 #endif 124 125 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) 126 /** 127 * Emits a log message at note log level. 128 * 129 * @param[in] ... Arguments for the format specification. 130 */ 131 #define LogNote(...) Logger::LogAtLevel<kLogLevelNote>(kLogModuleName, __VA_ARGS__) 132 #else 133 #define LogNote(...) 134 #endif 135 136 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) 137 /** 138 * Emits a log message at info log level. 139 * 140 * @param[in] ... Arguments for the format specification. 141 */ 142 #define LogInfo(...) Logger::LogAtLevel<kLogLevelInfo>(kLogModuleName, __VA_ARGS__) 143 #else 144 #define LogInfo(...) 145 #endif 146 147 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) 148 /** 149 * Emits a log message at debug log level. 150 * 151 * @param[in] ... Arguments for the format specification. 152 */ 153 #define LogDebg(...) Logger::LogAtLevel<kLogLevelDebg>(kLogModuleName, __VA_ARGS__) 154 #else 155 #define LogDebg(...) 156 #endif 157 158 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) 159 /** 160 * Emits an error log message at warning log level if there is an error. 161 * 162 * The emitted log will use the the following format "Failed to {aText}: {ErrorToString(aError)}", and will be emitted 163 * only if there is an error, i.e., @p aError is not `kErrorNone`. 164 * 165 * @param[in] aError The error to check and log. 166 * @param[in] aText The text to include in the log. 167 */ 168 #define LogWarnOnError(aError, aText) Logger::LogOnError(kLogModuleName, aError, aText) 169 #else 170 #define LogWarnOnError(aError, aText) 171 #endif 172 173 #if OT_SHOULD_LOG 174 /** 175 * Emits a log message at a given log level. 176 * 177 * @param[in] aLogLevel The log level to use. 178 * @param[in] ... Argument for the format specification. 179 */ 180 #define LogAt(aLogLevel, ...) Logger::LogInModule(kLogModuleName, aLogLevel, __VA_ARGS__) 181 #else 182 #define LogAt(aLogLevel, ...) 183 #endif 184 185 #if OT_SHOULD_LOG 186 /** 187 * Emits a log message independent of the configured log level. 188 * 189 * @param[in] ... Arguments for the format specification. 190 */ 191 #define LogAlways(...) Logger::LogInModule("", kLogLevelNone, __VA_ARGS__) 192 #else 193 #define LogAlways(...) 194 #endif 195 196 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 197 /** 198 * Emit a log message for the certification test. 199 * 200 * @param[in] ... Arguments for the format specification. 201 */ 202 #define LogCert(...) LogAlways(__VA_ARGS__) 203 #else 204 #define LogCert(...) 205 #endif 206 207 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT) && OPENTHREAD_CONFIG_LOG_PKT_DUMP 208 /** 209 * Generates a memory dump at log level critical. 210 * 211 * @param[in] aText A string that is printed before the bytes. 212 * @param[in] aData A pointer to the data buffer. 213 * @param[in] aDataLength Number of bytes in @p aData. 214 */ 215 #define DumpCrit(aText, aData, aDataLength) Logger::Dump<kLogLevelCrit, kLogModuleName>(aText, aData, aDataLength) 216 #else 217 #define DumpCrit(aText, aData, aDataLength) 218 #endif 219 220 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) && OPENTHREAD_CONFIG_LOG_PKT_DUMP 221 /** 222 * Generates a memory dump at log level warning. 223 * 224 * @param[in] aText A string that is printed before the bytes. 225 * @param[in] aData A pointer to the data buffer. 226 * @param[in] aDataLength Number of bytes in @p aData. 227 */ 228 #define DumpWarn(aText, aData, aDataLength) Logger::Dump<kLogLevelWarn, kLogModuleName>(aText, aData, aDataLength) 229 #else 230 #define DumpWarn(aText, aData, aDataLength) 231 #endif 232 233 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) && OPENTHREAD_CONFIG_LOG_PKT_DUMP 234 /** 235 * Generates a memory dump at log level note. 236 * 237 * @param[in] aText A string that is printed before the bytes. 238 * @param[in] aData A pointer to the data buffer. 239 * @param[in] aDataLength Number of bytes in @p aData. 240 */ 241 #define DumpNote(aText, aData, aDataLength) Logger::Dump<kLogLevelNote, kLogModuleName>(aText, aData, aDataLength) 242 #else 243 #define DumpNote(aText, aData, aDataLength) 244 #endif 245 246 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_PKT_DUMP 247 /** 248 * Generates a memory dump at log level info. 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 #define DumpInfo(aText, aData, aDataLength) Logger::Dump<kLogLevelInfo, kLogModuleName>(aText, aData, aDataLength) 255 #else 256 #define DumpInfo(aText, aData, aDataLength) 257 #endif 258 259 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) && OPENTHREAD_CONFIG_LOG_PKT_DUMP 260 /** 261 * Generates a memory dump at log level debug. 262 * 263 * @param[in] aText A string that is printed before the bytes. 264 * @param[in] aData A pointer to the data buffer. 265 * @param[in] aDataLength Number of bytes in @p aData. 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 #define DumpAlways(aText, aData, aDataLength) Logger::DumpInModule("", kLogLevelNone, aText, aData, aDataLength) 281 #endif 282 283 #if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && OPENTHREAD_CONFIG_LOG_PKT_DUMP 284 /** 285 * Generates a memory dump for certification test. 286 * 287 * @param[in] aText A string that is printed before the bytes. 288 * @param[in] aData A pointer to the data buffer. 289 * @param[in] aDataLength Number of bytes in @p aData. 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 OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) 318 static void LogOnError(const char *aModuleName, Error aError, const char *aText); 319 #endif 320 321 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP 322 static constexpr uint8_t kStringLineLength = 80; 323 static constexpr uint8_t kDumpBytesPerLine = 16; 324 325 template <LogLevel kLogLevel, const char *kModuleName> Dump(const char * aText,const void * aData,uint16_t aDataLength)326 static void Dump(const char *aText, const void *aData, uint16_t aDataLength) 327 { 328 DumpAtLevel<kLogLevel>(kModuleName, aText, aData, aDataLength); 329 } 330 331 static void DumpInModule(const char *aModuleName, 332 LogLevel aLogLevel, 333 const char *aText, 334 const void *aData, 335 uint16_t aDataLength); 336 337 template <LogLevel kLogLevel> 338 static void DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength); 339 #endif 340 }; 341 342 extern template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...); 343 extern template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...); 344 extern template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...); 345 extern template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...); 346 extern template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...); 347 extern template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...); 348 349 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP 350 extern template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName, 351 const char *aText, 352 const void *aData, 353 uint16_t aDataLength); 354 extern template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName, 355 const char *aText, 356 const void *aData, 357 uint16_t aDataLength); 358 extern template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName, 359 const char *aText, 360 const void *aData, 361 uint16_t aDataLength); 362 extern template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName, 363 const char *aText, 364 const void *aData, 365 uint16_t aDataLength); 366 extern template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName, 367 const char *aText, 368 const void *aData, 369 uint16_t aDataLength); 370 extern template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName, 371 const char *aText, 372 const void *aData, 373 uint16_t aDataLength); 374 #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP 375 #endif // OT_SHOULD_LOG 376 377 typedef otLogHexDumpInfo HexDumpInfo; ///< Represents the hex dump info. 378 379 /** 380 * Generates the next hex dump line. 381 * 382 * Can call this method back-to-back to generate the hex dump output line by line. On the first call the `mIterator` 383 * field in @p aInfo MUST be set to zero. 384 * 385 * Here is an example of the generated hex dump output: 386 * 387 * "==========================[{mTitle} len=070]============================" 388 * "| 41 D8 87 34 12 FF FF 25 | 4C 57 DA F2 FB 2F 62 7F | A..4...%LW.../b. |" 389 * "| 3B 01 F0 4D 4C 4D 4C 54 | 4F 00 15 15 00 00 00 00 | ;..MLMLTO....... |" 390 * "| 00 00 00 01 80 DB 60 82 | 7E 33 72 3B CC B3 A1 84 | ......`.~3r;.... |" 391 * "| 3B E6 AD B2 0B 45 E7 45 | C5 B9 00 1A CB 2D 6D 1C | ;....E.E.....-m. |" 392 * "| 10 3E 3C F5 D3 70 | | .><..p |" 393 * "------------------------------------------------------------------------" 394 * 395 * @param[in,out] aInfo A reference to a `LogHexDumpInfo` to use to generate hex dump. 396 * 397 * @retval kErrorNone Successfully generated the next line, `mLine` field in @p aInfo is updated. 398 * @retval kErrorNotFound Reached the end and no more line to generate. 399 */ 400 Error GenerateNextHexDumpLine(HexDumpInfo &aInfo); 401 402 } // namespace ot 403 404 #endif // LOG_HPP_ 405