C言語マルチスレッドにおける異なるレベルログの実装
/***********************************************************************
モジュール名:C言語マルチレベルログモジュールの実現
モジュール機能:マルチスレッド環境でマルチレベルログの記録を実現
モジュールの説明:ログによって生成された時間を、時間によって命名されたフォルダにそれぞれ記録し、ログの出力レベルを設定できます.
/***********************************************************************
//sys_log.h
//sys_thread.c
//sys_log.c
モジュール名:C言語マルチレベルログモジュールの実現
モジュール機能:マルチスレッド環境でマルチレベルログの記録を実現
モジュールの説明:ログによって生成された時間を、時間によって命名されたフォルダにそれぞれ記録し、ログの出力レベルを設定できます.
/***********************************************************************
//sys_log.h
#ifndef SYS_LOG_H
#define SYS_LOG_H
#include
#ifdef __cplusplus
extern
"C" {
#endif
#define TRUE 1
#define FALSE 0
#define IN
#define OUT
#define LOG_PATH "sys_log"
typedef enum {
DEBUG,
INFO,
WARN,
ERROR,
OFF
}LOG_LEVEL;
void set_log_level(
IN LOG_LEVEL level
);
char* log_level_2_str(
IN LOG_LEVEL level
);
LOG_LEVEL log_str_2_level(
IN const char* level
);
void write_log(
IN LOG_LEVEL level, //
IN const char* file, //
IN const char* function,//
IN int line, //
IN const char* format,//
...
);
void write_log_2_file(
IN const char* file_name,//
IN LOG_LEVEL level, //
IN const char* file, //
IN const char* function,//
IN int line, //
IN const char* msg
);
//
void set_log_path(IN const char* path);
//
void log_terminal();
//
void log_shutdown_terminal();
//
void log_shutdown_file();
void log_to_file();
//
#define LOG_DEBUG(format, ...) write_log(DEBUG, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOG_ERROR(format, ...) write_log(ERROR, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOG_INFO(format, ...) write_log( INFO, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOG_WARN(format, ...) write_log(WARN, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif
//sys_thread.c
#include
typedef struct tagTHREAD_INFO{
char name[64];
pthread_t tid;
}THREAD_INFO;
static THREAD_INFO g_thread_info[1024];
static int g_thread_num = 0;
void register_thread_name(
IN pthread_t tid,
IN const char* name
)
{
memset((void*)&g_thread_info[g_thread_num], 0, sizeof(THREAD_INFO));
g_thread_info[g_thread_num].tid = tid;
memcpy((void*)g_thread_info[g_thread_num].name, (void*)name, strlen(name));
g_thread_num++;
}
char* get_thread_name()
{
int = 0;
pthread_t tid = pthread_self();
for (; i
//sys_log.c
//sys_log.c
#include
#include
#include
#include
#include
#include
#include
#include
#include "sys_log.h"
#include "sys_thread.h"
char g_log_root[64] = {0} ;
char g_start_time[64] = {0};
//
static LOG_LEVEL g_log_level = DEBUG;
static int g_log_terminal = TRUE;
static int g_log_to_file = TRUE;
void log_terminal()
{
g_log_terminal = TRUE;
}
void log_shutdown_terminal()
{
g_log_terminal = FALSE;
}
void log_shutdown_file()
{
g_log_to_file = FALSE;
}
void log_to_file()
{
g_log_to_file = TRUE;
}
void set_log_path(IN const char* path)
{
if (path)
{
memcpy(g_log_root, path, strlen(path));
}
}
void set_log_level(
IN LOG_LEVEL level
)
{
g_log_level = level;
}
LOG_LEVEL log_str_2_level(
IN const char* level
)
{
if (!level)
{
return DEBUG;
}
if (strcmp("DEBUG", level) == 0)
{
return DEBUG;
}
if (strcmp("INFO", level) == 0)
{
return INFO;
}
if (strcmp("WARN", level) == 0)
{
return WARN;
}
if (strcmp("ERROR", level) == 0)
{
return ERROR;
}
if (strcmp("OFF", level) == 0)
{
return OFF;
}
return DEBUG;
}
char* log_level_2_str(
IN LOG_LEVEL level
)
{
switch (level)
{
case DEBUG:
return (char*)"DEBUG";
case INFO:
return (char*)"INFO";
case WARN:
return (char*)"WARN";
case ERROR:
return (char*)"ERROR";
case OFF:
return (char*)"OFF";
default:
return (char*)"UNKNOW";
}
return (char*)"UNKNOW";
}
void write_log(
IN LOG_LEVEL level, //
IN const char* file, //
IN const char* function,//
IN int line, //
IN const char* format,//
IN ...
)
{
if (level < g_log_level)
{
return;
}
if (!strlen(g_log_root))
{
//
memcpy(g_log_root, LOG_PATH, strlen(LOG_PATH));
//assert(ret == 0);
}
mkdir(g_log_root, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
time_t now = time(NULL);
char timestamp[128] = {0};
struct tm date;
struct tm *ptr = localtime_r(&now, &date);
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d", ptr);
char forder[160] = {0};
sprintf(forder, "%s/%s", g_log_root, timestamp);
mkdir(forder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
//
if (strlen(g_start_time) == 0)
{
memset(g_start_time, 0, sizeof(g_start_time));
strftime(g_start_time, sizeof(timestamp), "%H_%M_%S", ptr);
}
memset(forder, 0, sizeof(forder));
sprintf(forder, "%s/%s/%s", g_log_root, timestamp, g_start_time);
mkdir(forder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
char threadId[256] = {0};
char* threadName = get_thread_name();
if (!threadName)
{
sprintf(threadId, "%s/thread.%lld.log", forder, pthread_self());
} else {
sprintf(threadId, "%s/thread.%s.log", forder, threadName);
}
va_list vap;
va_start(vap , format);
char msg[2048] = {0};
vsnprintf(msg, sizeof(msg), format, vap);
write_log_2_file(threadId, level, file, function, line, msg);
va_end(vap);
}
void write_log_2_file(
IN const char* file_name,//
IN LOG_LEVEL level, //
IN const char* file, //
IN const char* function,//
IN int line, //
IN const char* msg
)
{
FILE *fp = NULL;
fp = fopen(file_name, "a+");
if (!fp)
{
return;
}
//assert(fp);
char log_info[4092] = {0};
//
time_t now = time(NULL);;
struct tm date;
char timestamp[80] = {0};
struct tm *ptr = localtime_r(&now, &date);
strftime(timestamp, 100, "%B %d %Y %T", ptr);
sprintf(log_info, "[%s|%s|%s:%d|%s]%s
", timestamp,
log_level_2_str(level), function, line, get_thread_name(), msg);
if (g_log_to_file)
{
fwrite(log_info, sizeof(char), strlen(log_info), fp);
}
fclose(fp);
if (g_log_terminal) {
fprintf(stdout, log_info);
}
}