在linux环境下使用c语言开发的一款日志系统clog,统一接口,功能丰富。
├── config.h #clog的配置头文件,通过宏定义,用户可以自定义自己的clog日志系统
├── clog.h #clog头文件,定义clog日志系统的接口
├── clog.c #clog日志内容组合
├── consoleclog.c #clog日志终端输出
├── fileclog.c #clog日志文件输出
├── shmclog.c #clog日志多进程共享内存输出日志
├── tcpclog.c #clog日志多进程tcp输出日志
├── tcp.c
├── tcp.h
└── udpclog.c #clog日志多进程udp输出日志
支持5种日志级别,error、warning、info、debug、trace
//日志级别
typedef enum
{
CLOG_ERROR=0,
CLOG_WARNING=1,
CLOG_INFO=2,
CLOG_DEBUG=3,
CLOG_TRACE=4
}Clog_Print_Level;
【日志级别】-【时间】-【模块名】-【组件名】-【进程id】-【线程id】-【文件名】-【行号】-【函数名】->日志内容
[ERROR]-[2216-11-13 21:36:20.837]-[clog]-[clog]-[5624]-[140016484947776]-[main.c]-[23]-[random_gen_log]-> HJIGJHF
[WARN]-[2216-11-13 21:36:20.837]-[clog]-[clog]-[5624]-[140016484947776]-[main.c]-[24]-[random_gen_log]-> HJIGJHF
[INFO]-[2216-11-13 21:36:20.837]-[clog]-[clog]-[5624]-[140016484947776]-[main.c]-[25]-[random_gen_log]-> HJIGJHF
[DEBUG]-[2216-11-13 21:36:20.837]-[clog]-[clog]-[5624]-[140016484947776]-[main.c]-[26]-[random_gen_log]-> HJIGJHF
[TRACE]-[2216-11-13 21:36:20.837]-[clog]-[clog]-[5624]-[140016484947776]-[main.c]-[27]-[random_gen_log]-> HJIGJHF
用户可以根据自己的需求自定义日志内容
//日志打印内容
#define CONTAIN_LOG_LEVEL 1 //是否显示日志级别 1->显示,0->不显示
#define CONTAIN_LOG_TIME 1 //是否显示日志时间 1->显示,0->不显示
#define CONTAIN_LOG_MODULE 1 //是否显示日志模块名 1->显示,0->不显示
#define CONTAIN_LOG_COMPONENT 1 //是否显示日志组件名 1->显示,0->不显示
#define CONTAIN_LOG_FILENAME 1 //是否显示日志文件名 1->显示,0->不显示
#define CONTAIN_LOG_LINENAME 1 //是否显示日志行号 1->显示,0->不显示
#define CONTAIN_LOG_FUNCNAME 1 //是否显示日志函数名 1->显示,0->不显示
#define CONTAIN_LOG_PROCESSID 1 //是否显示日志进程id 1->显示,0->不显示
#define CONTAIN_LOG_THREADID 1 //是否显示日志线程id 1->显示,0->不显示
日志支持输出到文件和终端,通过宏定义供用户选择输出方式
#define SUPPORT_CLOG_FILE 1 //0-->关闭输出到文件 1-->开启输出到文件
#define SUPPORT_CLOG_CONSOLE 1 //0->关闭输出到终端 1-->开启输出到终端
#define SUPPORT_MULTI_PROCESS 1 //0-->单进程 1-->多进程
#define DATA_TRANSFER_WAY 0 //0-->使用共享内存作为数据传递 1-->使用tcp作为数据传递 2-->使用UDP作为数据传递
在多进程下,用户可以选择进程间的通信方式,tcp、udp、共享内存。用以进行日志的输出
每一种通信方式下,只有一个server端和多个client端。server端通过通信方式接收其他进程的日志内容,并将日志内容输入到文件或终端。client端为日志生产者,通过多进程通信方式不断的向server端发送日志内容
日志内容输出接口,采用c语言的变参函数设计,支持任意长度的日志内容
clog_e(...) // error级别
clog_w(...) // warning级别
clog_i(...) // info级别
clog_d(...) // debug级别
clog_t(...) // trace级别
//设置日志文件存储目录
int set_log_file_save_dir(const char* logdir);
//设置文件日志存储的最小日志级别
void set_log_file_level(Clog_Print_Level plevel);
//设置终端日志打印的最小日志级别
void set_log_console_level(Clog_Print_Level plevel);
//设置终端日志每个日志级别,打印的文字颜色
void set_console_level_color(Clog_Print_Level plevel,Clog_Console_FG_Color fg_color);
//console 终端打印字体颜色
typedef enum
{
FG_DEFAULT=0,
FG_Black=30,
FG_Red=31,
FG_Green=32,
FG_Yellow=33,
FG_Blue =34,
FG_Magenta=35,
FG_Cyan=36,
FG_White=37
}Clog_Console_FG_Color;
//设置tcp client连接时用到的ip地址和端口号,使client端建立tcp连接
int log_tcp_connect(const char ip[16],unsigned short tcp_port);
//设置tcp server端的端口号,可用于接收client端socket连接的子线程数量
int log_tcp_server(unsigned short tcp_port,unsigned int thread_count);
//设置udp client端连接时用到的ip地址和端口号
int log_set_udp(const char ip[16],unsigned short udp_port);
//设置udp server端的IP地址和端口号
int log_udp_server(const char ip[16],unsigned short udp_port);
//共享内存server端
int log_shm_server();
//共享内存client端
int log_shm_connect();
#include
#include
#include
#include
#include "clog.h"
//随机生成指定条数和指定大小的日志内容
#define LOG_COUNT 50
#define LOG_SIZE 20
void random_gen_log()
{
int index=0;
for(index=0;index<LOG_COUNT;index++)
{
//随机数产生日志单条内容长度
int log_len=5+rand()%(LOG_SIZE);
char* log_data=(char*)malloc(log_len* sizeof(char));
int index=0;
for(index=0;index<log_len-1;index++)
{
log_data[index]='A'+rand()%26;
}
log_data[index]='\0';
clog_e("%s",log_data);
clog_w("%s",log_data);
clog_i("%s",log_data);
clog_d("%s",log_data);
clog_t("%s",log_data);
free(log_data);
log_data=NULL;
usleep(1000*10);
}
}
//测试单进程下的文件和终端日志
void test_clog_file_console()
{
set_log_console_level(CLOG_TRACE);
set_console_level_color(CLOG_ERROR,FG_Red);
set_console_level_color(CLOG_WARNING,FG_Yellow);
set_console_level_color(CLOG_INFO,FG_DEFAULT);
set_console_level_color(CLOG_DEBUG,FG_Blue);
set_console_level_color(CLOG_TRACE,FG_Cyan);
set_log_file_save_dir("/home/nvidia/Videos/");
set_log_file_level(CLOG_TRACE);
random_gen_log();
}
//测试多进程下的使用tcp传输日志
void test_clog_tcp(int argc,char* argv[])
{
if(argc!=2)
{
return;
}
if(strcmp(argv[1],"client")==0)
{
log_tcp_connect("127.0.0.1",7789);
random_gen_log();
}
else if(strcmp(argv[1],"server")==0)
{
set_log_console_level(CLOG_TRACE);
set_console_level_color(CLOG_ERROR,FG_Red);
set_console_level_color(CLOG_WARNING,FG_Yellow);
set_console_level_color(CLOG_INFO,FG_DEFAULT);
set_console_level_color(CLOG_DEBUG,FG_Blue);
set_console_level_color(CLOG_TRACE,FG_Cyan);
set_log_file_save_dir("/home/nvidia/Videos/");
set_log_file_level(CLOG_TRACE);
log_tcp_server(7789,1);
}
}
//测试多进程下的使用udp传输日志
void test_clog_udp(int argc,char* argv[])
{
if(argc!=2)
{
return;
}
if(strcmp(argv[1],"client")==0)
{
log_set_udp("127.0.0.1",7789);
random_gen_log();
}
else if(strcmp(argv[1],"server")==0)
{
set_log_console_level(CLOG_TRACE);
set_console_level_color(CLOG_ERROR,FG_Red);
set_console_level_color(CLOG_WARNING,FG_Yellow);
set_console_level_color(CLOG_INFO,FG_DEFAULT);
set_console_level_color(CLOG_DEBUG,FG_Blue);
set_console_level_color(CLOG_TRACE,FG_Cyan);
set_log_file_save_dir("/home/nvidia/Videos/");
set_log_file_level(CLOG_TRACE);
log_udp_server("127.0.0.1",7789);
}
}
//测试多进程下的使用共享内存传输日志
void test_clog_shm(int argc,char* argv[])
{
if(argc!=2)
{
return;
}
if(strcmp(argv[1],"client")==0)
{
log_shm_connect();
random_gen_log();
}
else if(strcmp(argv[1],"server")==0)
{
set_log_console_level(CLOG_TRACE);
set_console_level_color(CLOG_ERROR,FG_Red);
set_console_level_color(CLOG_WARNING,FG_Yellow);
set_console_level_color(CLOG_INFO,FG_DEFAULT);
set_console_level_color(CLOG_DEBUG,FG_Blue);
set_console_level_color(CLOG_TRACE,FG_Cyan);
set_log_file_save_dir("/home/nvidia/Videos/");
set_log_file_level(CLOG_TRACE);
log_shm_server();
}
}
config.h
#ifndef CLOG_CONFIG_H
#define CLOG_CONFIG_H
//日志打印内容
#define CONTAIN_LOG_LEVEL 1
#define CONTAIN_LOG_TIME 1
//模块名
#define CONTAIN_LOG_MODULE 1
//组件名
#define CONTAIN_LOG_COMPONENT 1
#define CONTAIN_LOG_FILENAME 1
#define CONTAIN_LOG_LINENAME 1
#define CONTAIN_LOG_FUNCNAME 1
//进程id
#define CONTAIN_LOG_PROCESSID 1
//线程id
#define CONTAIN_LOG_THREADID 1
#ifndef CLOG_MODULE_NAME
#define CLOG_MODULE_NAME "clog"
#endif
#ifndef CLOG_COMPONENT_NAME
#define CLOG_COMPONENT_NAME "clog"
#endif
#define SUPPORT_CLOG_FILE 1 //0-->关闭输出到文件 1-->开启输出到文件
#define SUPPORT_CLOG_CONSOLE 1 //0->关闭输出到终端 1-->开启输出到终端
//单个文件最大大小
#define CLOG_FILE_MAX_SIZE (10*1024*1024) //100M
#define SUPPORT_MULTI_PROCESS 1 //0-->单进程 1-->多进程
#define DATA_TRANSFER_WAY 0 //0-->使用共享内存作为数据传递 1-->使用tcp作为数据传递 2-->使用UDP作为数据传递
#define CLOG_UDP_LENGTH 1024
#define CLOG_SHM_QUEUE_COUNT 5 //共享内存存储队列元素个数
#define CLOG_SHM_QUEUE_LEN 1024 //共享内存单条日志最大size
#endif //CLOG_CONFIG_H
clog.h
#ifndef CLOG_CLOG_H
#define CLOG_CLOG_H
#include "config.h"
#include
#include
//解决__FILE__为绝对路径的问题
#define CLOG_FILENAME(x) (strrchr((x),'/')?strrchr((x),'/')+1:(x))
//日志级别
typedef enum
{
CLOG_ERROR=0,
CLOG_WARNING=1,
CLOG_INFO=2,
CLOG_DEBUG=3,
CLOG_TRACE=4
}Clog_Print_Level;
//console 终端打印字体颜色
typedef enum
{
FG_DEFAULT=0,
FG_Black=30,
FG_Red=31,
FG_Green=32,
FG_Yellow=33,
FG_Blue =34,
FG_Magenta=35,
FG_Cyan=36,
FG_White=37
}Clog_Console_FG_Color;
#define clog_e(...) clog_print(CLOG_ERROR,CLOG_MODULE_NAME,CLOG_COMPONENT_NAME,CLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__,__VA_ARGS__)
#define clog_w(...) clog_print(CLOG_WARNING,CLOG_MODULE_NAME,CLOG_COMPONENT_NAME,CLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__,__VA_ARGS__)
#define clog_i(...) clog_print(CLOG_INFO,CLOG_MODULE_NAME,CLOG_COMPONENT_NAME,CLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__,__VA_ARGS__)
#define clog_d(...) clog_print(CLOG_DEBUG,CLOG_MODULE_NAME,CLOG_COMPONENT_NAME,CLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__,__VA_ARGS__)
#define clog_t(...) clog_print(CLOG_TRACE,CLOG_MODULE_NAME,CLOG_COMPONENT_NAME,CLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__,__VA_ARGS__)
void clog_print(Clog_Print_Level plevel,const char* module_name,const char* component_name,const char* filename,const int linenum,const char* funcname,char *fmt, ...);
#if SUPPORT_CLOG_CONSOLE
void set_log_console_level(Clog_Print_Level plevel);
void set_console_level_color(Clog_Print_Level plevel,Clog_Console_FG_Color fg_color);
void log_output_console(const char* clog_data);
#endif
#if SUPPORT_CLOG_FILE
int set_log_file_save_dir(const char* logdir);
void set_log_file_level(Clog_Print_Level plevel);
void log_output_file(const char* clog_data);
#endif
#if SUPPORT_MULTI_PROCESS
#if DATA_TRANSFER_WAY == 1
int log_tcp_connect(const char ip[16],unsigned short tcp_port);
int log_tcp_server(unsigned short tcp_port,unsigned int thread_count);
void log_output_tcp(const char* clog_data);
#elif DATA_TRANSFER_WAY == 2
int log_set_udp(const char ip[16],unsigned short udp_port);
int log_udp_server(const char ip[16],unsigned short udp_port);
void log_output_udp(const char* clog_data);
#elif DATA_TRANSFER_WAY == 0
int log_shm_server();
int log_shm_connect();
int log_output_shm(const char* clog_data);
#endif
#endif
#endif //CLOG_CLOG_H
clog.c
#include "clog.h"
#include
#include
#include
#include
#include
#include
#include
#include
//日志支持任意长度,默认时512字节,会根据日志的长度通过realloc函数动态调整
static uint64_t clog_data_length=512;
static char* level_to_char(Clog_Print_Level plevel)
{
switch (plevel)
{
case CLOG_ERROR:
return "ERROR";
case CLOG_WARNING:
return "WARN";
case CLOG_INFO:
return "INFO";
case CLOG_DEBUG:
return "DEBUG";
case CLOG_TRACE:
return "TRACE";
}
}
static void time_to_str(char timestr[24])
{
struct tm *ptm;
struct timeb stTimeb;
ftime(&stTimeb);
ptm = localtime(&stTimeb.time);
snprintf(timestr,24,"%04d-%02d-%02d %02d:%02d:%02d.%03d",
ptm->tm_yday+1900,ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec, stTimeb.millitm);
}
void clog_print(Clog_Print_Level plevel,const char* module_name,const char* component_name,const char* filename,const int linenum,const char* funcname,char *fmt, ...)
{
uint64_t ret=0;
uint64_t total_len=0;
uint64_t header_len=0;
//total_length(uint64_t)+level(uint8_t)+log_data
char *log_data=(char*)malloc(clog_data_length+2);
char* log_ptr=log_data;
char log_time[24]="\0";
time_to_str(log_time);
log_ptr+=sizeof(uint64_t);
memcpy(log_ptr,&plevel,sizeof(uint8_t));
log_ptr+=sizeof(uint8_t);
#if CONTAIN_LOG_LEVEL
log_ptr+=sprintf(log_ptr,"[%s]",level_to_char(plevel));
#endif
#if CONTAIN_LOG_TIME
log_ptr+=sprintf(log_ptr,"-[%s]",log_time);
#endif
#if CONTAIN_LOG_MODULE
log_ptr+=sprintf(log_ptr,"-[%s]",module_name);
#endif
#if CONTAIN_LOG_COMPONENT
log_ptr+=sprintf(log_ptr,"-[%s]",component_name);
#endif
#if CONTAIN_LOG_PROCESSID
log_ptr+=sprintf(log_ptr,"-[%u]",getpid());
#endif
#if CONTAIN_LOG_THREADID
log_ptr+=sprintf(log_ptr,"-[%lu]",pthread_self());
#endif
#if CONTAIN_LOG_FILENAME
log_ptr+=sprintf(log_ptr,"-[%s]",filename);
#endif
#if CONTAIN_LOG_LINENAME
log_ptr+=sprintf(log_ptr,"-[%d]",linenum);
#endif
#if CONTAIN_LOG_FUNCNAME
log_ptr+=sprintf(log_ptr,"-[%s]",funcname);
#endif
log_ptr+=sprintf(log_ptr,"-> ");
header_len=(uint64_t)(log_ptr-log_data);
va_list args;
va_start(args, fmt);
ret=vsnprintf(log_ptr,clog_data_length-header_len,fmt, args);
va_end(args);
//根据日志的实际长度动态调整log_data的大小
while((header_len+ret)>=clog_data_length)
{
clog_data_length+=clog_data_length;
log_data=(char*)realloc(log_data, clog_data_length+2);
log_ptr=log_data+header_len;
va_list args;
va_start(args, fmt);
ret=vsnprintf(log_ptr,clog_data_length-header_len,fmt, args);
va_end(args);
}
if(log_ptr[ret-1]!='\n')
{
log_ptr[ret]='\n';
ret++;
}
log_ptr[ret]='\0';
ret++;
log_ptr+=ret;
total_len=(uint64_t)(log_ptr-log_data);
memcpy(log_data,&total_len,sizeof(uint64_t));
//fprintf(stdout,"begin outptu device:%lu\n",total_len);
//device output
#if SUPPORT_MULTI_PROCESS
#if DATA_TRANSFER_WAY == 1
log_output_tcp(log_data);
#elif DATA_TRANSFER_WAY == 2
log_output_udp(log_data);
#elif DATA_TRANSFER_WAY == 0
log_output_shm(log_data);
#endif
#else
#if SUPPORT_CLOG_FILE
log_output_file(log_data);
#endif
#if SUPPORT_CLOG_CONSOLE
log_output_console(log_data);
#endif
#endif
free(log_data);
log_data=NULL;
return;
}
consoleclog.c
#include "clog.h"
#include
#include
#include
static pthread_mutex_t log_console_mutex = PTHREAD_MUTEX_INITIALIZER;
static Clog_Print_Level log_console_level=CLOG_INFO;
static Clog_Console_FG_Color log_console_fg_color[5]={FG_DEFAULT,FG_DEFAULT,FG_DEFAULT,FG_DEFAULT,FG_DEFAULT};
void set_log_console_level(Clog_Print_Level plevel)
{
log_console_level=plevel;
}
void set_console_level_color(Clog_Print_Level plevel,Clog_Console_FG_Color fg_color)
{
switch (plevel)
{
case CLOG_ERROR:
{
log_console_fg_color[0]=fg_color;
break;
}
case CLOG_WARNING:
{
log_console_fg_color[1]=fg_color;
break;
}
case CLOG_INFO:
{
log_console_fg_color[2]=fg_color;
break;
}
case CLOG_DEBUG:
{
log_console_fg_color[3]=fg_color;
break;
}
case CLOG_TRACE:
{
log_console_fg_color[4]=fg_color;
break;
}
}
}
void log_output_console(const char* clog_data)
{
char* log_ptr=(char*)clog_data;
uint64_t log_len=((uint64_t*)log_ptr)[0]-sizeof(uint64_t)-sizeof(uint8_t);
log_ptr+=sizeof(uint64_t);
Clog_Print_Level plevel=(Clog_Print_Level)(((uint8_t*)log_ptr)[0]);
log_ptr+=sizeof(uint8_t);
//fprintf(stdout,"console:total_len:%lu,plevel=%d\n",log_len,plevel);
if(plevel<=log_console_level)
{
pthread_mutex_lock (&log_console_mutex);
printf("\x1b[0;%dm%s\x1b[0m", (int)log_console_fg_color[(int)plevel], log_ptr);
pthread_mutex_unlock (&log_console_mutex);
}
}
fileclog.c
#include "clog.h"
#include
#include
#include
#include
#include
#include
#include
static pthread_mutex_t log_file_mutex = PTHREAD_MUTEX_INITIALIZER;
static FILE* log_file_fp=NULL;
static Clog_Print_Level log_file_level=CLOG_INFO;
static int log_file_size=0;
static int log_file_index=0;
static char log_file_save_dir[128]="\0";
int open_file()
{
char filename[256];
time_t timep;
struct tm *ptm;
time(&timep);
ptm = gmtime(&timep);
sprintf(filename,"%s/clog_%04d-%02d-%02d_%d.log",log_file_save_dir,ptm->tm_year+1900,ptm->tm_mon+1, ptm->tm_mday,log_file_index);
log_file_fp=fopen(filename,"w+");
if(log_file_fp==NULL)
{
fprintf(stderr,"The log file failed to open:%s\n",filename);
return -1;
}
log_file_size=0;
return 0;
}
int set_log_file_save_dir(const char logdir[128])
{
//check is dir
struct stat file_info;
if (stat(logdir, &file_info) < 0)
{
fprintf(stderr,"get stat failed:%s\n",logdir);
return -1;
}
if (S_ISDIR(file_info.st_mode)==0)
{
fprintf(stderr,"%s is not a dir\n",logdir);
return -1;
}
if (access(logdir,W_OK | F_OK)<0)
{
fprintf(stderr,"The current user does not have write access to this directory:%s\n",logdir);
return -1;
}
strncpy(log_file_save_dir,logdir, sizeof(log_file_save_dir));
log_file_size=0;
log_file_index=0;
return open_file();
}
void set_log_file_level(Clog_Print_Level plevel)
{
log_file_level=plevel;
}
void log_output_file(const char* clog_data)
{
char* log_ptr=(char*)clog_data;
uint64_t log_len=((uint64_t*)log_ptr)[0]-sizeof(uint64_t)-sizeof(uint8_t);
log_ptr+=sizeof(uint64_t);
Clog_Print_Level plevel=(Clog_Print_Level)(((uint8_t*)log_ptr)[0]);
log_ptr+=sizeof(uint8_t);
//fprintf(stdout,"file:total_len:%lu,plevel=%d\n",log_len,plevel);
if(plevel<=log_file_level)
{
if(log_file_fp!=NULL)
{
pthread_mutex_lock (&log_file_mutex);
log_file_size+=fwrite(log_ptr,log_len-1,1,log_file_fp);
fflush(log_file_fp);
if(log_file_size>=CLOG_FILE_MAX_SIZE)
{
log_file_index++;
fclose(log_file_fp);
open_file();
}
pthread_mutex_unlock (&log_file_mutex);
}
}
}
shmclog.c
#include "clog.h"
#include
#include
#include
#include
#include
#include
#include
key_t shm_key=1000;
//无锁原子操作
#define CAS(a_ptr, a_oldVal, a_newVal) __sync_bool_compare_and_swap(a_ptr, a_oldVal, a_newVal)
//共享内存实现一读多写的无锁队列
typedef struct
{
volatile int readindex;
volatile int writeindex;
char shm_log_data[CLOG_SHM_QUEUE_COUNT][1+CLOG_SHM_QUEUE_LEN];
}SHM_CLOG_DATA;
SHM_CLOG_DATA* shm_clog_data_ptr=NULL;
int log_shm_server()
{
int shmid;
void *shm_addr;
// 创建共享内存
if ((shmid = shmget(shm_key, sizeof(SHM_CLOG_DATA), 0666 | IPC_CREAT)) < 0)
{
fprintf(stderr,"shmget create shm memory failed:errno(%d)-%s\n",errno,strerror(errno));
return -1;
}
fprintf(stdout,"shmget create shm memory successful\n");
//映射共享内存
if ((shm_addr = shmat(shmid, (void*)0, 0)) == (void*)-1)
{
fprintf(stderr,"shmat map shm memory failed:errno(%d)-%s\n",errno,strerror(errno));
return -1;
}
fprintf(stdout,"shmat map shm memory successful\n");
SHM_CLOG_DATA* shm_clog_data_ptr=(SHM_CLOG_DATA*)shm_addr;
//init data
shm_clog_data_ptr->readindex=0;
shm_clog_data_ptr->writeindex=0;
memset(shm_clog_data_ptr->shm_log_data,'\0',sizeof(shm_clog_data_ptr->shm_log_data));
int currentMaximumReadIndex;
int currentReadIndex;
char* log_ptr=NULL;
do{
currentReadIndex = shm_clog_data_ptr->readindex;
//fprintf(stdout,"currentReadIndex:%d\n",currentReadIndex);
log_ptr=shm_clog_data_ptr->shm_log_data[currentReadIndex];
while(!CAS(&(log_ptr[0]),1,0))
{
usleep(10*1000);//10ms
}
//begin write data to log
#if SUPPORT_CLOG_FILE
log_output_file(log_ptr+1);
#endif
#if SUPPORT_CLOG_CONSOLE
log_output_console(log_ptr+1);
#endif
CAS(&(shm_clog_data_ptr->readindex), currentReadIndex, (currentReadIndex + 1)%CLOG_SHM_QUEUE_COUNT);
}while(1);
shmdt(shm_addr);
return 0;
}
int log_shm_connect()
{
int shmid;
char *shm_addr;
// 创建共享内存
if ((shmid = shmget(shm_key, sizeof(SHM_CLOG_DATA), 0)) < 0)
{
fprintf(stderr,"shmget create shm memory failed:errno(%d)-%s\n",errno,strerror(errno));
return -1;
}
//映射共享内存
if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
{
fprintf(stderr,"shmat map shm memory failed:errno(%d)-%s\n",errno,strerror(errno));
return -1;
}
shm_clog_data_ptr=(SHM_CLOG_DATA*)shm_addr;
return 0;
}
int log_output_shm(const char* clog_data)
{
uint64_t queue_max_len=CLOG_SHM_QUEUE_LEN;
char* log_ptr=NULL;
int currentWriteIndex;
int currentReadIndex;
do{
currentWriteIndex=shm_clog_data_ptr->writeindex;
currentReadIndex=shm_clog_data_ptr->readindex;
if(((currentWriteIndex+1)%CLOG_SHM_QUEUE_COUNT) == (currentReadIndex%CLOG_SHM_QUEUE_COUNT))
{
//queue is full;
usleep(10*1000);//10ms
continue;
}
}while(!CAS(&(shm_clog_data_ptr->writeindex), currentWriteIndex, (currentWriteIndex+1)%CLOG_SHM_QUEUE_COUNT));
//fprintf(stdout,"currentWriteIndex:%d\n",currentWriteIndex);
log_ptr=shm_clog_data_ptr->shm_log_data[currentWriteIndex];
memcpy((log_ptr+1),clog_data,queue_max_len);
CAS(&(log_ptr[0]),0,1);
return 0;
}
udpclog.c
#include "clog.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int clog_udp_socket_fd=-1;
struct sockaddr_in clog_udp_sock_addr;
int log_set_udp(const char ip[16],unsigned short udp_port)
{
clog_udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&clog_udp_sock_addr, 0, sizeof(clog_udp_sock_addr));
clog_udp_sock_addr.sin_family = AF_INET;
clog_udp_sock_addr.sin_port = htons(udp_port);
clog_udp_sock_addr.sin_addr.s_addr = inet_addr(ip);
}
void log_output_udp(const char* clog_data)
{
if(clog_udp_socket_fd==-1)
{
return;
}
uint64_t total_len=((uint64_t*)clog_data)[0];
sendto(clog_udp_socket_fd, clog_data, total_len, 0, (struct sockaddr*)&clog_udp_sock_addr, sizeof(clog_udp_sock_addr));
return;
}
int log_udp_server(const char ip[16],unsigned short udp_port)
{
int udp_server_sockfd = socket(AF_INET,SOCK_DGRAM,0);
fprintf(stdout,"create server socket ssuccessful\n");
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(udp_port);
saddr.sin_addr.s_addr = inet_addr(ip);
if(bind(udp_server_sockfd,(struct sockaddr*)&saddr,sizeof(saddr))!=0)
{
fprintf(stderr,"server bind failed:errno(%d)-%s\n",errno,strerror(errno));
return -1;
}
fprintf(stdout,"server socket bind successful\n");
unsigned int max_length=sizeof(uint64_t)+sizeof(uint8_t)+ sizeof(char)*CLOG_UDP_LENGTH;
while(1)
{
int len = sizeof(caddr);
char *log_data=(char*)malloc(max_length);
recvfrom(udp_server_sockfd,log_data,max_length,0,(struct sockaddr*)&caddr,&len);
#if SUPPORT_CLOG_FILE
log_output_file(log_data);
#endif
#if SUPPORT_CLOG_CONSOLE
log_output_console(log_data);
#endif
}
close(udp_server_sockfd);
return 0;
}
tcpclog.c
#include "clog.h"
#include "tcp.h"
static int clog_tcp_socket_fd=-1;
int log_tcp_connect(const char ip[16],unsigned short tcp_port)
{
///定义sockfd
clog_tcp_socket_fd = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(tcp_port); ///服务器端口
servaddr.sin_addr.s_addr = inet_addr(ip); ///服务器ip
///连接服务器,成功返回0,错误返回-1
if (connect(clog_tcp_socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
fprintf(stderr,"connect clog tcp server(%s/%d) failed\n",ip,tcp_port);
return -1;
}
return 0;
}
static int clog_tcp_handle(int socket_fd,void* arg)
{
uint64_t ret=0;
uint64_t rd_len=0;
uint64_t total_len;
read(socket_fd,&total_len,sizeof(uint64_t));
char *log_data=(char*)malloc(total_len*sizeof(char));
*(uint64_t*)log_data=total_len;
char *log_ptr=log_data+sizeof(uint64_t);
total_len=total_len-sizeof(uint64_t);
ret=0;
rd_len=0;
while(ret<total_len)
{
rd_len=read(socket_fd,log_ptr,(total_len-ret));
log_ptr+=rd_len;
ret+=rd_len;
}
#if SUPPORT_CLOG_FILE
log_output_file(log_data);
#endif
#if SUPPORT_CLOG_CONSOLE
log_output_console(log_data);
#endif
free(log_data);
log_data=NULL;
return 1;
}
int log_tcp_server(unsigned short tcp_port,unsigned int thread_count)
{
int result=0;
server_struct *clog_server_info=initServerStruct(tcp_port,thread_count,clog_tcp_handle);
result=serverRun(clog_server_info);
free(clog_server_info);
return result;
}
void log_output_tcp(const char* clog_data)
{
if(clog_tcp_socket_fd==-1)
{
return;
}
uint64_t total_len=((uint64_t*)clog_data)[0];
write(clog_tcp_socket_fd,clog_data,total_len);
}
tcp.c 和tcp.h 的具体实现 见
基于epoll的多线程网络服务程序设计——C语言