/**
* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef LOG_H
#define LOG_H
#include <iostream>
#include <sstream>
#include <sys/syscall.h>
#include <unistd.h>
#include <securec.h>
#include <dlog_pub.h>
#include "hccl/base.h"
namespace Hccl {
#ifndef T_DESC
#define T_DESC(_msg, _y) ((_y) ? true : false)
#endif
#if T_DESC("日志处理适配", true)
constexpr u32 HCCL_LOG_DEBUG = 0x0;
constexpr u32 HCCL_LOG_INFO = 0x1;
constexpr u32 HCCL_LOG_WARN = 0x2;
constexpr u32 HCCL_LOG_ERROR = 0x3;
constexpr u32 HCCL_LOG_OPLOG = 0x6;
constexpr u32 HCCL_LOG_RUN_INFO = 0xff;
enum class HcclSubModuleID {
LOG_SUB_MODULE_ID_HCCL = 0,
LOG_SUB_MODULE_ID_HCOM = 1,
};
/* 设置日志的commid和rankid */
#ifndef LIKELY
#define LIKELY(x) (static_cast<bool>(__builtin_expect(static_cast<bool>(x), 1)))
#define UNLIKELY(x) (static_cast<bool>(__builtin_expect(static_cast<bool>(x), 0)))
#endif
/* 每一条日志的长度,超过该长度会申请堆内存 */
constexpr s32 LOG_TMPBUF_SIZE = 512;
void CallDlogInvalidType(int level, int errCode, std::string file, int line);
void CallDlogNoSzFormat(int level, int errCode, std::string file, int line);
void CallDlogMemError(int level, std::string file, int line);
void CallDlogPrintError(int level, std::string file, int line);
void CallDlog(int level, int sysCallBack, const char *buffer, std::string file, int line);
bool CheckDebugLogLevel();
bool CheckInfoLogLevel();
int HcclCheckLogLevel(int logLevel);
#define LOG_FUNC(moudle, level, fmt, ...) do { \
DlogRecord(moudle, level, fmt, ##__VA_ARGS__); \
} while (0)
#define LOG_PRINT(logType, szFormat, ...) \
do { \
if (UNLIKELY(HcclCheckLogLevel(logType) == 1)) { \
char stackLogBuffer[LOG_TMPBUF_SIZE]; /* 使用栈中的buffer, 小而快 */ \
if (szFormat == nullptr) { \
CallDlogNoSzFormat(HCCL_LOG_ERROR, HCCL_ERROR_CODE(HcclResult::HCCL_E_INTERNAL), __FILE__, __LINE__); \
} else { \
if (memset_s(stackLogBuffer, LOG_TMPBUF_SIZE, 0, sizeof(stackLogBuffer)) != EOK) { \
CallDlogMemError(HCCL_LOG_ERROR, __FILE__, __LINE__); \
} else if ((snprintf_s(stackLogBuffer, sizeof(stackLogBuffer), (sizeof(stackLogBuffer) - 1), szFormat, \
##__VA_ARGS__) \
== -1) \
&& (stackLogBuffer[0] == 0)) { \
CallDlogPrintError(HCCL_LOG_ERROR, __FILE__, __LINE__); \
} else { \
/* 如果collectiveID和rankID都为空,则默认输出为PID和TID */ \
CallDlog(logType, syscall(SYS_gettid), stackLogBuffer, __FILE__, __LINE__); \
} \
} \
} \
} while (0)
/* 当前日志级别,为了优化性能,日志EVENT 判断在宏入口检查 */
/* 使用宏记录日志, 以便获取日志在代码中的位置 */
#define MODULE_DEBUG(format, ...) \
do { \
LOG_PRINT(HCCL_LOG_DEBUG, format, ##__VA_ARGS__); \
} while (0)
#define MODULE_INFO(format, ...) \
do { \
LOG_PRINT(HCCL_LOG_INFO, format, ##__VA_ARGS__); \
} while (0)
#define MODULE_WARNING(format, ...) \
do { \
LOG_PRINT(HCCL_LOG_WARN, format, ##__VA_ARGS__); \
} while (0)
#define MODULE_ERROR(format, ...) \
do { \
LOG_PRINT(HCCL_LOG_ERROR, format, ##__VA_ARGS__); \
} while (0)
/* 运行日志,记录在run目录下 */
#define MODULE_RUN_INFO(format, ...) \
do { \
LOG_PRINT(HCCL_LOG_RUN_INFO, format, ##__VA_ARGS__); \
} while (0)
// 错误码
const u64 SYSTEM_RESERVE_ERROR = 0;
const u64 HCCL_MODULE_ID = 5;
/* 预定义日志宏, 便于使用 */
#define HCCL_DEBUG(...) MODULE_DEBUG(__VA_ARGS__)
#define HCCL_INFO(...) MODULE_INFO(__VA_ARGS__)
#define HCCL_WARNING(...) MODULE_WARNING(__VA_ARGS__)
#define HCCL_ERROR(...) MODULE_ERROR(__VA_ARGS__)
/* 运行日志 */
#define HCCL_RUN_INFO(...) MODULE_RUN_INFO(__VA_ARGS__)
#define HCCL_ERROR_CODE(error) \
((SYSTEM_RESERVE_ERROR << 32) + (HCCL_MODULE_ID << 24) \
+ ((static_cast<u64>(HcclSubModuleID::LOG_SUB_MODULE_ID_HCCL)) << 16) + static_cast<u64>(error))
#define HCOM_ERROR_CODE(error) \
((SYSTEM_RESERVE_ERROR << 32) + (HCCL_MODULE_ID << 24) \
+ ((static_cast<u64>(HcclSubModuleID::LOG_SUB_MODULE_ID_HCOM)) << 16) + static_cast<u64>(error))
#endif
#if T_DESC("公共代码宏", true)
// 检查C++11的智能指针, 若为空, 则记录日志, 并返回错误
#define CHK_SMART_PTR_NULL(smart_ptr) \
do { \
if (UNLIKELY(!(smart_ptr))) { \
HCCL_ERROR("[%s]errNo[0x%016llx] ptr [%s] is nullptr, return HCCL_E_PTR", \
__func__, HCCL_ERROR_CODE(HCCL_E_PTR), \
#smart_ptr); \
return HCCL_E_PTR; \
} \
} while (0)
/* 检查函数返回值, 记录指定日志, 并返回指定错误码 */
#define CHK_PRT_RET(result, exeLog, retCode) \
do { \
if (UNLIKELY(result)) { \
exeLog; \
return retCode; \
} \
} while (0)
/* 检查函数返回值, 记录指定日志, 并直接返回 */
#define CHK_PRT_RET_NULL(result, exeLog) \
do { \
if (UNLIKELY(result)) { \
exeLog; \
return; \
} \
} while (0)
/* 检查函数返回值, 记录指定日志, 函数不返回 */
#define CHK_PRT_CONT(result, exeLog) \
do { \
if (UNLIKELY(result)) { \
exeLog; \
} \
} while (0)
// 检查C++11的智能指针, 若为空, 则记录日志, 并返回
#define CHK_SMART_PTR_RET_NULL(smart_ptr) \
do { \
if (UNLIKELY(!(smart_ptr))) { \
HCCL_ERROR("[%s]errNo[0x%016llx]smart_ptr is nullptr.", \
__func__, HCCL_ERROR_CODE(HCCL_E_PTR)); \
return; \
} \
} while (0)
/* 检查函数返回值, 并返回指定错误码 */
#define CHK_RET(call) \
do { \
HcclResult hcclRet = (HcclResult)(call); \
if (UNLIKELY(hcclRet != HcclResult::HCCL_SUCCESS)) { \
if (hcclRet == HcclResult::HCCL_E_AGAIN) { \
HCCL_WARNING("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} else { \
HCCL_ERROR("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} \
return hcclRet; \
} \
} while (0)
/* 检查result. 若错误, 则设置错误并break */
#define CHK_PRT_BREAK(result, exeLog, exeCmd) \
if (UNLIKELY(result)) { \
exeLog; \
exeCmd; \
break; \
}
/* 检查函数返回值,HCCL_E_UNAVAIL时给Warning, 并返回指定错误码 */
#define CHK_RET_UNAVAIL(call) \
do { \
HcclResult hcclRet = (HcclResult)(call); \
if (UNLIKELY(hcclRet != HcclResult::HCCL_SUCCESS)) { \
if (hcclRet == HcclResult::HCCL_E_AGAIN || hcclRet == HcclResult::HCCL_E_UNAVAIL) { \
HCCL_WARNING("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} else { \
HCCL_ERROR("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} \
return hcclRet; \
} \
} while (0)
/* 检查指针, 若指针为NULL, 则记录日志, 并返回错误 */
#define CHK_PTR_NULL(ptr) \
do { \
if (UNLIKELY((ptr) == nullptr)) { \
HCCL_ERROR("errNo[0x%016llx] ptr [%s] is NULL, return HcclResult::HCCL_E_PTR", \
HCCL_ERROR_CODE(HcclResult::HCCL_E_PTR), #ptr); \
return HcclResult::HCCL_E_PTR; \
} \
} while (0)
/* 检查函数返回值, 返错时打印函数名及通信域标识 */
#define CHK_RET_AND_PRINT_IDE(call, identifier) \
do { \
HcclResult hcclRet = (HcclResult)(call); \
if (UNLIKELY(hcclRet != HCCL_SUCCESS)) { \
HCCL_RUN_INFO("[HCCL_TRACE]%s identifier[%s]", __func__, identifier); \
if (hcclRet == HCCL_E_AGAIN) { \
HCCL_WARNING("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} else { \
HCCL_ERROR("[%s]call trace: hcclRet -> %d", __func__, hcclRet); \
} \
return hcclRet; \
} \
} while (0)
/* 检查函数返回值, 并返回HCCL_E_INTERNAL错误码 */
#define CHK_SAFETY_FUNC_RET(call) \
do { \
s32 ret = call; \
if (UNLIKELY(ret != EOK)) { \
HCCL_ERROR("[%s]call trace: safety func err ret -> %d", __func__, ret); \
return HCCL_E_INTERNAL; \
} \
} while (0)
#define EXCEPTION_CATCH(expression, retExp) \
do { \
try { \
expression; \
} catch (HcclException & e) { \
HCCL_ERROR("[%s]Failed, exception caught:%s", __func__, e.what()); \
auto backTraces = e.GetBackTraceStrings(); \
std::for_each(backTraces.begin(), backTraces.end(), [](string item) { \
HCCL_ERROR(item.c_str()); \
}); \
retExp; \
} catch (std::exception & e) { \
HCCL_ERROR("[%s]Failed, exception caught:%s", __func__, e.what()); \
retExp; \
} catch (...) { \
HCCL_ERROR("exception caught others"); \
retExp; \
} \
} while (0)
#endif
} // namespace Hccl
#endif // HCCLV2_LOG_H