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); } }