Clog——基于C语言的日志系统设计

clog——一种基于Linux C的日志系统

在linux环境下使用c语言开发的一款日志系统clog,统一接口,功能丰富。

支持的功能

  • 支持多线程日志采集。
  • 支持多进程日志采集,多进程采用tcp、udp或共享内存通信。
  • 支持自定义日志格式。
  • 支持多方式日志输出,file、console。

代码结构

├── 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种日志级别,errorwarninginfodebugtrace

//日志级别
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
//设置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
//设置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();

使用demo

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <unistd.h>

#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 <string.h>
#include <stdint.h>

//解决__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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>

#include <unistd.h>
#include <sys/timeb.h>
#include <pthread.h>

//日志支持任意长度,默认时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 <stdio.h>
#include <stdint.h>
#include <pthread.h>

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 <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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 <stdio.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sched.h>

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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

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语言

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值