blob: 0870e0685a439f642f8529f156184148e9ffeb2b [file] [log] [blame]
/*
* Copyright (c) 2022, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes logging related definitions.
*/
#ifndef LOG_HPP_
#define LOG_HPP_
#include "openthread-core-config.h"
#include <openthread/logging.h>
#include <openthread/platform/logging.h>
#include <openthread/platform/toolchain.h>
namespace ot {
/**
* @def OT_SHOULD_LOG
*
* This definition indicates whether or not logging is enabled.
*
*/
#define OT_SHOULD_LOG (OPENTHREAD_CONFIG_LOG_OUTPUT != OPENTHREAD_CONFIG_LOG_OUTPUT_NONE)
/**
* This macro indicates whether the OpenThread logging is enabled at a given log level.
*
* @param[in] aLevel The log level to check.
*
* @returns TRUE if logging is enabled at @p aLevel, FALSE otherwise.
*
*/
#define OT_SHOULD_LOG_AT(aLevel) (OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL >= (aLevel)))
/**
* This enumeration represents the log level.
*
*/
enum LogLevel : uint8_t
{
kLogLevelNone = OT_LOG_LEVEL_NONE, ///< None (disable logs)
kLogLevelCrit = OT_LOG_LEVEL_CRIT, ///< Critical log level
kLogLevelWarn = OT_LOG_LEVEL_WARN, ///< Warning log level
kLogLevelNote = OT_LOG_LEVEL_NOTE, ///< Note log level
kLogLevelInfo = OT_LOG_LEVEL_INFO, ///< Info log level
kLogLevelDebg = OT_LOG_LEVEL_DEBG, ///< Debug log level
};
constexpr uint8_t kMaxLogModuleNameLength = 14; ///< Maximum module name length
#if OT_SHOULD_LOG && (OPENTHREAD_CONFIG_LOG_LEVEL != OT_LOG_LEVEL_NONE)
/**
* This macro registers log module name.
*
* This macro is used in a `cpp` file to register the log module name for that file before using any other logging
* functions or macros (e.g., `LogInfo()` or `DumpInfo()`, ...) in the file.
*
* @param[in] aName The log module name string (MUST be shorter than `kMaxLogModuleNameLength`).
*
*/
#define RegisterLogModule(aName) \
constexpr char kLogModuleName[] = aName; \
namespace { \
/* Defining this type to silence "unused constant" warning/error \
* for `kLogModuleName` under any log level config. \
*/ \
using DummyType = char[sizeof(kLogModuleName)]; \
} \
static_assert(sizeof(kLogModuleName) <= kMaxLogModuleNameLength + 1, "Log module name is too long")
#else
#define RegisterLogModule(aName) static_assert(true, "Consume the required semi-colon at the end of macro")
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT)
/**
* This macro emits a log message at critical log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogCrit(...) Logger::Log<kLogLevelCrit, kLogModuleName>(__VA_ARGS__)
#else
#define LogCrit(...)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
/**
* This macro emits a log message at warning log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogWarn(...) Logger::Log<kLogLevelWarn, kLogModuleName>(__VA_ARGS__)
#else
#define LogWarn(...)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE)
/**
* This macro emits a log message at note log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogNote(...) Logger::Log<kLogLevelNote, kLogModuleName>(__VA_ARGS__)
#else
#define LogNote(...)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
/**
* This macro emits a log message at info log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogInfo(...) Logger::Log<kLogLevelInfo, kLogModuleName>(__VA_ARGS__)
#else
#define LogInfo(...)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG)
/**
* This macro emits a log message at debug log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogDebg(...) Logger::Log<kLogLevelDebg, kLogModuleName>(__VA_ARGS__)
#else
#define LogDebg(...)
#endif
#if OT_SHOULD_LOG
/**
* This macro emits a log message at a given log level.
*
* @param[in] aLogLevel The log level to use.
* @param[in] ... Argument for the format specification.
*
*/
#define LogAt(aLogLevel, ...) Logger::LogInModule(kLogModuleName, aLogLevel, __VA_ARGS__)
#else
#define LogAt(aLogLevel, ...)
#endif
#if OT_SHOULD_LOG
/**
* This macro emits a log message independent of the configured log level.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogAlways(...) Logger::LogInModule("", kLogLevelNone, __VA_ARGS__)
#else
#define LogAlways(...)
#endif
#if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* This macro emit a log message for the certification test.
*
* @param[in] ... Arguments for the format specification.
*
*/
#define LogCert(...) LogAlways(__VA_ARGS__)
#else
#define LogCert(...)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_CRIT) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump at log level critical.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpCrit(aText, aData, aDataLength) Logger::Dump<kLogLevelCrit, kLogModuleName>(aText, aData, aDataLength)
#else
#define DumpCrit(aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump at log level warning.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpWarn(aText, aData, aDataLength) Logger::Dump<kLogLevelWarn, kLogModuleName>(aText, aData, aDataLength)
#else
#define DumpWarn(aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump at log level note.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpNote(aText, aData, aDataLength) Logger::Dump<kLogLevelNote, kLogModuleName>(aText, aData, aDataLength)
#else
#define DumpNote(aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump at log level info.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpInfo(aText, aData, aDataLength) Logger::Dump<kLogLevelInfo, kLogModuleName>(aText, aData, aDataLength)
#else
#define DumpInfo(aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG) && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump at log level debug.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpDebg(aText, aData, aDataLength) Logger::Dump<kLogLevelDebg, kLogModuleName>(aText, aData, aDataLength)
#else
#define DumpDebg(aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump independent of the configured log level.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpAlways(aText, aData, aDataLength) Logger::DumpInModule("", kLogLevelNone, aText, aData, aDataLength)
#endif
#if OT_SHOULD_LOG && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && OPENTHREAD_CONFIG_LOG_PKT_DUMP
/**
* This macro generates a memory dump for certification test.
*
* @param[in] aText A string that is printed before the bytes.
* @param[in] aData A pointer to the data buffer.
* @param[in] aDataLength Number of bytes in @p aData.
*
*/
#define DumpCert(aText, aData, aDataLength) DumpAlways(aText, aData, aDataLength)
#else
#define DumpCert(aText, aData, aDataLength)
#endif
//----------------------------------------------------------------------------------------------------------------------
#if OT_SHOULD_LOG
class Logger
{
// The `Logger` class implements the logging methods.
//
// The `Logger` methods are not intended to be directly used
// and instead the logging macros should be used.
public:
template <LogLevel kLogLevel, const char *kModuleName, typename... Args>
static void Log(const char *aFormat, Args... aArgs)
{
LogAtLevel<kLogLevel>(kModuleName, aFormat, aArgs...);
}
static void LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...);
template <LogLevel kLogLevel> static void LogAtLevel(const char *aModuleName, const char *aFormat, ...);
static void LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs);
#if OPENTHREAD_CONFIG_LOG_PKT_DUMP
static constexpr uint8_t kStringLineLength = 80;
static constexpr uint8_t kDumpBytesPerLine = 16;
template <LogLevel kLogLevel, const char *kModuleName>
static void Dump(const char *aText, const void *aData, uint16_t aDataLength)
{
DumpAtLevel<kLogLevel>(kModuleName, aText, aData, aDataLength);
}
static void DumpInModule(const char *aModuleName,
LogLevel aLogLevel,
const char *aText,
const void *aData,
uint16_t aDataLength);
template <LogLevel kLogLevel>
static void DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength);
static void DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, uint16_t aDataLength);
#endif
};
extern template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...);
extern template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...);
extern template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...);
extern template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...);
extern template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...);
extern template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...);
#if OPENTHREAD_CONFIG_LOG_PKT_DUMP
extern template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
extern template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
extern template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
extern template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
extern template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
extern template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName,
const char *aText,
const void *aData,
uint16_t aDataLength);
#endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP
#endif // OT_SHOULD_LOG
} // namespace ot
#endif // LOG_HPP_