* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* CBB is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* 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 FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* cm_log.c
*
*
* IDENTIFICATION
* src/cm_utils/cm_log.c
*
* -------------------------------------------------------------------------
*/
#include "cm_log.h"
#include "cm_file.h"
#include "cm_date.h"
#include "cm_thread.h"
#include "cm_timer.h"
#include "cm_hash.h"
#include "cm_atomic.h"
#include "cm_date.h"
#include "zlib.h"
#ifndef _WIN32
#include <dirent.h>
#include <execinfo.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define CM_INVALID_FD (-1)
bool32 g_high_frequency_restart_process = CM_FALSE;
static log_file_handle_t g_logger[LOG_COUNT] = {
[LOG_RUN] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_DEBUG] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_ALARM] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_AUDIT] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_OPER] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_MEC] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_TRACE] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_PROFILE] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_BLACKBOX] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_DMS_EVT_TRC] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_DMS_RFM_TRC] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
[LOG_DYNAMIC] = {
.file_handle = CM_INVALID_FD,
.file_inode = 0 },
};
#define MAX_THREAD_NUM_COUNT 1000
#define MAX_LOG_SUPPRESS_COUNT 128
#define LOG_SUPPRESS_TIMEOUT (int32)(5 * 60 * MICROSECS_PER_SECOND)
#define LOG_SUPPRESS_TIME_THRESHOLD (int32)(1 * MICROSECS_PER_SECOND)
#define LOG_SUPPRESS_MAX_COUNT 10
#define MAX_LOG_SUPPRESS_EXPIRED_TIME (int32)(2 * LOG_SUPPRESS_TIMEOUT)
#define CM_FILENAME_FORMAT_DEFAULT 0
#define CM_FILENAME_FORMAT_SEPARATED 1
#define CM_MAX_LENGTH 64
typedef enum en_log_suppress_status {
LOG_NORMAL = 0,
LOG_SUPPRESS,
LOG_SUPPRESS_TMOUT,
LOG_SUPPRESS_BEGIN,
LOG_SUPPRESS_END,
LOG_SUPPRESS_STATUS_CEIL
} log_suppress_status;
typedef struct st_log_suppress {
int64 print_time;
int32 count;
log_suppress_status suppress_status;
uint32 line;
log_type_t type;
char name[CM_FILE_NAME_BUFFER_SIZE];
bool8 is_used;
} log_suppress_t;
typedef struct st_log_suppress_entry {
log_suppress_t log_suppress[MAX_LOG_SUPPRESS_COUNT];
uint32 thread_id;
} log_suppress_entry_t;
static thread_local_var uint32 g_thrd_log_suppress_id = 0;
static const char *g_log_suppress_status_str[LOG_SUPPRESS_STATUS_CEIL] = {
[LOG_NORMAL] = "",
[LOG_SUPPRESS] = "",
[LOG_SUPPRESS_TMOUT] = "LOG_SUPPRESS>",
[LOG_SUPPRESS_BEGIN] = "LOG_SUPPRESS_BEGIN>",
[LOG_SUPPRESS_END] = "LOG_SUPPRESS_END>"
};
static log_suppress_entry_t *g_log_suppress_array = NULL;
static spinlock_t g_log_suppress_lock;
log_file_handle_t *cm_log_logger_file(uint32 log_count)
{
return &g_logger[log_count];
}
static log_param_t g_log_param = {0};
inline log_param_t *cm_log_param_instance(void)
{
return &g_log_param;
}
status_t cm_set_log_module_name(const char *module_name, int32 len)
{
if (len > CM_MAX_LOG_MODULE_NAME || len < 0) {
return CM_ERROR;
}
errno_t errcode;
log_param_t *log_param = cm_log_param_instance();
errcode = strncpy_s(log_param->log_module_name, CM_MAX_LOG_MODULE_NAME, module_name, len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return CM_ERROR;
}
return CM_SUCCESS;
}
static void cm_log_remove_file(const char *file_name)
{
(void)chmod(file_name, S_IRUSR | S_IWUSR | S_IXUSR);
(void)__unlink(file_name);
}
static int32 cm_log_convert_token(const char *src, char *dst, size_t len)
{
int32 count = 0;
if (src == NULL || dst == NULL) {
return 0;
}
size_t file_name_len = strlen(src);
if (file_name_len >= len) {
return 0;
}
if (strncpy_s(dst, len, src, file_name_len) != EOK) {
return 0;
}
char *psz = dst;
char *pszEnd = psz + strlen(dst);
while (psz < pszEnd) {
if (*psz == '\\') {
*psz = '/';
count++;
}
psz++;
}
return count;
}
static status_t cm_log_create_directory(const char *log_dir)
{
char tmp[CM_MAX_PATH_LEN] = {0};
char path_name[CM_MAX_PATH_LEN] = {0};
(void)cm_log_convert_token(log_dir, tmp, CM_MAX_PATH_LEN);
size_t len = strlen(tmp);
size_t count;
if (tmp[len - 1] != '/') {
tmp[len] = '/';
len++;
tmp[len] = '\0';
}
size_t lastPos = 0;
for (size_t i = 1; i < len; i++) {
if (tmp[i] == '/') {
count = i - lastPos;
MEMS_RETURN_IFERR(strncat_s(path_name, CM_MAX_PATH_LEN, &tmp[lastPos], (size_t)count));
lastPos = i;
if (make_dir(path_name, g_log_param.log_path_permissions) != 0 && errno != EEXIST && errno != EACCES) {
return CM_ERROR;
}
}
}
return CM_SUCCESS;
}
static void cm_log_get_dir(char *log_dir, uint32 buf_size, const char *file_name)
{
char *p = NULL;
size_t file_name_len = strlen(file_name);
MEMS_RETVOID_IFERR(strncpy_s(log_dir, buf_size, file_name, file_name_len));
p = strrchr(log_dir, '/');
if (p == NULL) {
return;
}
*p = '\0';
}
static void cm_log_chmod_dir(const char *log_dir, log_type_t log_type)
{
(void)chmod(log_dir, g_log_param.log_path_permissions);
if (log_type == LOG_ALARM) {
return;
}
char *p = strrchr(log_dir, '/');
if (p == NULL) {
return;
}
*p = '\0';
(void)chmod(log_dir, g_log_param.log_path_permissions);
}
static void cm_log_create_dir(const log_file_handle_t *log_file_handle)
{
char log_dir[CM_FILE_NAME_BUFFER_SIZE] = {0};
cm_log_get_dir(log_dir, CM_FILE_NAME_BUFFER_SIZE, log_file_handle->file_name);
(void)cm_log_create_directory((const char *)log_dir);
cm_log_chmod_dir(log_dir, log_file_handle->log_type);
}
static void cm_log_build_normal_head(char *buf, uint32 buf_size, log_level_t log_level, const char *module_name,
log_suppress_status suppress_status)
{
int tz;
char date[CM_MAX_TIME_STRLEN] = {0};
errno_t errcode;
const char *log_level_str = NULL;
switch (log_level) {
case LEVEL_ERROR:
log_level_str = "ERROR";
break;
case LEVEL_WARN:
log_level_str = "WARN";
break;
default:
log_level_str = "INFO";
break;
}
(void)cm_date2str(g_timer()->now, "yyyy-mm-dd hh24:mi:ss.ff3", date, CM_MAX_TIME_STRLEN);
tz = g_timer()->tz;
if (tz >= 0) {
errcode = snprintf_s(buf, (size_t)buf_size, CM_MAX_LOG_HEAD_LENGTH - 1, "UTC+%d %s|%s|%u|%s>%s", tz, date,
module_name, cm_get_current_thread_id(), log_level_str, g_log_suppress_status_str[suppress_status]);
} else {
errcode = snprintf_s(buf, (size_t)buf_size, CM_MAX_LOG_HEAD_LENGTH - 1, "UTC%d %s|%s|%u|%s>%s", tz, date,
module_name, cm_get_current_thread_id(), log_level_str, g_log_suppress_status_str[suppress_status]);
}
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
}
static void cm_log_close_file(log_file_handle_t *log_file_handle)
{
if (log_file_handle->file_handle != CM_INVALID_FD) {
(void)close(log_file_handle->file_handle);
log_file_handle->file_handle = CM_INVALID_FD;
log_file_handle->file_inode = 0;
}
}
static bool32 cm_log_stat_file(const log_file_handle_t *log_file_handle, uint64 *file_size, uint32 *file_inode)
{
struct stat st;
The value of the two output parameters is unpredictable when the function returns false,
so the file_size and file_inode are initialized to 0?
*/
*file_size = 0;
*file_inode = 0;
if (stat(log_file_handle->file_name, &st) != 0) {
return CM_FALSE;
}
*file_size = (uint64)st.st_size;
*file_inode = (uint32)st.st_ino;
return CM_TRUE;
}
The parameter bak_file_name is the backup file name that is currently searched.
for example, "zenith_20081104160845999.log"
The parameter log_file_name is the file name of the log file?for example, "zenith"
The parameter log_ext_name is the extension of the log file?for example, ".log"
*/
static bool32 is_backup_file(const char *bak_file_name, const char *log_file_name, const char *log_ext_name)
{
size_t log_file_name_len = strlen(log_file_name);
size_t log_ext_name_len = strlen(log_ext_name);
size_t bak_file_name_len = strlen(bak_file_name);
size_t timestamp_len = (g_log_param.log_filename_format == CM_FILENAME_FORMAT_SEPARATED)
? strlen("_yyyy-mm-dd_hhmissfff")
: strlen("_yyyymmddhhmissfff");
if (log_file_name_len + timestamp_len + log_ext_name_len + 1 != bak_file_name_len) {
return CM_FALSE;
}
if (strncmp(bak_file_name, log_file_name, (size_t)log_file_name_len) != 0) {
return CM_FALSE;
}
const char *bak_file_ext_name = bak_file_name + log_file_name_len + timestamp_len + 1;
if (strcmp(bak_file_ext_name, log_ext_name) != 0) {
return CM_FALSE;
}
const char *timestamp = bak_file_name + log_file_name_len;
if (timestamp[0] != '_') {
return CM_FALSE;
}
for (unsigned int i = 1; i < timestamp_len; i++) {
if (g_log_param.log_filename_format == CM_FILENAME_FORMAT_SEPARATED
&& (timestamp[i] == '-' || timestamp[i] == '_')) {
continue;
}
if (timestamp[i] < '0' || timestamp[i] > '9') {
return CM_FALSE;
}
}
return CM_TRUE;
}
static bool32 cm_log_compare_file(const char *left_file_name, const char *right_file_name)
{
struct stat left_file_stat;
struct stat right_file_stat;
if (stat(left_file_name, &left_file_stat) != 0) {
return CM_FALSE;
}
if (stat(right_file_name, &right_file_stat) != 0) {
return CM_TRUE;
}
if (left_file_stat.st_mtime == right_file_stat.st_mtime) {
return (strcmp(left_file_name, right_file_name) > 0);
}
return left_file_stat.st_mtime > right_file_stat.st_mtime;
}
static status_t cm_log_add_backup_file(char *backup_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 *backup_file_count, const char *log_dir, const char *bak_file)
{
uint32 i, j;
bool32 need_insert = CM_TRUE;
errno_t errcode;
char *file_name = (char *)cm_malloc_prot(CM_FILE_NAME_BUFFER_SIZE);
if (file_name == NULL) {
CM_THROW_ERROR(ERR_MALLOC_BYTES_MEMORY, CM_FILE_NAME_BUFFER_SIZE);
return CM_ERROR;
}
errcode = snprintf_s(file_name, CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s/%s", log_dir, bak_file);
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_FREE_PROT_PTR(file_name);
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return CM_ERROR;
}
for (i = 0; i < *backup_file_count; ++i) {
if (cm_log_compare_file(backup_file_name[i], file_name)) {
break;
}
}
if (*backup_file_count == CM_MAX_LOG_FILE_COUNT_LARGER) {
if (i == 0) {
cm_log_remove_file(file_name);
CM_FREE_PROT_PTR(file_name);
need_insert = CM_FALSE;
} else {
cm_log_remove_file(backup_file_name[0]);
CM_FREE_PROT_PTR(backup_file_name[0]);
for (j = 0; j < (*backup_file_count - 1); ++j) {
backup_file_name[j] = backup_file_name[j + 1];
}
backup_file_name[j] = NULL;
i--;
}
} else {
(*backup_file_count)++;
}
if (need_insert) {
for (j = (*backup_file_count) - 1; j > i; j--) {
backup_file_name[j] = backup_file_name[j - 1];
}
backup_file_name[i] = file_name;
}
return CM_SUCCESS;
}
#ifdef _WIN32
static status_t cm_log_search_backup_file(char *backup_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 *backup_file_count, const char *log_dir, const char *log_file_name, const char *log_ext_name)
{
char bak_file_fmt[CM_FILE_NAME_BUFFER_SIZE] = {0};
WIN32_FIND_DATA data;
PRTS_RETURN_IFERR(snprintf_s(bak_file_fmt,
CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s/%s*.%s", log_dir, log_file_name, log_ext_name));
HANDLE handle = FindFirstFile(bak_file_fmt, &data);
if (handle == INVALID_HANDLE_VALUE) {
CM_THROW_ERROR(ERR_INVALID_DIR, bak_file_fmt);
return CM_ERROR;
}
do {
if (is_backup_file(data.cFileName, log_file_name, log_ext_name)) {
if (cm_log_add_backup_file(backup_file_name, backup_file_count, log_dir, data.cFileName) != CM_SUCCESS) {
FindClose(handle);
return CM_ERROR;
}
}
} while (FindNextFile(handle, &data));
FindClose(handle);
return CM_SUCCESS;
}
#else
static status_t cm_log_search_backup_file(char *backup_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 *backup_file_count, const char *log_dir, const char *file_name, const char *log_ext_name)
{
struct dirent *ent = NULL;
DIR *dir = opendir(log_dir);
if (dir == NULL) {
CM_THROW_ERROR(ERR_INVALID_DIR, log_dir);
return CM_ERROR;
}
ent = readdir(dir);
while (ent != NULL) {
if (is_backup_file(ent->d_name, file_name, log_ext_name)) {
if (cm_log_add_backup_file(backup_file_name, backup_file_count, log_dir, ent->d_name) != CM_SUCCESS) {
(void)closedir(dir);
return CM_ERROR;
}
}
ent = readdir(dir);
}
(void)closedir(dir);
return CM_SUCCESS;
}
#endif
static status_t cm_log_get_bak_file_list(char *backup_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 *backup_file_count, const char *log_file, bool32 need_compressed)
{
const char *log_dir = NULL;
const char *log_file_name = NULL;
const char *log_ext_name = NULL;
errno_t errcode;
for example , if log_file = "/home/enipcore/log/run/zenith.log"
then log_dir = "/home/enipcore/log/run", log_file_name = "zenith", log_ext_name = "log"
if need_compressed is true, then log_ext_name = "rlog.gz"
*/
char buf[CM_FILE_NAME_BUFFER_SIZE] = {0};
errcode = strncpy_s(buf, CM_FILE_NAME_BUFFER_SIZE, log_file, CM_MAX_FILE_NAME_LEN);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return CM_ERROR;
}
char *p = NULL;
p = strrchr(buf, '/');
if (p == NULL) {
CM_THROW_ERROR(ERR_INVALID_DIR, log_file);
return CM_ERROR;
}
*p = '\0';
log_dir = buf;
log_file_name = p + 1;
p = strrchr((char *)log_file_name, '.');
if (p == NULL) {
CM_THROW_ERROR(ERR_INVALID_DIR, log_file);
return CM_ERROR;
}
*p = '\0';
log_ext_name = p + 1;
char backup_log_ext_name[CM_FILE_NAME_BUFFER_SIZE] = { 0 };
if (need_compressed) {
PRTS_RETURN_IFERR(snprintf_s(backup_log_ext_name,
CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s.%s", log_ext_name, "gz"));
} else {
PRTS_RETURN_IFERR(snprintf_s(backup_log_ext_name,
CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s", log_ext_name));
}
return cm_log_search_backup_file(backup_file_name, backup_file_count, log_dir, log_file_name, backup_log_ext_name);
}
static void cm_log_remove_bak_file(char *backup_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 *remove_file_count,
uint32 backup_file_count,
uint32 need_backup_count)
{
uint32 i;
*remove_file_count = 0;
if (backup_file_count > need_backup_count) {
*remove_file_count = backup_file_count - need_backup_count;
}
for (i = 0; i < backup_file_count; ++i) {
if (i < *remove_file_count) {
cm_log_remove_file(backup_file_name[i]);
} else {
name of removed file will be freed after log */
CM_FREE_PROT_PTR(backup_file_name[i]);
}
}
}
static status_t cm_log_get_timestamp(char* timestamp, uint32 max_length)
{
errno_t errcode;
date_detail_t detail = g_timer()->detail;
if (g_log_param.log_filename_format == CM_FILENAME_FORMAT_DEFAULT) {
errcode = snprintf_s(timestamp, max_length, max_length - 1, "%4u%02u%02u%02u%02u%02u%03u",
detail.year, detail.mon, detail.day,
detail.hour, detail.min, detail.sec, detail.millisec);
} else if (g_log_param.log_filename_format == CM_FILENAME_FORMAT_SEPARATED) {
errcode = snprintf_s(timestamp, max_length, max_length - 1, "%4u-%02u-%02u_%02u%02u%02u%03u",
detail.year, detail.mon, detail.day,
detail.hour, detail.min, detail.sec, detail.millisec);
} else {
return CM_ERROR;
}
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return CM_ERROR;
}
return CM_SUCCESS;
}
static void cm_log_get_bak_file_name(const log_file_handle_t *log_file_handle, char *bak_file)
{
The name of the backup log?logFile.ext ==> logFile_yyyymmddhhmissff3.ext
Where logFile is the file name, ext is the file extension, and yyyymmddhhmissff3 is in milliseconds.
*/
char bak_file_name[CM_FILE_NAME_BUFFER_SIZE] = {0};
char ext_name[CM_MAX_LENGTH] = {0};
char timestamp[CM_MAX_LENGTH] = {0};
char *file_ext_name = NULL;
size_t name_len = CM_MAX_FILE_NAME_LEN;
errno_t errcode;
if (cm_log_get_timestamp(timestamp, CM_MAX_LENGTH) != CM_SUCCESS) {
return;
}
errcode = strncpy_s(bak_file_name, sizeof(bak_file_name), log_file_handle->file_name, (size_t)name_len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
Find the character '.' from the bak_file_name.
Because the log file name is generated inside the code, there must be a character '.'
*/
char *p = strrchr(bak_file_name, '.');
if (p == NULL) {
return;
}
*p = '\0';
file_ext_name = p + 1;
name_len = (uint32)strlen(file_ext_name);
errcode = strncpy_s(ext_name, sizeof(ext_name), file_ext_name, (size_t)name_len);
if (errcode != EOK) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
errcode = snprintf_s(bak_file, CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s_%s.%s", bak_file_name, timestamp,
ext_name);
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
}
1.Back up the current log file (ensure that the current log file has been turned off before backing up the file)
2.bak_file_name : all backup file name before transfer, 0 ~ remove_file_count need to be removed
3.new_bak_file_name : a new log file name dcf.rlog transferred to, for example dcf.rlog
*/
static status_t cm_rmv_and_bak_log_file(log_file_handle_t *log_file_handle,
char *bak_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
char new_bak_file_name[CM_FILE_NAME_BUFFER_SIZE],
uint32 *remove_file_count)
{
uint32 backup_file_count = 0;
uint64 file_size;
uint32 file_inode;
uint32 need_bak_file_count = log_file_handle->log_type == LOG_AUDIT ?
g_log_param.audit_backup_file_count : g_log_param.log_backup_file_count;
uint32 file_name_len = CM_MAX_FILE_NAME_LEN;
bool32 need_compressed = CM_FALSE;
if (need_bak_file_count == 0) {
cm_log_remove_file(log_file_handle->file_name);
bak_file_name[0] = (char *)cm_malloc_prot(CM_FILE_NAME_BUFFER_SIZE);
if (bak_file_name[0] == NULL) {
return CM_ERROR;
}
*remove_file_count = 1;
MEMS_RETURN_IFERR(strncpy_s(bak_file_name[0], CM_FILE_NAME_BUFFER_SIZE, log_file_handle->file_name,
(size_t)file_name_len));
return CM_SUCCESS;
}
if (cm_log_param_instance()->log_compressed) {
need_compressed = CM_TRUE;
}
CM_RETURN_IFERR(cm_log_get_bak_file_list(bak_file_name, &backup_file_count,
log_file_handle->file_name, need_compressed));
cm_log_remove_bak_file(bak_file_name, remove_file_count, backup_file_count, need_bak_file_count - 1);
cm_log_get_bak_file_name(log_file_handle, new_bak_file_name);
cm_log_remove_file(new_bak_file_name);
if (log_file_handle->log_type == LOG_OPER
&& cm_log_stat_file(log_file_handle, &file_size, &file_inode) == CM_TRUE) {
if (file_size < g_log_param.max_log_file_size) {
return CM_SUCCESS;
}
}
if (rename(log_file_handle->file_name, new_bak_file_name) == 0 &&
chmod(new_bak_file_name, g_log_param.log_bak_file_permissions) == 0) {
return CM_SUCCESS;
}
return CM_ERROR;
}
static inline int cm_log_open_flag(log_type_t log_type)
{
return O_RDWR | O_APPEND | O_CREAT;
}
void cm_log_open_file(log_file_handle_t *log_file_handle)
{
uint64 file_size;
uint32 file_inode;
log_file_handle->file_inode = 0;
log_file_handle->file_handle = CM_INVALID_FD;
cm_log_create_dir(log_file_handle);
int flags = cm_log_open_flag(log_file_handle->log_type);
int handle = open(log_file_handle->file_name, flags, g_log_param.log_file_permissions);
if (handle == CM_INVALID_FD) {
return;
}
(void)chmod(log_file_handle->file_name, g_log_param.log_file_permissions);
if (!cm_log_stat_file(log_file_handle, &file_size, &file_inode)) {
(void)close(handle);
return;
}
log_file_handle->file_handle = handle;
log_file_handle->file_inode = file_inode;
}
static void cm_write_log_file(log_file_handle_t *log_file_handle, char *buf, uint32 size)
{
if (log_file_handle->file_handle == CM_INVALID_FD) {
cm_log_open_file(log_file_handle);
}
if (log_file_handle->file_handle != CM_INVALID_FD && buf != NULL) {
if (log_file_handle->log_type != LOG_MEC && log_file_handle->log_type != LOG_BLACKBOX &&
log_file_handle->log_type != LOG_DMS_RFM_TRC && log_file_handle->log_type != LOG_DMS_EVT_TRC
&& log_file_handle->log_type != LOG_DYNAMIC) {
buf[size] = '\n';
size++;
}
if (write(log_file_handle->file_handle, buf, size) == -1) {
return;
}
}
}
static void cm_write_rmv_and_bak_file_log(char *bak_file_name[CM_MAX_LOG_FILE_COUNT_LARGER],
uint32 remove_file_count,
char curr_bak_file_name[CM_FILE_NAME_BUFFER_SIZE])
{
for (uint32 i = 0; i < remove_file_count; ++i) {
LOG_RUN_FILE_INF(CM_FALSE, "[LOG] file '%s' is removed", bak_file_name[i]);
}
if (strlen(curr_bak_file_name) != 0) {
LOG_RUN_FILE_INF(CM_FALSE, "[LOG] file '%s' is added", curr_bak_file_name);
}
}
static status_t compress_file_to_gzip(const char *infilename, const char *outfilename)
{
uint32 num_read = 0;
char *buffer = cm_log_param_instance()->log_compress_buf;
if (buffer == NULL) {
LOG_RUN_ERR("log_compress_buf is NULL");
return CM_ERROR;
}
uint32 buffer_len = CM_LOG_COMPRESS_BUFSIZE;
FILE *infile = fopen(infilename, "r");
if (NULL == infile) {
return CM_ERROR;
}
gzFile outfile = gzopen(outfilename, "wb9");
if (NULL == outfile) {
(void)fclose(infile);
return CM_ERROR;
}
while ((num_read = (uint32)fread(buffer, sizeof(char), buffer_len, infile)) > 0) {
if (gzwrite(outfile, buffer, num_read) == 0) {
(void)fclose(infile);
(void)gzclose(outfile);
return CM_ERROR;
}
}
if (feof(infile) == 0) {
(void)fclose(infile);
(void)gzclose(outfile);
return CM_ERROR;
}
(void)fclose(infile);
(void)gzclose(outfile);
errno_t rc = memset_s(buffer, buffer_len, 0, buffer_len);
if (rc != EOK) {
return CM_ERROR;
}
return CM_SUCCESS;
}
static void cm_compress_log_file(log_file_handle_t *log_file_handle, char *bak_file_name, uint32 file_name_len)
{
char new_bak_file_name[CM_FILE_NAME_BUFFER_SIZE];
if (!cm_log_param_instance()->log_compressed || !log_file_handle->log_compressed) {
return;
}
if (strlen(bak_file_name) == 0) {
return;
}
PRTS_RETVOID_IFERR(snprintf_s(new_bak_file_name,
CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s.%s", bak_file_name, "gz"));
if (compress_file_to_gzip(bak_file_name, new_bak_file_name) == CM_SUCCESS &&
chmod(new_bak_file_name, cm_log_param_instance()->log_bak_file_permissions) == 0 &&
cm_remove_file(bak_file_name) == CM_SUCCESS) {
return;
}
LOG_RUN_ERR("failed to rotate the log file:%s", bak_file_name);
return;
}
static void cm_stat_and_write_log(log_file_handle_t *log_file_handle, char *buf, uint32 size,
bool32 need_rec_filelog, cm_log_write_func_t func)
{
uint64 file_size = 0;
uint32 file_inode = 0;
uint32 timeout_ticks = 10000;
char new_bak_file_name[CM_FILE_NAME_BUFFER_SIZE];
char *bak_file_name[CM_MAX_LOG_FILE_COUNT_LARGER];
uint32 remove_file_count = 0;
int handle_before_log;
uint64 max_file_size;
new_bak_file_name[0] = '\0';
status_t ret = CM_SUCCESS;
if (LOG_DEBUG_INF_ON) {
timeout_ticks = 100000;
}
if (!cm_spin_timed_lock(&log_file_handle->lock, timeout_ticks)) {
return;
}
if (!cm_log_stat_file(log_file_handle, &file_size, &file_inode)) {
cm_log_close_file(log_file_handle);
}
if (file_inode != log_file_handle->file_inode) {
cm_log_close_file(log_file_handle);
}
max_file_size = log_file_handle->log_type == LOG_AUDIT ? g_log_param.max_audit_file_size :
g_log_param.max_log_file_size;
if ((file_size + 100 > max_file_size && need_rec_filelog == CM_TRUE)
1.reserve 2000 bytes in case of run log increasing continuously with backup file log
2.in case of dead loop when file_size larger than max_file_size + SIZE_K(2)
*/
|| (file_size < max_file_size + SIZE_K(3) && file_size > max_file_size + SIZE_K(2)
&& need_rec_filelog == CM_FALSE)) {
cm_log_close_file(log_file_handle);
ret = cm_rmv_and_bak_log_file(log_file_handle, bak_file_name, new_bak_file_name, &remove_file_count);
}
if (ret == CM_SUCCESS) {
handle_before_log = log_file_handle->file_handle;
func(log_file_handle, buf, size);
cm_spin_unlock(&log_file_handle->lock);
cm_compress_log_file(log_file_handle, new_bak_file_name, CM_FILE_NAME_BUFFER_SIZE);
cm_write_rmv_and_bak_file_log(bak_file_name, remove_file_count, new_bak_file_name);
if (handle_before_log == CM_INVALID_FD && log_file_handle->file_handle != CM_INVALID_FD &&
!g_high_frequency_restart_process) {
LOG_RUN_FILE_INF(CM_FALSE, "[LOG] file '%s' is added", log_file_handle->file_name);
}
} else {
cm_spin_unlock(&log_file_handle->lock);
}
for (uint32 i = 0; i < remove_file_count; ++i) {
CM_FREE_PROT_PTR(bak_file_name[i]);
}
}
static void cm_log_write_large_buf(const char *buf, bool32 need_rec_filelog, const char *format,
va_list ap, log_file_handle_t *log_file_hanle)
{
size_t log_head_len = strlen(buf);
va_list ap1;
errno_t errcode;
va_copy(ap1, ap);
char *pTmp = (char *)cm_malloc_prot(CM_MAX_LOG_NEW_BUFFER_SIZE);
if (pTmp == NULL) {
va_end(ap1);
return;
}
errcode = strncpy_s(pTmp, CM_MAX_LOG_NEW_BUFFER_SIZE, buf, log_head_len);
if (errcode != EOK) {
CM_FREE_PROT_PTR(pTmp);
va_end(ap1);
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return;
}
errcode = vsnprintf_s(pTmp + log_head_len, (size_t)(CM_MAX_LOG_NEW_BUFFER_SIZE - log_head_len),
(size_t)(CM_MAX_LOG_NEW_BUFFER_SIZE - log_head_len - 1), format, ap1);
va_end(ap1);
if (errcode >= 0) {
cm_stat_and_write_log(log_file_hanle, pTmp, (uint32)strlen(pTmp), need_rec_filelog, cm_write_log_file);
} else {
cm_stat_and_write_log(log_file_hanle, pTmp, (uint32)strlen(pTmp), need_rec_filelog, cm_write_log_file);
}
CM_FREE_PROT_PTR(pTmp);
}
static void cm_log_fulfil_write_buf(log_file_handle_t *log_file_handle, text_t *buf_text, uint32 buf_size,
bool32 need_rec_filelog, const char *format, va_list ap)
{
va_list ap1;
va_copy(ap1, ap);
int32 iRtn = vsnprintf_s(buf_text->str + buf_text->len, (size_t)(buf_size - buf_text->len),
(size_t)(buf_size - buf_text->len - 1), format, ap1);
va_end(ap1);
if (iRtn < 0) {
CM_NULL_TERM(buf_text);
cm_log_write_large_buf(buf_text->str, need_rec_filelog, format, ap, log_file_handle);
return;
}
cm_stat_and_write_log(log_file_handle, buf_text->str, (uint32)strlen(buf_text->str),
need_rec_filelog, cm_write_log_file);
}
static status_t get_log_suppress_mem(void)
{
if (g_log_suppress_array == NULL || g_thrd_log_suppress_id == MAX_THREAD_NUM_COUNT) {
return CM_ERROR;
}
if (g_log_suppress_array[g_thrd_log_suppress_id].thread_id == cm_get_current_thread_id()) {
return CM_SUCCESS;
}
cm_spin_lock(&g_log_suppress_lock, NULL);
for (uint32 i = 0; i < MAX_THREAD_NUM_COUNT; i++) {
if (g_log_suppress_array[i].thread_id == 0) {
g_log_suppress_array[i].thread_id = cm_get_current_thread_id();
g_thrd_log_suppress_id = i;
cm_spin_unlock(&g_log_suppress_lock);
return CM_SUCCESS;
}
}
cm_spin_unlock(&g_log_suppress_lock);
g_thrd_log_suppress_id = MAX_THREAD_NUM_COUNT;
return CM_ERROR;
}
static uint32 get_log_index(log_type_t log_type, const char *code_file_name, uint32 code_line_num)
{
if (get_log_suppress_mem() != CM_SUCCESS) {
return MAX_LOG_SUPPRESS_COUNT;
}
char buf[CM_FILE_NAME_BUFFER_SIZE + CM_MAX_NAME_LEN] = {0};
errno_t errcode = snprintf_s(buf, CM_FILE_NAME_BUFFER_SIZE + CM_MAX_NAME_LEN,
CM_FILE_NAME_BUFFER_SIZE + CM_MAX_NAME_LEN - 1,
"%u%s:%u", (uint32)log_type, code_file_name, code_line_num);
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return MAX_LOG_SUPPRESS_COUNT;
}
uint32 name_len = (uint32)strlen(buf);
uint32 name_hash_val = cm_hash_bytes((uint8 *)buf, name_len, name_len);
uint32 index = name_hash_val % MAX_LOG_SUPPRESS_COUNT;
for (uint32 i = index; i < MAX_LOG_SUPPRESS_COUNT + index; i++) {
uint32 index_tmp = i % MAX_LOG_SUPPRESS_COUNT;
log_suppress_t *suppress = &g_log_suppress_array[g_thrd_log_suppress_id].log_suppress[index_tmp];
if (!suppress->is_used) {
suppress->is_used = CM_TRUE;
suppress->line = code_line_num;
suppress->type = log_type;
suppress->count = 0;
suppress->print_time = g_timer()->now;
suppress->suppress_status = LOG_NORMAL;
errcode = strcpy_s(suppress->name, CM_FILE_NAME_BUFFER_SIZE, code_file_name);
if (SECUREC_UNLIKELY(errcode == -1)) {
CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return MAX_LOG_SUPPRESS_COUNT;
}
return index_tmp;
} else {
if (suppress->line == code_line_num &&
suppress->type == log_type &&
(strcmp(suppress->name, code_file_name) == 0)) {
return index_tmp;
}
}
}
return MAX_LOG_SUPPRESS_COUNT;
}
static inline bool32 is_log_match_suppress_rule(log_suppress_t *one_log_suppress)
{
bool8 need_suppress = CM_FALSE;
int64 time_diff = g_timer()->now - one_log_suppress->print_time;
if ((time_diff < LOG_SUPPRESS_TIME_THRESHOLD && one_log_suppress->count >= LOG_SUPPRESS_MAX_COUNT)) {
need_suppress = CM_TRUE;
}
if (time_diff > LOG_SUPPRESS_TIME_THRESHOLD) {
one_log_suppress->print_time = g_timer()->now;
one_log_suppress->count = 0;
}
return need_suppress;
}
static inline void clear_expired_suppress_status(log_suppress_t *one_log_suppress)
{
if (((g_timer()->now - one_log_suppress->print_time) > MAX_LOG_SUPPRESS_EXPIRED_TIME)) {
(void)memset_s(one_log_suppress, sizeof(log_suppress_t), 0, sizeof(log_suppress_t));
}
}
static log_suppress_status check_log_suppress(log_type_t log_type, const char *code_file_name, uint32 code_line_num)
{
uint32 index = get_log_index(log_type, code_file_name, code_line_num);
if (index == MAX_LOG_SUPPRESS_COUNT) {
return LOG_NORMAL;
}
log_suppress_t *log_suppress = &g_log_suppress_array[g_thrd_log_suppress_id].log_suppress[index];
switch (log_suppress->suppress_status) {
case LOG_NORMAL:
if (is_log_match_suppress_rule(log_suppress)) {
log_suppress->suppress_status = LOG_SUPPRESS_BEGIN;
} else {
log_suppress->count++;
}
break;
case LOG_SUPPRESS_BEGIN:
log_suppress->print_time = g_timer()->now + LOG_SUPPRESS_TIMEOUT;
log_suppress->count = 0;
log_suppress->suppress_status = LOG_SUPPRESS;
break;
case LOG_SUPPRESS_TMOUT:
if (log_suppress->count >=
LOG_SUPPRESS_MAX_COUNT * (LOG_SUPPRESS_TIMEOUT / LOG_SUPPRESS_TIME_THRESHOLD)) {
log_suppress->print_time = g_timer()->now + LOG_SUPPRESS_TIMEOUT;
log_suppress->count = 1;
log_suppress->suppress_status = LOG_SUPPRESS;
} else {
log_suppress->suppress_status = LOG_SUPPRESS_END;
}
break;
case LOG_SUPPRESS:
if (g_timer()->now > log_suppress->print_time) {
log_suppress->suppress_status = LOG_SUPPRESS_TMOUT;
}
log_suppress->count++;
break;
case LOG_SUPPRESS_END:
log_suppress->print_time = g_timer()->now;
log_suppress->count = 0;
log_suppress->is_used = CM_FALSE;
log_suppress->suppress_status = LOG_NORMAL;
break;
default:
break;
}
clear_expired_suppress_status(log_suppress);
return log_suppress->suppress_status;
}
void cm_write_normal_log_common(log_type_t log_type, log_level_t log_level, const char *code_file_name,
uint32 code_line_num, const char *module_name, bool32 need_rec_filelog, const char *format, va_list args)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + CM_MAX_LOG_HEAD_LENGTH + 2] = {0};
char new_format[CM_MAX_LOG_CONTENT_LENGTH] = {0};
log_file_handle_t *log_file_handle = &g_logger[log_type];
text_t buf_text;
log_param_t *log_param = cm_log_param_instance();
errno_t errcode;
errcode = snprintf_s(new_format, CM_MAX_LOG_CONTENT_LENGTH, CM_MAX_LOG_CONTENT_LENGTH - 1, "%s [%s:%u]",
format, code_file_name, code_line_num);
if (log_param->log_suppress_enable && (log_type == LOG_RUN || log_type == LOG_DEBUG)) {
cm_spin_lock(&log_param->lock, NULL);
(void)cm_atomic32_inc(&log_param->reference_count);
cm_spin_unlock(&log_param->lock);
log_suppress_status suppress_status = check_log_suppress(log_type, code_file_name, code_line_num);
(void)cm_atomic32_dec(&log_param->reference_count);
if (suppress_status == LOG_SUPPRESS) {
return;
}
cm_log_build_normal_head((char *)buf, sizeof(buf), log_level, module_name, suppress_status);
} else {
cm_log_build_normal_head((char *)buf, sizeof(buf), log_level, module_name, LOG_NORMAL);
}
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
if (errcode >= 0) {
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), need_rec_filelog, new_format, args);
} else {
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), need_rec_filelog, new_format, args);
}
}
void cm_write_normal_log(log_type_t log_type, log_level_t log_level, const char *code_file_name, uint32 code_line_num,
const char *module_name, bool32 need_rec_filelog, const char *format, ...)
{
va_list args;
va_start(args, format);
cm_write_normal_log_common(log_type, log_level, code_file_name, code_line_num, module_name, CM_TRUE, format, args);
va_end(args);
}
void cm_write_audit_log(const char *format, ...)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1] = {0};
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_AUDIT];
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = 0;
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
uint32 g_warn_id[] = {
WARN_FILEDESC_ID,
WARN_SSL_DIASBLED_ID,
};
char *g_warning_desc[] = {
"InsufficientDataInstFileDesc",
"SSLDisabled",
};
void cm_write_alarm_log_core(uint32 warn_id, uint32 *warn_id_set, char **warn_desc_set, const char *format,
va_list args)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + 2] = {0};
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_ALARM];
char date[CM_MAX_TIME_STRLEN] = {0};
errno_t errcode;
(void)cm_date2str(g_timer()->now, "yyyy-mm-dd hh24:mi:ss", date, CM_MAX_TIME_STRLEN);
errcode = snprintf_s(buf, sizeof(buf), CM_MAX_LOG_CONTENT_LENGTH + 1,
"%s|%u|%s|%s|%s|{'component-name':'%s','instance-name':'%s',", date,
warn_id_set[warn_id], warn_desc_set[warn_id], LOG_MODULE_NAME,
g_log_param.instance_name, LOG_MODULE_NAME, g_log_param.instance_name);
if (errcode < 0) {
return;
}
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
}
void cm_write_alarm_log(uint32 warn_id, const char *format, ...)
{
va_list args;
va_start(args, format);
cm_write_alarm_log_core(warn_id, g_warn_id, g_warning_desc, format, args);
va_end(args);
}
void cm_write_alarm_log_ex(uint32 warn_id, uint32 *warn_id_set, char **warn_desc_set, const char *format, ...)
{
va_list args;
va_start(args, format);
cm_write_alarm_log_core(warn_id, warn_id_set, warn_desc_set, format, args);
va_end(args);
}
void cm_write_oper_log(const char *format, ...)
{
if (!LOG_INITED || !LOG_OPER_ON) {
return;
}
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1] = {0};
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_OPER];
cm_log_build_normal_head((char *)buf, sizeof(buf), LEVEL_INFO, LOG_MODULE_NAME, LOG_NORMAL);
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
status_t cm_log_suppress_array_free(void)
{
log_param_t *log_param = cm_log_param_instance();
cm_spin_lock(&log_param->lock, NULL);
while (cm_atomic32_get(&log_param->reference_count) != 0) {
cm_sleep(CM_SLEEP_5_FIXED);
}
CM_FREE_PROT_PTR(g_log_suppress_array);
cm_spin_unlock(&log_param->lock);
return CM_SUCCESS;
}
status_t cm_log_suppress_array_alloc(void)
{
if (g_log_suppress_array != NULL) {
return CM_SUCCESS;
}
LOG_RUN_INF("[LOG]Start allocating memory for g_log_suppress_array");
log_suppress_entry_t* tem_log_suppress_array =
(log_suppress_entry_t *)cm_malloc_prot(MAX_THREAD_NUM_COUNT * sizeof(log_suppress_entry_t));
if (tem_log_suppress_array == NULL) {
LOG_RUN_ERR("[LOG]Memory allocation for g_log_suppress_array failed");
return CM_ERROR;
}
errno_t errcode = memset_s(tem_log_suppress_array,
MAX_THREAD_NUM_COUNT * sizeof(log_suppress_entry_t),
0,
MAX_THREAD_NUM_COUNT * sizeof(log_suppress_entry_t));
if (errcode != EOK) {
LOG_RUN_ERR("Secure C lib has thrown an error %d", errcode);
CM_FREE_PROT_PTR(tem_log_suppress_array);
return CM_ERROR;
}
g_log_suppress_array = tem_log_suppress_array;
LOG_RUN_INF("[LOG]Memory allocation for g_log_suppress_array succeeded");
return CM_SUCCESS;
}
status_t cm_log_suppress_array_verify(bool32 log_suppress_enable)
{
if (log_suppress_enable) {
CM_RETURN_IFERR(cm_log_suppress_array_alloc());
} else {
CM_RETURN_IFERR(cm_log_suppress_array_free());
}
return CM_SUCCESS;
}
status_t cm_log_init(log_type_t log_type, const char *file_name)
{
log_file_handle_t *log_file = &g_logger[log_type];
uint32 file_name_len = (uint32)strlen(file_name);
errno_t errcode;
GS_INIT_SPIN_LOCK(log_file->lock);
errcode = strncpy_s(log_file->file_name, CM_FULL_PATH_BUFFER_SIZE, file_name, (size_t)file_name_len);
if (errcode != EOK) {
LOG_DEBUG_ERR("[LOG]log init fail, log_type:%d file_name:%s", (int32)log_type, file_name);
return CM_ERROR;
}
log_file->file_handle = CM_INVALID_FD;
log_file->file_inode = 0;
log_file->log_type = log_type;
CM_RETURN_IFERR(cm_log_suppress_array_verify(cm_log_param_instance()->log_suppress_enable));
return CM_SUCCESS;
}
void cm_log_open_compress(log_type_t log_type, bool8 log_compressed)
{
log_file_handle_t *log_file = &g_logger[log_type];
log_file->log_compressed = log_compressed;
}
void cm_log_uninit(void)
{
(void)cm_log_suppress_array_free();
}
void cm_log_set_file_permissions(uint16 val)
{
uint16 usr_perm;
uint16 grp_perm;
uint16 oth_perm;
uint32 log_file_perm = 0;
uint32 log_bak_file_perm = 0;
usr_perm = (val / 100) % 10;
if (usr_perm & 1) {
log_file_perm |= S_IXUSR;
}
if (usr_perm & 2) {
log_file_perm |= S_IWUSR;
}
if (usr_perm & 4) {
log_file_perm |= S_IRUSR;
log_bak_file_perm |= S_IRUSR;
}
grp_perm = (val / 10) % 10;
if (grp_perm & 1) {
log_file_perm |= S_IXGRP;
log_bak_file_perm |= S_IXGRP;
}
if (grp_perm & 2) {
log_file_perm |= S_IWGRP;
}
if (grp_perm & 4) {
log_file_perm |= S_IRGRP;
log_bak_file_perm |= S_IRGRP;
}
oth_perm = val % 10;
if (oth_perm & 1) {
log_file_perm |= S_IXOTH;
log_bak_file_perm |= S_IXOTH;
}
if (oth_perm & 2) {
log_file_perm |= S_IWOTH;
}
if (oth_perm & 4) {
log_file_perm |= S_IROTH;
log_bak_file_perm |= S_IROTH;
}
g_log_param.log_bak_file_permissions = log_bak_file_perm;
g_log_param.log_file_permissions = log_file_perm;
}
void cm_log_set_path_permissions(uint16 val)
{
uint16 usr_perm;
uint16 grp_perm;
uint16 oth_perm;
uint32 log_path_perm = 0;
usr_perm = (val / 100) % 10;
if (usr_perm & 1) {
log_path_perm |= S_IXUSR;
}
if (usr_perm & 2) {
log_path_perm |= S_IWUSR;
}
if (usr_perm & 4) {
log_path_perm |= S_IRUSR;
}
grp_perm = (val / 10) % 10;
if (grp_perm & 1) {
log_path_perm |= S_IXGRP;
}
if (grp_perm & 2) {
log_path_perm |= S_IWGRP;
}
if (grp_perm & 4) {
log_path_perm |= S_IRGRP;
}
oth_perm = val % 10;
if (oth_perm & 1) {
log_path_perm |= S_IXOTH;
}
if (oth_perm & 2) {
log_path_perm |= S_IWOTH;
}
if (oth_perm & 4) {
log_path_perm |= S_IROTH;
}
g_log_param.log_path_permissions = log_path_perm;
}
static void cm_recovery_left_log_file(log_file_handle_t *log_file_handle, char *file_name)
{
char filename_gz[CM_FILE_NAME_BUFFER_SIZE] = {0};
PRTS_RETVOID_IFERR(snprintf_s(filename_gz, CM_FILE_NAME_BUFFER_SIZE, CM_MAX_FILE_NAME_LEN, "%s.%s", file_name, "gz"));
cm_log_remove_file(filename_gz);
cm_compress_log_file(log_file_handle, file_name, CM_FILE_NAME_BUFFER_SIZE);
return;
}
status_t cm_recovery_log_file(log_type_t log_type)
{
log_file_handle_t *log_file_handle = &g_logger[log_type];
char *left_file_name[CM_MAX_LOG_FILE_COUNT_LARGER];
uint32 left_file_count = 0;
CM_RETURN_IFERR(cm_log_get_bak_file_list(left_file_name, &left_file_count, log_file_handle->file_name, CM_FALSE));
if (left_file_count > 0) {
for (uint32 i = 0; i < left_file_count; i++) {
if (i >= CM_MAX_LOG_FILE_COUNT_LARGER) {
break;
}
if (left_file_name[i]) {
cm_recovery_left_log_file(log_file_handle, left_file_name[i]);
cm_log_remove_file(left_file_name[i]);
CM_FREE_PROT_PTR(left_file_name[i]);
}
}
}
return CM_SUCCESS;
}
void cm_fync_logfile(void)
{
#ifndef _WIN32
for (int i = 0; i < LOG_COUNT; i++) {
if (g_logger[i].file_handle != CM_INVALID_FD) {
(void)fsync(g_logger[i].file_handle);
cm_log_close_file(&g_logger[i]);
}
}
#endif
}
void cm_close_logfile(void)
{
for (uint32 i = 0; i < LOG_COUNT; i++) {
if (g_logger[i].file_handle == CM_INVALID_FD) {
cm_log_close_file(&g_logger[i]);
}
}
}
void cm_write_mec_log(const char *format, ...)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1] = {0};
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_MEC];
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
void cm_write_blackbox_log(const char *format, ...)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1] = {0};
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_BLACKBOX];
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
void cm_write_dynamic_log(const char *format, ...)
{
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1];
buf[0] = '\0';
text_t buf_text;
log_file_handle_t *log_file_handle = &g_logger[LOG_DYNAMIC];
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
static uint64 g_tracekey = (uint64)-1;
void set_trace_key(uint64 tracekey)
{
g_tracekey = tracekey;
}
uint64 get_trace_key(void)
{
return g_tracekey;
}
void unset_trace_key(void)
{
g_tracekey = (uint64)-1;
}
bool8 is_trace_key(uint64 tracekey)
{
return (g_tracekey == tracekey && g_tracekey != (uint64)-1);
}
void cm_write_trace_log(uint64 tracekey, const char *format, ...)
{
if (!is_trace_key(tracekey)) {
return;
}
date_t now = g_timer()->now;
char date[CM_MAX_TIME_STRLEN] = {0};
uint64 tid = (uint64)cm_get_current_thread_id();
(void)cm_date2str(now, "yyyy-mm-dd hh24:mi:ss.FF3", date, CM_MAX_TIME_STRLEN);
char buf[CM_MAX_LOG_CONTENT_LENGTH + 1] = {0};
text_t buf_text;
errno_t errcode = snprintf_s(buf, sizeof(buf), CM_MAX_LOG_CONTENT_LENGTH,
"%s|%llu|KEY:%llu:", date, tid, tracekey);
if (errcode < 0) {
return;
}
log_file_handle_t *log_file_handle = &g_logger[LOG_TRACE];
va_list args;
va_start(args, format);
buf_text.str = buf;
buf_text.len = (uint32)strlen(buf);
cm_log_fulfil_write_buf(log_file_handle, &buf_text, sizeof(buf), CM_TRUE, format, args);
va_end(args);
}
void cm_write_dynamic_trace_log(uint32 type, char* buf, uint32 size)
{
log_file_handle_t *log_file_handle = &g_logger[type];
cm_stat_and_write_log(log_file_handle, buf, size, CM_TRUE, cm_write_log_file);
}
#define BLACKBOX_PRINT_LINE_LEN 16
#define BLACKBOX_PRINT_SPACE_LEN 4
#define BLACKBOX_MAX_PRINT_SIZE (SIZE_M(8))
void cm_dump_mem_core_in_blackbox(uchar *dump_loc, uchar *last_data, uint32 *repeat_time)
{
uchar row_data[BLACKBOX_PRINT_LINE_LEN] = {0};
bool8 is_same = CM_TRUE;
uchar *dump_start = dump_loc;
uint32 index;
for (index = 0; index < BLACKBOX_PRINT_LINE_LEN; dump_loc++, index++) {
row_data[index] = *dump_loc;
if (is_same && last_data[index] != row_data[index]) {
is_same = CM_FALSE;
}
}
if (is_same) {
(*repeat_time)++;
return;
}
if (*repeat_time > 0) {
LOG_BLACKBOX_INF("\r\n Repeat %u times", *repeat_time);
*repeat_time = 0;
}
LOG_BLACKBOX_INF("\r\n %p: ", dump_start);
for (index = 0; index < BLACKBOX_PRINT_LINE_LEN; index++) {
LOG_BLACKBOX_INF("%02x ", row_data[index]);
if ((index + 1) % BLACKBOX_PRINT_SPACE_LEN == 0) {
LOG_BLACKBOX_INF(" ");
}
}
LOG_BLACKBOX_INF("[");
for (index = 0; index < BLACKBOX_PRINT_LINE_LEN; index++) {
if (isprint(row_data[index])) {
LOG_BLACKBOX_INF("%c", row_data[index]);
} else {
LOG_BLACKBOX_INF("%s", ".");
}
}
LOG_BLACKBOX_INF("]");
(void)memcpy_s(last_data, BLACKBOX_PRINT_LINE_LEN, row_data, BLACKBOX_PRINT_LINE_LEN);
}
void cm_dump_mem_in_blackbox(void *dump_addr, uint32 dump_len)
{
uint32 index;
uint32 row_index = 0;
uchar *dump_loc;
uchar row_data[BLACKBOX_PRINT_LINE_LEN] = {0};
uchar last_data[BLACKBOX_PRINT_LINE_LEN] = {0xf};
uint32 repeat_time = 0;
uint32 row_cnt;
uint32 col_left;
if ((dump_addr == NULL) || (dump_len == 0) || (dump_len > BLACKBOX_MAX_PRINT_SIZE)) {
LOG_BLACKBOX_INF("[DUMP] dump memory fail, dump_addr or dump_len is equal zero\r\n");
return;
}
dump_loc = (uchar *)dump_addr;
row_cnt = dump_len / BLACKBOX_PRINT_LINE_LEN;
col_left = dump_len % BLACKBOX_PRINT_LINE_LEN;
for (index = 0; index < row_cnt; index++) {
cm_dump_mem_core_in_blackbox(dump_loc, last_data, &repeat_time);
dump_loc += BLACKBOX_PRINT_LINE_LEN;
}
if (repeat_time > 0) {
LOG_BLACKBOX_INF("\r\n Repeat %u times", repeat_time);
}
if (col_left == 0) {
return;
}
LOG_BLACKBOX_INF("\r\n %p:", dump_loc);
for (index = 0; index < BLACKBOX_PRINT_LINE_LEN; dump_loc++, index++, row_index++) {
if (index >= col_left) {
row_data[row_index] = 0;
} else {
row_data[row_index] = *dump_loc;
}
LOG_BLACKBOX_INF("%02x ", row_data[row_index]);
if ((index + 1) % BLACKBOX_PRINT_SPACE_LEN == 0) {
LOG_BLACKBOX_INF(" ");
}
}
LOG_BLACKBOX_INF("[");
for (row_index = 0; row_index < BLACKBOX_PRINT_LINE_LEN; row_index++) {
if (isprint(row_data[row_index])) {
LOG_BLACKBOX_INF("%c", row_data[row_index]);
} else {
LOG_BLACKBOX_INF("%s", ".");
}
}
LOG_BLACKBOX_INF("]");
}
#ifdef __cplusplus
}
#endif