442 lines
11 KiB
C
442 lines
11 KiB
C
/** @file log.c
|
|
@brief 系统日志接口文件
|
|
@version 1.0.0
|
|
*/
|
|
#include <sys/time.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <uthash/utlist.h>
|
|
#include <uthash/utstring.h>
|
|
|
|
#include "log.h"
|
|
#include "../../../../Product/common/common.h"
|
|
|
|
#define SHOW_CONSOLE_RED ("\033[31;48m\033[1m%s\033[0m%c")
|
|
#define SHOW_CONSOLE_YELLOW ("\033[33;48m\033[1m%s\033[0m%c")
|
|
#define SHOW_CONSOLE_GREEN ("\033[32;48m\033[1m%s\033[0m%c")
|
|
#define SHOW_CONSOLE_BLUE ("\033[34;48m\033[1m%s\033[0m%c")
|
|
|
|
#define LOG_FILE_BASEDIR (".")
|
|
|
|
#define MAX_LOG_FILE_SIZE (1024 * 1024)
|
|
#define MAX_PATH (256)
|
|
|
|
typedef struct LOG_ITEM
|
|
{
|
|
LOG_LEVEL level;
|
|
int isPrinted;
|
|
int isAddTags;
|
|
struct timeval timestamp;
|
|
char *pLogContent;
|
|
struct LOG_ITEM *next, *prev;
|
|
}*PLOG_ITEM;
|
|
|
|
typedef struct
|
|
{
|
|
pid_t pid;
|
|
char exeName[MAX_PATH];
|
|
char logFilePath[MAX_PATH];
|
|
FILE *pLogFile;
|
|
} LOG_PROCESS_INFO, *PLOG_PROCESS_INFO;
|
|
|
|
static int g_bEnableLog = TRUE; // 是否启用 Log 功能
|
|
static int g_bEnLogToFile = TRUE;
|
|
static char g_strLogTag[32]; // Log 标志
|
|
static unsigned int g_LogRdPos = 0;
|
|
static pthread_t g_logThreadId;
|
|
static LOG_PROCESS_INFO g_LogProcessInfo;
|
|
static pthread_mutex_t g_logLock;
|
|
static PLOG_ITEM g_pLogItemList = NULL;
|
|
|
|
static int g_iMinLevel = LOG_Fatal | LOG_Error | LOG_Warn | LOG_Debug | LOG_Info | LOG_Step;
|
|
|
|
/**
|
|
* @brief Log 调试等级转字符串
|
|
* @param level 调试等级
|
|
* @return 调试等级对应的字符串
|
|
*/
|
|
const char* LogLevelToStr(LOG_LEVEL level)
|
|
{
|
|
switch(level)
|
|
{
|
|
case LOG_Test:
|
|
return "T";
|
|
|
|
case LOG_Info:
|
|
return "I";
|
|
|
|
case LOG_Call:
|
|
return "C";
|
|
|
|
case LOG_Debug:
|
|
return "D";
|
|
|
|
case LOG_Warn:
|
|
return "W";
|
|
|
|
case LOG_Error:
|
|
return "E";
|
|
|
|
case LOG_Fatal:
|
|
return "F";
|
|
|
|
case LOG_Step:
|
|
return "S";
|
|
|
|
case LOG_Devp:
|
|
return "V";
|
|
|
|
case LOG_Unknown:
|
|
return "U";
|
|
|
|
case LOG_All:
|
|
return "A";
|
|
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
static void __logColorOutput(const char* pColFmt, UT_string* pLog)
|
|
{
|
|
if(pLog == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(pColFmt == NULL)
|
|
{
|
|
print("%s", utstring_body(pLog));
|
|
}
|
|
else
|
|
{
|
|
if(utstring_find(pLog, -1, "\n", 1) == utstring_len(pLog) - 1)
|
|
{
|
|
char* pLogArray = utstring_body(pLog);
|
|
pLogArray[utstring_len(pLog) - 1] = 0;
|
|
|
|
print(pColFmt, pLogArray, '\n');
|
|
|
|
strcat(pLogArray, "\n");
|
|
}
|
|
else
|
|
{
|
|
print(pColFmt, utstring_body(pLog), '\0');
|
|
}
|
|
}
|
|
}
|
|
|
|
static void* __logOutputThread(void *p)
|
|
{
|
|
(void)p;
|
|
while(TRUE)
|
|
{
|
|
int isWriteLog = FALSE;
|
|
PLOG_ITEM pItem = NULL, pTmp = NULL;
|
|
|
|
pthread_mutex_lock(&g_logLock);
|
|
|
|
LL_FOREACH_SAFE(g_pLogItemList, pItem, pTmp)
|
|
{
|
|
UT_string *pLogStr;
|
|
struct tm lTime;
|
|
int logFileSize = 0;
|
|
|
|
if(++g_LogRdPos % 100 == 0)
|
|
{
|
|
GET_FILE_SIZE(g_LogProcessInfo.logFilePath, logFileSize);
|
|
}
|
|
|
|
localtime_r(&(pItem->timestamp.tv_sec), &lTime);
|
|
|
|
utstring_new(pLogStr);
|
|
|
|
if(pItem->isAddTags)
|
|
{
|
|
utstring_printf(pLogStr, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] [%s] %s",
|
|
lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday,
|
|
lTime.tm_hour, lTime.tm_min, lTime.tm_sec, pItem->timestamp.tv_usec / 1000,
|
|
LogLevelToStr(pItem->level), pItem->pLogContent);
|
|
}
|
|
else
|
|
{
|
|
utstring_printf(pLogStr, "%s", pItem->pLogContent);
|
|
}
|
|
|
|
if(pItem->isPrinted == FALSE)
|
|
{
|
|
if(pItem->level & LOG_Error
|
|
|| pItem->level & LOG_Fatal)
|
|
{
|
|
__logColorOutput(SHOW_CONSOLE_RED, pLogStr);
|
|
}
|
|
else if(pItem->level & LOG_Warn
|
|
|| pItem->level & LOG_Unknown)
|
|
{
|
|
__logColorOutput(SHOW_CONSOLE_YELLOW, pLogStr);
|
|
}
|
|
else if(pItem->level & LOG_Test
|
|
|| pItem->level & LOG_Call)
|
|
{
|
|
__logColorOutput(SHOW_CONSOLE_BLUE, pLogStr);
|
|
}
|
|
else if(pItem->level & LOG_Devp)
|
|
{
|
|
__logColorOutput(SHOW_CONSOLE_GREEN, pLogStr);
|
|
}
|
|
else
|
|
{
|
|
print("%s", utstring_body(pLogStr));
|
|
}
|
|
|
|
pItem->isPrinted = TRUE;
|
|
}
|
|
|
|
if(g_LogProcessInfo.pLogFile != NULL && g_bEnLogToFile)
|
|
{
|
|
if(logFileSize >= MAX_LOG_FILE_SIZE)
|
|
{
|
|
fflush(g_LogProcessInfo.pLogFile);
|
|
fclose(g_LogProcessInfo.pLogFile);
|
|
|
|
g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+");
|
|
}
|
|
|
|
if(g_LogProcessInfo.pLogFile)
|
|
{
|
|
fwrite(utstring_body(pLogStr), 1, utstring_len(pLogStr), g_LogProcessInfo.pLogFile);
|
|
}
|
|
|
|
isWriteLog = TRUE;
|
|
}
|
|
|
|
LL_DELETE(g_pLogItemList, pItem);
|
|
|
|
utstring_free(pLogStr);
|
|
free(pItem->pLogContent);
|
|
free(pItem);
|
|
|
|
if(g_LogRdPos % 100 == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_logLock);
|
|
|
|
usleep(1000);
|
|
if(g_LogProcessInfo.pLogFile != NULL && isWriteLog)
|
|
{
|
|
fflush(g_LogProcessInfo.pLogFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 设置调试等级
|
|
* @param level 调试等级
|
|
* @param iEnable 1 打开调试等级, 0 关闭调试等级
|
|
*/
|
|
void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable)
|
|
{
|
|
if(iEnable > 0)
|
|
{
|
|
g_iMinLevel |= level;
|
|
}
|
|
else
|
|
{
|
|
g_iMinLevel &= ~(level);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 初始化系统日志功能
|
|
* @param pLogTag 系统日志标志
|
|
* @param pPath 系统日志保存路径
|
|
* @param bEnable 打开/关闭调试信息
|
|
*/
|
|
void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable)
|
|
{
|
|
char strPath[MAX_PATH * 2];
|
|
(void)pPath;
|
|
|
|
pthread_mutex_init(&g_logLock, 0);
|
|
|
|
g_LogRdPos = 0;
|
|
memset(g_strLogTag, 0, 32);
|
|
|
|
memset(&g_LogProcessInfo, 0, sizeof(LOG_PROCESS_INFO));
|
|
|
|
if(pLogTag == NULL)
|
|
{
|
|
strcpy(g_strLogTag, "");
|
|
}
|
|
else
|
|
{
|
|
strncpy(g_strLogTag, pLogTag, 31);
|
|
}
|
|
|
|
memset(strPath, 0, MAX_PATH * 2);
|
|
|
|
g_LogProcessInfo.pid = getpid();
|
|
if(readlink("/proc/self/exe", strPath, MAX_PATH) == -1)
|
|
{
|
|
strcpy(g_LogProcessInfo.exeName, pLogTag);
|
|
}
|
|
else
|
|
{
|
|
char *pExeName = strrchr(strPath, '/');
|
|
|
|
if(pExeName == NULL)
|
|
{
|
|
strncpy(g_LogProcessInfo.exeName, strPath, MAX_PATH - 1);
|
|
}
|
|
else
|
|
{
|
|
strncpy(g_LogProcessInfo.exeName, pExeName + 1, MAX_PATH - 1);
|
|
}
|
|
}
|
|
|
|
memset(g_LogProcessInfo.logFilePath, 0, MAX_PATH);
|
|
sprintf(g_LogProcessInfo.logFilePath, "%s/%s_%d.log", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName, g_LogProcessInfo.pid);
|
|
|
|
memset(strPath, 0, MAX_PATH);
|
|
//sprintf(strPath, "rm -f %s/%s_*.log > /dev/zero", LOG_FILE_BASEDIR, g_LogProcessInfo.exeName);
|
|
//ret = system(strPath);
|
|
|
|
//g_LogProcessInfo.pLogFile = fopen(g_LogProcessInfo.logFilePath, "w+");
|
|
|
|
g_bEnableLog = bEnable;
|
|
|
|
IHW_RunLogService();
|
|
}
|
|
|
|
void IHW_RunLogService(void)
|
|
{
|
|
pthread_create(&g_logThreadId, NULL, __logOutputThread, NULL);
|
|
}
|
|
|
|
static void __logTo(LOG_LEVEL level, int isAddTag, char* pMsg, int isPrint)
|
|
{
|
|
PLOG_ITEM pLogItem;
|
|
|
|
pLogItem = (PLOG_ITEM)malloc(sizeof(struct LOG_ITEM));
|
|
|
|
if(pLogItem == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pLogItem->pLogContent = strdup(pMsg);
|
|
pLogItem->isPrinted = isPrint ? FALSE : TRUE;
|
|
pLogItem->level = level;
|
|
pLogItem->isAddTags = isAddTag ? TRUE : FALSE;
|
|
gettimeofday(&(pLogItem->timestamp), NULL);
|
|
|
|
pthread_mutex_lock(&g_logLock);
|
|
LL_APPEND(g_pLogItemList, pLogItem);
|
|
pthread_mutex_unlock(&g_logLock);
|
|
}
|
|
|
|
void IHW_LogStrWithoutPrint(int level, char* pMsg)
|
|
{
|
|
__logTo(level, TRUE, pMsg, FALSE);
|
|
}
|
|
|
|
void IHW_LogRawString(int level, char* pMsg)
|
|
{
|
|
__logTo(level, TRUE, pMsg, TRUE);
|
|
}
|
|
|
|
/**
|
|
* @brief 输出调试信息
|
|
* @param cFlag 调试信息开关
|
|
* @param pMsg 调试信息内容
|
|
*/
|
|
void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...)
|
|
{
|
|
va_list arg_ptr;
|
|
UT_string *pLogContent;
|
|
|
|
if(!g_bEnableLog)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 检查调试等级
|
|
if(!(g_iMinLevel & level))
|
|
{
|
|
return;
|
|
}
|
|
|
|
utstring_new(pLogContent);
|
|
va_start(arg_ptr, pMsg);
|
|
utstring_printf_va(pLogContent, pMsg, arg_ptr);
|
|
va_end(arg_ptr);
|
|
|
|
__logTo(level, FALSE, utstring_body(pLogContent), TRUE);
|
|
|
|
utstring_free(pLogContent);
|
|
}
|
|
|
|
/**
|
|
* @brief 输出调试信息
|
|
* @param cFlag 调试信息开关
|
|
* @param pMsg 调试信息内容
|
|
*/
|
|
void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...)
|
|
{
|
|
UT_string* pLogContent = NULL;
|
|
va_list arg_ptr;
|
|
|
|
if(!g_bEnableLog)
|
|
{
|
|
fprintf(stdout, "skip2\n");
|
|
return;
|
|
}
|
|
|
|
// 检查调试等级
|
|
if(!(g_iMinLevel & level))
|
|
{
|
|
fprintf(stdout, "skip1\n");
|
|
return;
|
|
}
|
|
|
|
utstring_new(pLogContent);
|
|
va_start(arg_ptr, pMsg);
|
|
utstring_printf_va(pLogContent, pMsg, arg_ptr);
|
|
va_end(arg_ptr);
|
|
|
|
__logTo(level, TRUE, utstring_body(pLogContent), TRUE);
|
|
|
|
utstring_free(pLogContent);
|
|
}
|
|
|
|
const char* LogLeveToString(LOG_LEVEL lv)
|
|
{
|
|
switch(lv)
|
|
{
|
|
case LOG_Fatal: return "LOG_Fatal";
|
|
case LOG_Error: return "LOG_Error";
|
|
case LOG_Warn: return "LOG_Warn";
|
|
case LOG_Debug: return "LOG_Debug";
|
|
case LOG_Info: return "LOG_Info";
|
|
case LOG_Test: return "LOG_Test";
|
|
case LOG_Call: return "LOG_Call";
|
|
case LOG_Devp: return "LOG_Devp";
|
|
case LOG_Step: return "LOG_Step";
|
|
case LOG_Unknown: return "LOG_Unknown";
|
|
case LOG_All: return "LOG_All";
|
|
case LOG_Close: return "LOG_Close";
|
|
}
|
|
|
|
return "Unknown";
|
|
}
|