* 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.
*/
#include <securec.h>
#include <stdint.h>
#include <syslog.h>
#include <stdio.h>
#include <string>
#include <sys/time.h>
#include "hccl_common.h"
#include "slog.h"
#include "slog_api.h"
using namespace std;
static s32 stub_log_level = DLOG_ERROR;
static s32 stub_checker_level = DLOG_ERROR;
constexpr s32 LOG_TIME_STAMP_SIZE = 27;
constexpr u32 TIME_FROM_1900 = 1900;
void initLogLevel() __attribute__((constructor));
#define HUAWEI_SECC_RET_CHECK_AND_RETURN(ret) do { \
switch (ret) { \
case EOK: \
return HCCL_SUCCESS; \
case EINVAL: \
return HCCL_E_PARA; \
default: \
return HCCL_E_INTERNAL; \
} \
} while (0)
#define HUAWEI_SECC_RET_TRANSFORM(ret) ((ret == EOK) ? HCCL_SUCCESS : ((ret == EINVAL) ? HCCL_E_PARA : HCCL_E_INTERNAL))
int CheckLogLevel(int moduleId, int logLevel)
{
(void)moduleId;
(void)logLevel;
return 1;
}
s32 log_level_get_stub() {
return stub_log_level;
}
void log_level_set_stub(s32 log_level) {
stub_log_level = log_level;
}
int32_t dlog_setlevel(int32_t moduleId, int32_t level, int32_t enableEvent)
{
stub_checker_level = level;
return 0;
}
HcclResult sal_get_current_time(char *timeStr, u32 len)
{
struct timeval tv;
time_t tmpt;
struct tm *now;
if (timeStr == NULL) {
return HCCL_E_PARA;
}
if (0 > gettimeofday(&tv, NULL)) {
return HCCL_E_INTERNAL;
}
tmpt = (time_t)tv.tv_sec;
now = localtime(&tmpt);
if (now == NULL) {
return HCCL_E_INTERNAL;
}
int iLen = snprintf_s(timeStr, len, len, "%04d-%02d-%02d %02d:%0d:%02d.%06u",\
now->tm_year + TIME_FROM_1900,
now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, (u32)tv.tv_usec);
if (iLen == -1) {
HCCL_WARNING("Print time failed[%d]." \
"params: time[%s], len[%u], time_format:%04d-%02d-%02d %02d:%02d:%02d.%06u",\
iLen, timeStr, len, now->tm_year + TIME_FROM_1900, now->tm_mon + 1, now->tm_mday,
now->tm_hour, now->tm_min, now->tm_sec, (u32)tv.tv_usec);
}
return HCCL_SUCCESS;
}
string get_log_str_from_type_stub(s32 type)
{
string str = "";
switch (type) {
case DLOG_DEBUG:
str = "[DEBUG]";
break;
case DLOG_INFO:
str = "[INFO]";
break;
case DLOG_WARN:
str = "[WARNING]";
break;
case DLOG_ERROR:
str = "[ERROR]";
break;
case DLOG_EVENT:
str = "[EVENT]";
break;
default:
break;
}
return str;
}
HcclResult sal_memset(void *dest, size_t destMaxSize, int c, size_t count)
{
CHK_PTR_NULL(dest);
s32 ret = memset_s(dest, destMaxSize, c, count);
if (ret != EOK) {
HCCL_ERROR("errNo[0x%016llx] In sal_memset, memset_s failed. errorno[%d], params: dest[%p], "\
"destMaxSize[%d], c[%d], count[%d]", HCCL_ERROR_CODE(HUAWEI_SECC_RET_TRANSFORM(ret)), ret, dest, \
destMaxSize, c, count);
}
HUAWEI_SECC_RET_CHECK_AND_RETURN(ret);
}
void sal_dlog_printf_stub(int level,char* log_buffer)
{
char time_stamp[LOG_TIME_STAMP_SIZE] = {0};
(void)sal_memset(time_stamp, LOG_TIME_STAMP_SIZE, 0, sizeof(time_stamp));
(void)sal_get_current_time(time_stamp, LOG_TIME_STAMP_SIZE);
string str_type= get_log_str_from_type_stub(level);
printf("[%-26s][pid:%u]%s%s\n", time_stamp, getpid(), str_type.c_str(), log_buffer);
}
void DlogRecord(int moduleId, int level, const char *fmt, ...)
{
if((moduleId == HCCL && level < stub_log_level) || (moduleId != HCCL && level < stub_checker_level)){
return;
}
char stack_log_buffer[LOG_TMPBUF_SIZE];
va_list arg;
(void)va_start(arg, fmt);
(void)sal_memset(stack_log_buffer, LOG_TMPBUF_SIZE, 0, sizeof(stack_log_buffer));
C库标准的vsnprintf()函数在字符串超出缓存长度后返回需要的缓存空间.
公司的安全函数库包装后的vsnprintf_s()在字符串超出缓存长度后返回值为-1, 无法根据返回值重新申请堆内存.
*/
vsnprintf_s(stack_log_buffer, sizeof(stack_log_buffer), (sizeof(stack_log_buffer) - 1), fmt, arg);
va_end(arg);
sal_dlog_printf_stub(level, stack_log_buffer);
}
void DlogInner(int moduleId, int level, const char *fmt, ...)
{
if((moduleId == HCCL && level < stub_log_level) || (moduleId != HCCL && level < stub_checker_level)){
return;
}
char stack_log_buffer[LOG_TMPBUF_SIZE];
va_list arg;
(void)va_start(arg, fmt);
(void)sal_memset(stack_log_buffer, LOG_TMPBUF_SIZE, 0, sizeof(stack_log_buffer));
C库标准的vsnprintf()函数在字符串超出缓存长度后返回需要的缓存空间.
公司的安全函数库包装后的vsnprintf_s()在字符串超出缓存长度后返回值为-1, 无法根据返回值重新申请堆内存.
*/
vsnprintf_s(stack_log_buffer, sizeof(stack_log_buffer), (sizeof(stack_log_buffer) - 1), fmt, arg);
va_end(arg);
sal_dlog_printf_stub(level, stack_log_buffer);
}
void initLogLevel()
{
auto setLogEnv = [](const char* env, s32& log_level) {
char *env_var = getenv(env);
if (env_var) {
if(strlen(env_var) > 1 || env_var[0] < '0' || env_var[0] > '3')
{
return;
}
log_level = static_cast<s32>(atoi(env_var));
printf("Environment variable %s is set to: %d\n", env, log_level);
}
};
setLogEnv("ASCEND_LOG_LEVEL", stub_log_level);
setLogEnv("CHECK_LOG_LEVEL", stub_checker_level);
}