/* 自定義打開、輸出、關閉日誌函數類型 */ typedef int funcOpenLog( LOG *g , char *log_pathfilename , void **open_handle ); typedef int funcWriteLog( LOG *g , void **open_handle , int log_level , char *buf , long len , long *writelen ); typedef int funcChangeTest( LOG *g , void **test_handle ); typedef int funcCloseLog( LOG *g , void **open_handle ); #define LOG_NO_OUTPUTFUNC NULL , NULL , NULL , NULL , NULL , NULL /* 設置輸出類型 */ _WINDLL_FUNC int SetLogOutput( LOG *g , int output , char *log_pathfilename , funcOpenLog *pfuncOpenLogFirst , funcOpenLog *pfuncOpenLog , funcWriteLog *pfuncWriteLog , funcChangeTest *pfuncChangeTest , funcCloseLog *pfuncCloseLog , funcCloseLog *pfuncCloseLogFinally );
funcOpenLog funcOpenLog_ConnectToLogServer ; int funcOpenLog_ConnectToLogServer( LOG *g , char *log_pathfilename , void **open_handle ) { char *ptr = NULL ; char *ptr2 = NULL ; long log_pathfilename_len ; char ch_len ; char ip[ MAXLEN_IP + 1 ] ; long port ; long timeout ; int nret = 0 ; if( IsLogOpened(g) == 1 ) return 0; /* 申請日誌打開環境句柄內存 */ (*open_handle) = (int*)malloc( sizeof(int) ) ; if( (*open_handle) == NULL ) { return -11; } /* 分析文件名和網絡地址 */ ptr = strchr( log_pathfilename , '@' ) ; if( ptr == NULL ) return -21; log_pathfilename_len = ptr - log_pathfilename ; ch_len = (char)log_pathfilename_len ; ptr++; ptr2 = strchr( ptr , ':' ) ; memset( ip , 0x00 , sizeof(ip) ); strncpy( ip , ptr , ptr2 - ptr ); ptr2++; port = atol(ptr2) ; /* 建立客戶端socket */ nret = TCPCreateClient( (int*)(*open_handle) ) ; if( nret ) return -31; /* 鏈接服務端socket */ nret = TCPConnectToServer( (int*)(*open_handle) , ip , port ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -32; } /* 發送文件名 */ timeout = 10 * 1000 ; nret = TCPSendData( *(int*)(*open_handle) , & ch_len , 1 , & timeout ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -33; } nret = TCPSendData( *(int*)(*open_handle) , log_pathfilename , log_pathfilename_len , & timeout ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -34; } SetOpenFlag(g,1); return 0; } funcWriteLog funcWriteLog_SendToLogServer ; int funcWriteLog_SendToLogServer( LOG *g , void **open_handle , int log_level , char *buf , long len , long *writelen ) { long timeout ; int nret = 0 ; if( IsLogOpened(g) == 0 ) return 0; /* 發送日誌數據 */ timeout = 10 * 1000 ; (*writelen) = TCPSendData( *(int*)(*open_handle) , buf , len , & timeout ) ; if( (*writelen) ) { /* 若是發送失敗,重連服務端,而後再發送,若是還失敗,報錯返回 */ funcCloseLog_DisconnectFromLogServer( g , open_handle ); nret = funcOpenLog_ConnectToLogServer( g , g->log_pathfilename , & (g->open_handle) ) ; if( nret ) return -41; timeout = 10 * 1000 ; (*writelen) = TCPSendData( *(int*)(*open_handle) , buf , len , & timeout ) ; if( (*writelen) <= 0 ) return -42; } return 0; } funcCloseLog funcCloseLog_DisconnectFromLogServer ; int funcCloseLog_DisconnectFromLogServer( LOG *g , void **open_handle ) { if( IsLogOpened(g) == 0 ) return 0; /* 斷開socket鏈接 */ CloseSocket( (int*)(*open_handle) ); /* 釋放日誌打開環境內存 */ free( (*open_handle) ); SetOpenFlag(g,0); return 0; }
#include <stdio.h> #include "LOGSERVER.h" #define LOG_STYLES_TEST ( LOG_STYLE_DATETIME | LOG_STYLE_LOGLEVEL | LOG_STYLE_PID | LOG_STYLE_TID | LOG_STYLE_SOURCE | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE ) int test_iLOG3SERVER() { LOG *g = NULL ; char buffer[ 64 + 1 ] = "" ; long buflen = sizeof(buffer) - 1 ; int nret = 0 ; /* 建立日誌句柄,帶後綴'G'的函數還會自動設置到線程安全的全局缺省日誌句柄 */ if( CreateLogHandleG() == NULL ) { printf( "CreateLogHandleG failed\n" ); return -1; } else { printf( "CreateLogHandleG ok\n" ); } /* 設置日誌屬性 */ nret = SetLogOutputG( LOG_OUTPUT_CALLBACK , "$ProgramFiles$/test_iLOG3SERVER.log@127.0.0.1 :7878" , & funcOpenLog_ConnectToLogServer , NULL , & funcWriteLog_SendToLogServer , NULL , NULL , & funcCloseLog_DisconnectFromLogServer ) ; /* 設置輸出類型時掛上那三個回調函數,實現自定義的鏈接遠程日誌服務器、輸出日誌數據到遠程日誌服務器、關閉通信鏈接功能 */ if( nret ) { printf( "SetLogOutputG failed\n" ); return -1; } SetLogLevelG( LOG_LEVEL_INFO ); SetLogStylesG( LOG_STYLES_TEST , LOG_NO_STYLEFUNC ); /* 輸出日誌 */ DebugLogG( __FILE__ , __LINE__ , "hello DEBUG" ); InfoLogG( __FILE__ , __LINE__ , "hello INFO" ); WarnLogG( __FILE__ , __LINE__ , "hello WARN" ); ErrorLogG( __FILE__ , __LINE__ , "hello ERROR" ); FatalLogG( __FILE__ , __LINE__ , "hello FATAL" ); DebugHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello DEBUG" ); InfoHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello INFO" ); WarnHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello WARN" ); ErrorHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello ERROR" ); FatalHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello FATAL" ); /* 釋放日誌句柄 */ DestroyLogHandleG(); return 0; } int main() { /* windows上須要作初始化 */ SocketSystemInitial(); return -test_iLOG3SERVER(); }
#ifndef _H_SERVER_ #define _H_SERVER_ /* * iLOG3SERVER - iLOG3簡單遠程服務器 * author : calvin * email : * history : 2014-02-11 v1.0.0 建立 */ #include <stdio.h> #include "LibX.h" #include "StringX.h" #include "Socket.h" #include "SocketTCP.h" #include "LOGSERVER.h" #define IP_LOGSERVER "0" #define PORT_LOGSERVER 7878 #define MAXCNT_LOGCLIENT 100 #define CLIENTSTATUS_UNUSED 0 #define CLIENTSTATUS_LOGGING 2 #define RECV_BUFFER_SIZE 1024 #ifndef MAXLEN_FILENAME #define MAXLEN_FILENAME 256 #endif struct SocketAddressExp { char ip [ MAXLEN_IP + 1 ] ; long port ; } ; struct LogClientAccept { char status ; /* 鏈接狀態 */ int clisock ; /* 已接受socket描述字 */ SOCKADDR cliaddr ; /* 已接受socket地址信息 */ struct SocketAddressExp cliaddr_exp ; /* 已接受socket地址信息(轉換爲易讀格式) */ char log_pathfilename[ MAXLEN_FILENAME + 1 ] ; FILE *fp ; } ; struct LogServerEnv { int lsnsock ; /* 偵聽socket描述字 */ SOCKADDR lsnaddr ; /* 偵聽socket地址信息 */ struct LogClientAccept client[ MAXCNT_LOGCLIENT ] ; /* 客戶端socket環境單元集 */ } ; int LogServer( char *server_ip , long server_port ); int SendSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); int ProcessSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); int ReceiveSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); #endif [/code] server.c [code=c] static int AcceptClientSocket( struct LogServerEnv *penv ) { int clisock ; SOCKADDR cliaddr ; struct SocketAddressExp cliaddr_exp ; long timeout ; char ch ; long ch_len ; char log_pathfilename[ MAXLEN_FILENAME + 1 ] ; long log_pathfilename_len ; char env_key[ MAXLEN_FILENAME + 1 ] ; long env_key_len ; char *env_val = NULL ; long env_val_len ; char *p1 = NULL , *p2 = NULL ; FILE *fp = NULL ; int i ; struct LogClientAccept *pclient = NULL ; int nret ; /* 接受新socket鏈接 */ nret = TCPAcceptFromClient( & (penv->lsnsock) , & clisock , & cliaddr ) ; if( nret ) { printf( "TCPAcceptFromClient failed[%d]errno[%d]\n" , nret , errno ); return 0; } else { memset( & cliaddr_exp , 0x00 , sizeof(cliaddr_exp.ip) ); GetSocketAddressIP( & cliaddr , cliaddr_exp.ip ); GetSocketAddressPort( & cliaddr , & (cliaddr_exp.port) ); printf( "TCPAcceptFromClient ok , ip[%s]port[%ld]\n" , cliaddr_exp.ip , cliaddr_exp.port ); } /* 接收文件名長度 */ timeout = 10 * 1000 ; ch = 0 ; ch_len = 1 ; nret = TCPReceiveData( clisock , & ch , & ch_len , & timeout ) ; if( nret ) { printf( "TCPReceiveData failed[%d]errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } memset( log_pathfilename , 0x00 , sizeof(log_pathfilename) ); log_pathfilename_len = (long)ch ; nret = TCPReceiveData( clisock , log_pathfilename , & log_pathfilename_len , & timeout ) ; if( nret ) { printf( "TCPReceiveData failed[%d]errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } p1 = strchr( log_pathfilename , '$' ); while( p1 ) { /* 展開環境變量 */ p2 = strchr( p1 + 1 , '$' ) ; if( p2 == NULL ) return LOG_RETURN_ERROR_PARAMETER; memset( env_key , 0x00 , sizeof(env_key) ); env_key_len = p2 - p1 + 1 ; strncpy( env_key , p1 + 1 , env_key_len - 2 ); env_val = getenv( env_key ) ; if( env_val == NULL ) { printf( "environment [%s] not found\n" , env_key ); CloseSocket( & clisock ); return 0; } env_val_len = strlen(env_val) ; if( log_pathfilename_len + ( env_val_len - env_key_len ) > sizeof(log_pathfilename)-1 ) { printf( "filename overflow\n" ); CloseSocket( & clisock ); return 0; } memmove( p2+1 + ( env_val_len - env_key_len ) , p2+1 , strlen(p2+1) + 1 ); memcpy( p1 , env_val , env_val_len ); log_pathfilename_len += env_val_len - env_key_len ; p1 = strchr( p1 + ( env_val_len - env_key_len ) , '$' ); } fp = fopen( log_pathfilename , "a" ) ; if( fp == NULL ) { printf( "fopen failed errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } /* 查詢未使用客戶端socket環境單元 */ for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status == CLIENTSTATUS_UNUSED ) { break; } } if( i >= MAXCNT_LOGCLIENT ) { printf( "太多的客戶端\n" ); CloseSocket( & clisock ); return 0; } /* 填充客戶端socket環境單元 */ pclient->clisock = clisock ; memcpy( & (pclient->cliaddr) , & cliaddr , sizeof(SOCKADDR) ); memcpy( & (pclient->cliaddr_exp) , & cliaddr_exp , sizeof(struct SocketAddressExp) ); strcpy( pclient->log_pathfilename , log_pathfilename ); pclient->fp = fp ; pclient->status = CLIENTSTATUS_LOGGING ; return 0; } int ReceiveSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ) { char recv_buffer[ RECV_BUFFER_SIZE + 1 ] ; int recv_len ; int nret = 0 ; /* 接收通信數據到臨時接收緩衝區 */ memset( recv_buffer , 0x00 , sizeof(recv_buffer) ); recv_len = sizeof(recv_buffer)-1 ; recv_len = recv( pselclient->clisock , recv_buffer , recv_len , 0 ) ; if( recv_len == 0 ) { printf( "socket closed by remote[%s:%ld]\n" , pselclient->cliaddr_exp.ip , pselclient->cliaddr_exp.port ); CloseSocket( & (pselclient->clisock) ); fclose( pselclient->fp ); pselclient->status = CLIENTSTATUS_UNUSED ; return 0; } else if( recv_len < 0 ) { printf( "read socket failed from remote[%s:%ld] , errno[%d]\n" , pselclient->cliaddr_exp.ip , pselclient->cliaddr_exp.port , errno ); CloseSocket( & (pselclient->clisock) ); fclose( pselclient->fp ); pselclient->status = CLIENTSTATUS_UNUSED ; return 0; } fprintf( pselclient->fp , "%s" , recv_buffer ); return 0; } int LogServer( char *server_ip , long server_port ) { struct LogServerEnv env , *penv = & env ; int selsocks[ 1 + MAXCNT_LOGCLIENT ] ; struct LogClientAccept *pselclient[ 1 + MAXCNT_LOGCLIENT ] ; int selsocks_count ; struct LogClientAccept *pclient = NULL ; int i ; int selsock_index ; int nret = 0 ; /* 初始化聊天環境 */ memset( penv , 0x00 , sizeof(struct LogServerEnv) ); /* 建立服務端偵聽socket */ nret = TCPCreateServer( & (penv->lsnsock) , & (penv->lsnaddr) , server_ip , server_port ) ; if( nret ) { printf( "TCPCreateServer failed[%d]errno[%d]\n" , nret , errno ); return -1; } else { printf( "TCPCreateServer ok , ip[%s]port[%ld]\n" , server_ip , server_port ); } /* 主循環 */ while(1) { /* 準備socket描述字集合 */ selsocks[0] = penv->lsnsock ; selsocks_count = 1 ; for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status != CLIENTSTATUS_UNUSED ) { selsocks[selsocks_count] = pclient->clisock ; pselclient[selsocks_count] = pclient ; selsocks_count++; } } /* 等待socket描述字事件 */ selsock_index = SelectSocket( selsocks , selsocks_count , SELECTSOCKET_READ , NULL ) ; if( selsock_index < 0 ) { printf( "SelectSocket failed[%d]errno[%d]\n" , selsock_index , errno ); return -1; } /* 處理socket描述字事件 */ if( selsock_index == 0 ) { /* 接受新socket鏈接 */ nret = AcceptClientSocket( penv ) ; if( nret ) { printf( "AcceptClientSocket failed[%d]errno[%d]\n" , nret , errno ); return -1; } } else { /* 接收已鏈接socket數據 */ nret = ReceiveSocketData( penv , pselclient[selsock_index] ) ; if( nret ) { printf( "ReceiveSocketData failed[%d]errno[%d]\n" , nret , errno ); return -1; } } } /* 關閉全部已鏈接socket */ for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status != CLIENTSTATUS_UNUSED ) { CloseSocket( & (pclient->clisock) ); fclose( pclient->fp ); } } /* 關閉服務端偵聽socket */ CloseSocket( & (penv->lsnsock) ); return 0; } static void usage( char *i ) { printf( "USAGE : %s server_ip server_port\n" , i ); return; } int main( int argc , char *argv[] ) { int nret = 0 ; if( argc != 1 + 2 ) { usage( argv[0] ); exit(7); } /* 初始化網絡通信環境(windows上須要) */ SocketSystemInitial(); /* 啓動聊天服務器 */ nret = -LogServer( argv[1] , atol(argv[2]) ) ; /* 銷燬網絡通信環境 */ SocketSystemDestroy(); return nret; }編譯連接經過,運行 客戶端顯示 CreateLogHandleG ok DestroyLogHandleG ok 服務端顯示 TCPCreateServer ok , ip[127.0.0.1]port[7878] TCPAcceptFromClient ok , ip[127.0.0.1]port[1823] socket closed by remote[127.0.0.1:1823] ...(服務端是併發迭代服務器) 打開"$ProgramFiles$/test_iLOG3SERVER.log",看到日誌成功遠程落地了 2014-02-13 20:53:38 | INFO | 776:2740:test_iLOG3SERVER.c:38 | hello INFO 2014-02-13 20:53:38 | WARN | 776:2740:test_iLOG3SERVER.c:39 | hello WARN 2014-02-13 20:53:38 | ERROR | 776:2740:test_iLOG3SERVER.c:40 | hello ERROR 2014-02-13 20:53:38 | FATAL | 776:2740:test_iLOG3SERVER.c:41 | hello FATAL 2014-02-13 20:53:38 | INFO | 776:2740:test_iLOG3SERVER.c:44 | hello INFO 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 2014-02-13 20:53:38 | WARN | 776:2740:test_iLOG3SERVER.c:45 | hello WARN 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 2014-02-13 20:53:38 | ERROR | 776:2740:test_iLOG3SERVER.c:46 | hello ERROR 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 2014-02-13 20:53:38 | FATAL | 776:2740:test_iLOG3SERVER.c:47 | hello FATAL 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 設置日誌輸出類型函數SetLogOutput的回調機制,能夠幫助咱們擴展實現不少有意思的自定義功能,這裏只是演示了日誌遠程落地,還能把日誌輸出到IBMMQ、本地數據庫等,開源日誌函數庫iLOG3實際上是實現了一個日誌控制框架,經過大量回調函數鉤子,你徹底能夠編寫本身的函數來替代內部默認實現的功能。 還有不少其它回調函數鉤子能實現更有趣的功能,你慢慢探索吧 ^_^ 是否是越看越心動了?那就趕忙下載來玩玩吧 首頁傳送門 : [url]http://git.oschina.net/calvinwilliams/iLOG3[/url] 源代碼包doc目錄中包含了用戶指南和參考手冊,裏面有更詳盡的說明 (本文中的源代碼取自iLOG3姐妹庫iLOG3SERVER,後續即將放出)