blob: 1a2596ec2c93e5a6355a57c6f537e00942c87e0a [file] [log] [blame]
/*
*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <matter/tracing/build_config.h>
#define __LOG_METRIC_CONCAT_IMPL(a, b) a##b
#define __LOG_METRIC_MACRO_CONCAT(a, b) __LOG_METRIC_CONCAT_IMPL(a, b)
#if MATTER_TRACING_ENABLED
/**
* @def ReturnErrorOnFailureWithMetric(kMetricKey, expr)
*
* @brief
* This macros emits the specified metric with error code and returns the error code,
* if the expression returns an error. For a CHIP_ERROR expression, this means any value
* other than CHIP_NO_ERROR. For an integer expression, this means non-zero.
*
* Example usage:
*
* @code
* ReturnErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* does not evaluate to CHIP_NO_ERROR. Value of the metric is to the
* result of the expression.
* @param[in] expr An expression to be tested.
*/
#define ReturnErrorOnFailureWithMetric(kMetricKey, expr) \
do \
{ \
auto __err = (expr); \
if (!::chip::ChipError::IsSuccess(__err)) \
{ \
MATTER_LOG_METRIC(kMetricKey, __err); \
return __err; \
} \
} while (false)
/**
* @def ReturnLogErrorOnFailureWithMetric(kMetricKey, expr)
*
* @brief
* Returns the error code if the expression returns something different
* than CHIP_NO_ERROR. In addition, a metric is emitted with the specified metric key and
* error code as the value of the metric.
*
* Example usage:
*
* @code
* ReturnLogErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* does not evaluate to CHIP_NO_ERROR. Value of the metric is to the
* result of the expression.
* @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
*/
#define ReturnLogErrorOnFailureWithMetric(kMetricKey, expr) \
do \
{ \
CHIP_ERROR __err = (expr); \
if (__err != CHIP_NO_ERROR) \
{ \
MATTER_LOG_METRIC(kMetricKey, __err); \
ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
return __err; \
} \
} while (false)
/**
* @def ReturnOnFailureWithMetric(kMetricKey, expr)
*
* @brief
* Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other
* than CHIP_NO_ERROR. For an integer expression, this means non-zero. If the expression evaluates to
* anything but CHIP_NO_ERROR, a metric with the specified key is emitted along with error as the value.
*
* Example usage:
*
* @code
* ReturnOnFailureWithMetric(kMetricKey, channel->SendMsg(msg));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* does not evaluate to CHIP_NO_ERROR. Value of the metric is to the
* result of the expression.
* @param[in] expr An expression to be tested.
*/
#define ReturnOnFailureWithMetric(kMetricKey, expr) \
do \
{ \
auto __err = (expr); \
if (!::chip::ChipError::IsSuccess(__err)) \
{ \
MATTER_LOG_METRIC(kMetricKey, __err); \
return; \
} \
} while (false)
/**
* @def VerifyOrReturnWithMetric(kMetricKey, expr, ...)
*
* @brief
* Returns from the void function if expression evaluates to false. If the expression evaluates
* to false, a metric with the specified key is emitted.
*
* Example usage:
*
* @code
* VerifyOrReturnWithMetric(kMetricKey, param != nullptr, LogError("param is nullptr"));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* to false. Value of the metric is set to false.
* @param[in] expr A Boolean expression to be evaluated.
* @param[in] ... Statements to execute before returning. Optional.
*/
#define VerifyOrReturnWithMetric(kMetricKey, expr, ...) \
do \
{ \
if (!(expr)) \
{ \
MATTER_LOG_METRIC(kMetricKey, false); \
__VA_ARGS__; \
return; \
} \
} while (false)
/**
* @def VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...)
*
* @brief
* Returns a specified error code if expression evaluates to false. If the expression evaluates
* to false, a metric with the specified key is emitted with the value set to the code.
*
* Example usage:
*
* @code
* VerifyOrReturnErrorWithMetric(kMetricKey, param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* to false. Value of the metric is to code.
* @param[in] expr A Boolean expression to be evaluated.
* @param[in] code A value to return if @a expr is false.
* @param[in] ... Statements to execute before returning. Optional.
*/
#define VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...) \
VerifyOrReturnValueWithMetric(kMetricKey, expr, code, ##__VA_ARGS__)
/**
* @def VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...)
*
* @brief
* Returns a specified value if expression evaluates to false. If the expression evaluates
* to false, a metric with the specified key is emitted with the value set to value.
*
* Example usage:
*
* @code
* VerifyOrReturnValueWithMetric(kMetricKey, param != nullptr, Foo());
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* to false. Value of the metric is to value.
* @param[in] expr A Boolean expression to be evaluated.
* @param[in] value A value to return if @a expr is false.
* @param[in] ... Statements to execute before returning. Optional.
*/
#define VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...) \
do \
{ \
if (!(expr)) \
{ \
MATTER_LOG_METRIC(kMetricKey, value); \
__VA_ARGS__; \
return (value); \
} \
} while (false)
/**
* @def VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code)
*
* @brief
* Returns and print a specified error code if expression evaluates to false.
* If the expression evaluates to false, a metric with the specified key is emitted
* with the value set to code.
*
* Example usage:
*
* @code
* VerifyOrReturnLogErrorWithMetric(kMetricKey, param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* to false. Value of the metric is to code.
* @param[in] expr A Boolean expression to be evaluated.
* @param[in] code A value to return if @a expr is false.
*/
#if CHIP_CONFIG_ERROR_SOURCE
#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) \
do \
{ \
if (!(expr)) \
{ \
MATTER_LOG_METRIC(kMetricKey, code); \
ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(code), __FILE__, __LINE__); \
return code; \
} \
} while (false)
#else // CHIP_CONFIG_ERROR_SOURCE
#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) \
do \
{ \
if (!(expr)) \
{ \
MATTER_LOG_METRIC(kMetricKey, code); \
ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, code.Format()); \
return code; \
} \
} while (false)
#endif // CHIP_CONFIG_ERROR_SOURCE
/**
* @def SuccessOrExitWithMetric(kMetricKey, error)
*
* @brief
* This checks for the specified error, which is expected to
* commonly be successful (CHIP_NO_ERROR), and branches to
* the local label 'exit' if the error is not success.
* If error is not a success, a metric with key kMetricKey is emitted with
* the error code as the value of the metric.
*
* Example Usage:
*
* @code
* CHIP_ERROR TryHard()
* {
* CHIP_ERROR err;
*
* err = TrySomething();
* SuccessOrExitWithMetric(kMetricKey, err);
*
* err = TrySomethingElse();
* SuccessOrExitWithMetric(kMetricKey, err);
*
* exit:
* return err;
* }
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted
* if the condition evaluates to false. The value
* for the metric is result of the expression aStatus.
* @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
*
*/
#define SuccessOrExitWithMetric(kMetricKey, error) \
nlEXPECT(::chip::Tracing::ErrorHandling::LogMetricIfError((kMetricKey), (error)), exit)
/**
* @def VerifyOrExitWithMetric(kMetricKey, aCondition, anAction)
*
* @brief
* This checks for the specified condition, which is expected to
* commonly be true, and both executes @a anAction and branches to
* the local label 'exit' if the condition is false. If the condition
* is false a metric event with the specified key is emitted with value
* set to the result of the expression anAction.
*
* Example Usage:
*
* @code
* CHIP_ERROR MakeBuffer(const uint8_t *& buf)
* {
* CHIP_ERROR err = CHIP_NO_ERROR;
*
* buf = (uint8_t *)malloc(1024);
* VerifyOrExitWithMetric(kMetricKey, buf != NULL, err = CHIP_ERROR_NO_MEMORY);
*
* memset(buf, 0, 1024);
*
* exit:
* return err;
* }
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted
* if the aCondition evaluates to false. The value
* for the metric is result of the expression anAction.
* @param[in] aCondition A Boolean expression to be evaluated.
* @param[in] anAction An expression or block to execute when the
* assertion fails.
*/
#define VerifyOrExitWithMetric(kMetricKey, aCondition, anAction) \
nlEXPECT_ACTION(aCondition, exit, MATTER_LOG_METRIC((kMetricKey), (anAction)))
/**
* @def ExitNowWithMetric(kMetricKey, ...)
*
* @brief
* This unconditionally executes @a ... and branches to the local
* label 'exit'. In addition a metric is emitted with the specified key.
*
* @note The use of this interface implies neither success nor
* failure for the overall exit status of the enclosing function
* body.
*
* Example Usage:
*
* @code
* CHIP_ERROR ReadAll(Reader& reader)
* {
* CHIP_ERROR err;
*
* while (true)
* {
* err = reader.ReadNext();
* if (err == CHIP_ERROR_AT_END)
* ExitNowWithMetric(kMetricKey, err = CHIP_NO_ERROR);
* SuccessOrExit(err);
* DoSomething();
* }
*
* exit:
* return err;
* }
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted.
* @param[in] ... Statements to execute. Optional.
*/
#define ExitNowWithMetric(kMetricKey, ...) \
do \
{ \
MATTER_LOG_METRIC(kMetricKey); \
__VA_ARGS__; \
goto exit; \
} while (0)
/**
* @def LogErrorOnFailureWithMetric(kMetricKey, expr)
*
* @brief
* Logs a message if the expression returns something different than CHIP_NO_ERROR.
* In addition, a metric is emitted with the specified key and value set to result
* of the expression in case it evaluates to anything other than CHIP_NO_ERROR.
*
* Example usage:
*
* @code
* LogErrorOnFailureWithMetric(kMetricKey, channel->SendMsg(msg));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted if the expr evaluates
* does not evaluate to CHIP_NO_ERROR. Value of the metric is to the
* result of the expression.
* @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
*/
#define LogErrorOnFailureWithMetric(kMetricKey, expr) \
do \
{ \
CHIP_ERROR __err = (expr); \
if (__err != CHIP_NO_ERROR) \
{ \
MATTER_LOG_METRIC(kMetricKey, __err); \
ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
} \
} while (false)
/**
* @def VerifyOrDoWithMetric(kMetricKey, expr, ...)
*
* @brief
* Do something if expression evaluates to false. If the expression evaluates to false a metric
* with the specified key is emitted with value set to false.
*
* Example usage:
*
* @code
* VerifyOrDoWithMetric(param != nullptr, LogError("param is nullptr"));
* @endcode
*
* @param[in] kMetricKey Metric key for the metric event to be emitted.
* Value of the metric is set to false.
* @param[in] expr A Boolean expression to be evaluated.
* @param[in] code Error code to emit as part of the metric.
* @param[in] ... Statements to execute.
*/
#define VerifyOrDoWithMetric(kMetricKey, expr, code, ...) \
do \
{ \
if (!(expr)) \
{ \
MATTER_LOG_METRIC(kMetricKey, code); \
__VA_ARGS__; \
} \
} while (false)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility Macros to support optional arguments for MATTER_LOG_METRIC_XYZ macros
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility to always return the 4th argument from macro parameters
#define __GET_4TH_ARG(_a1, _a2, _a3, _a4, ...) _a4
// Utility macro to select the macro with the correct signature based on the invoked MATTER_LOG_METRIC_XYZ macro
#define __SELECT_MACRO_FOR_EVENT_METRIC(...) \
__GET_4TH_ARG(__VA_ARGS__, __MATTER_LOG_METRIC_3ARGS, __MATTER_LOG_METRIC_2ARGS, __MATTER_LOG_METRIC_1ARGS, )
// Wrapper to capture all arguments and invoke the real wrapper for logging metrics
#define __MATTER_LOG_METRIC(...) __SELECT_MACRO_FOR_EVENT_METRIC(__VA_ARGS__)(__VA_ARGS__)
// Wrapper macro that accepts metric key and logs and instant event
#define __MATTER_LOG_METRIC_1ARGS(key) \
do \
{ \
using Type = chip::Tracing::MetricEvent::Type; \
::chip::Tracing::MetricEvent _metric_event(Type::kInstantEvent, key); \
::chip::Tracing::Internal::LogMetricEvent(_metric_event); \
} while (false)
// Wrapper macro that accepts metric type and key and logs an event corresponding to the type
#define __MATTER_LOG_METRIC_2ARGS(type, key) \
do \
{ \
::chip::Tracing::MetricEvent _metric_event(type, key); \
::chip::Tracing::Internal::LogMetricEvent(_metric_event); \
} while (false)
// Wrapper macro that accepts metric type, key and value and logs the corresponding event
#define __MATTER_LOG_METRIC_3ARGS(type, key, value) \
do \
{ \
::chip::Tracing::MetricEvent _metric_event(type, key, value); \
::chip::Tracing::Internal::LogMetricEvent(_metric_event); \
} while (false)
////////////////////////
// Metric logging macros
////////////////////////
/**
* @def MATTER_LOG_METRIC
*
* @brief
* When tracing is enabled, this macro generates a metric event and logs it to the tracing backend.
*
* Example usage:
* @code
* MATTER_LOG_METRIC(chip::Tracing::kMetricPASESession, err);
* @endcode
* The above example generates an instant metric event with key kMetricPASESession.
* The metric also holds the 32 bit value corresponding to the ChipError object 'err'.
*
* @param[in] key The key representing the metric name/event.
*
* @param[in] value An optional value for the metric. This value corresponds to one of the values supported
* in MetricEvent::Value
*/
#define MATTER_LOG_METRIC(key, ...) __MATTER_LOG_METRIC(chip::Tracing::MetricEvent::Type::kInstantEvent, key, ##__VA_ARGS__)
/**
* @def MATTER_LOG_METRIC_BEGIN
*
* @brief
* Generate a metric with the Begin Type
*
* Example usage:
* @code
* MATTER_LOG_METRIC_BEGIN(chip::Tracing::kMetricPASESession);
* @endcode
* The above example generates a Begin metric event with key kMetricPASESession.
*
* @param[in] key The key representing the metric name/event.
*/
#define MATTER_LOG_METRIC_BEGIN(key) __MATTER_LOG_METRIC(chip::Tracing::MetricEvent::Type::kBeginEvent, key)
/**
* @def MATTER_LOG_METRIC_END
*
* @brief
* Generate a metric with the End Type
*
* Example usage:
* @code
* MATTER_LOG_METRIC_END(chip::Tracing::kMetricPASESession);
* @endcode
* The above example generates an End metric event with key kMetricPASESession.
*
* @param[in] key The key representing the metric name/event.
*
* @param[in] value An optional value for the metric. This value corresponds to one of the values supported
* in MetricEvent::Value
*/
#define MATTER_LOG_METRIC_END(key, ...) __MATTER_LOG_METRIC(chip::Tracing::MetricEvent::Type::kEndEvent, key, ##__VA_ARGS__)
/**
* @def MATTER_LOG_METRIC_SCOPE
*
* @brief
* Generate a scoped metric tracking Begin and End within a given scope.
*
* Example usage:
* @code
* MATTER_LOG_METRIC_SCOPE(chip::Tracing::kMetricPASESession);
* @endcode
* The above example generates an Begin and the End metric using RAII.
*
* @param[in] key The key representing the metric name/event.
* @param[in] error Reference to a ChipError object that is used as the value of the End event.
*/
#define MATTER_LOG_METRIC_SCOPE(key, error) \
::chip::Tracing::ScopedMetricEvent __LOG_METRIC_MACRO_CONCAT(_metric_scope, __COUNTER__)(key, error)
#else // Tracing is disabled
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Remap Success, Return, and Verify macros to the ones without metrics
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define ReturnErrorOnFailureWithMetric(kMetricKey, expr) ReturnErrorOnFailure(expr)
#define ReturnLogErrorOnFailureWithMetric(kMetricKey, expr) ReturnLogErrorOnFailure(expr)
#define ReturnOnFailureWithMetric(kMetricKey, expr) ReturnOnFailure(expr)
#define VerifyOrReturnWithMetric(kMetricKey, expr, ...) VerifyOrReturn(expr, ##__VA_ARGS__)
#define VerifyOrReturnErrorWithMetric(kMetricKey, expr, code, ...) VerifyOrReturnError(expr, code, ##__VA_ARGS__)
#define VerifyOrReturnValueWithMetric(kMetricKey, expr, value, ...) VerifyOrReturnValue(expr, value, ##__VA_ARGS__)
#define VerifyOrReturnLogErrorWithMetric(kMetricKey, expr, code) VerifyOrReturnLogError(expr, code)
#define SuccessOrExitWithMetric(kMetricKey, aStatus) SuccessOrExit(aStatus)
#define VerifyOrExitWithMetric(kMetricKey, aCondition, anAction) VerifyOrExit(aCondition, anAction)
#define ExitNowWithMetric(kMetricKey, ...) ExitNow(##__VA_ARGS__)
#define LogErrorOnFailureWithMetric(kMetricKey, expr) LogErrorOnFailure(expr)
#define VerifyOrDoWithMetric(kMetricKey, expr, code, ...) VerifyOrDo(expr, ##__VA_ARGS__)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Map all MATTER_LOG_METRIC_XYZ macros to noops
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define __MATTER_LOG_METRIC_DISABLE(...) \
do \
{ \
} while (false)
#define MATTER_LOG_METRIC(...) __MATTER_LOG_METRIC_DISABLE(__VA_ARGS__)
#define MATTER_LOG_METRIC_BEGIN(...) __MATTER_LOG_METRIC_DISABLE(__VA_ARGS__)
#define MATTER_LOG_METRIC_END(...) __MATTER_LOG_METRIC_DISABLE(__VA_ARGS__)
#define MATTER_LOG_METRIC_SCOPE(...) __MATTER_LOG_METRIC_DISABLE(__VA_ARGS__)
#endif // MATTER_TRACING_ENABLED