開源純C日誌函數庫iLOG3快速入門(4、使用合適的日誌輸出函數或宏)

iLOG3提供了多套日誌輸出函數或宏供用戶使用,根據本身的開發環境和軟件場景挑選合適的日誌輸出函數或宏將使你的代碼更簡潔優美。

先給個經常使用示例,使用最基礎的寫法

#include <stdio.h>
#include <errno.h>

#include "LOG.h"

#define LOG_STYLES_HELLO    ( LOG_STYLE_DATETIMEMS | LOG_STYLE_LOGLEVEL | LOG_STYLE_PID | LOG_STYLE_TID | LOG_STYLE_SOURCE | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE )

int test_hello()
{
    LOG        *g = NULL ;
    
    char        buffer[ 64 + 1 ] = "" ;
    long        buflen = sizeof(buffer) - 1 ;
    
    g = CreateLogHandle() ;
    if( g == NULL )
    {
        printf( "建立日誌句柄失敗errno[%d]\n" , errno );
        return -1;
    }
    
    printf( "建立日誌句柄成功\n" );
    
    SetLogOutput( g , LOG_OUTPUT_FILE , "test_hello.log" , LOG_NO_OUTPUTFUNC );
    SetLogLevel( g , LOG_LEVEL_INFO );
    SetLogStyles( g , LOG_STYLES_HELLO , LOG_NO_STYLEFUNC );
    
    DebugLog( g , __FILE__ , __LINE__ , "hello DEBUG" );
    InfoLog( g , __FILE__ , __LINE__ , "hello INFO" );
    WarnLog( g , __FILE__ , __LINE__ , "hello WARN" );
    ErrorLog( g , __FILE__ , __LINE__ , "hello ERROR" );
    FatalLog( g , __FILE__ , __LINE__ , "hello FATAL" );
    
    DebugHexLog( g , __FILE__ , __LINE__ , buffer , buflen , "緩衝區[%ld]" , buflen );
    InfoHexLog( g , __FILE__ , __LINE__ , buffer , buflen , "緩衝區[%ld]" , buflen );
    WarnHexLog( g , __FILE__ , __LINE__ , buffer , buflen , "緩衝區[%ld]" , buflen );
    ErrorHexLog( g , __FILE__ , __LINE__ , buffer , buflen , "緩衝區[%ld]" , buflen );
    FatalHexLog( g , __FILE__ , __LINE__ , buffer , buflen , "緩衝區[%ld]" , buflen );
    
    DestroyLogHandle( g );
    printf( "銷燬日誌句柄\n" );
    
    return 0;
}

int main()
{
    return -test_hello();
}
編譯連接運行
test_hello.log


2014-02-15 11:30:05.109000 | INFO  | 1200:3700:test_hello.c:29 | hello INFO
2014-02-15 11:30:05.109000 | WARN  | 1200:3700:test_hello.c:30 | hello WARN
2014-02-15 11:30:05.109000 | ERROR | 1200:3700:test_hello.c:31 | hello ERROR
2014-02-15 11:30:05.109000 | FATAL | 1200:3700:test_hello.c:32 | hello FATAL
2014-02-15 11:30:05.109000 | INFO  | 1200:3700:test_hello.c:35 | 緩衝區[64]
             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-15 11:30:05.109000 | WARN  | 1200:3700:test_hello.c:36 | 緩衝區[64]
             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-15 11:30:05.109000 | ERROR | 1200:3700:test_hello.c:37 | 緩衝區[64]
             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-15 11:30:05.109000 | FATAL | 1200:3700:test_hello.c:38 | 緩衝區[64]
             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   ................
咱們首先來看行日誌輸出函數
/* 寫日誌函數 */
_WINDLL_FUNC int WriteLog( LOG *g , char *c_filename , long c_fileline , int log_level , char *format , ... );
_WINDLL_FUNC int DebugLog( LOG *g , char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int InfoLog( LOG *g , char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int WarnLog( LOG *g , char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int ErrorLog( LOG *g , char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int FatalLog( LOG *g , char *c_filename , long c_fileline , char *format , ... );
/*
使用示例
InfoLog( g , __FILE__ , __LINE__ , "xxx處理完成,結果碼[%d]" , nret );
*/
在支持c99的編譯器上,建議用日誌輸出宏來代替日誌輸出函數,好處是少輸入了兩個參數__FILE__,__LINE__

/* 寫日誌函數的可變參數宏 */
#if ( defined __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901 )
#define WRITELOG( _g_ , _log_level_ , ... )    WriteLog( _g_ , __FILE__ , __LINE__ , _log_level_ , __VA_ARGS__ );
#define DEBUGLOG( _g_ , ... )            DebugLog( _g_ , __FILE__ , __LINE__ , __VA_ARGS__ );
#define INFOLOG( _g_ , ... )            InfoLog( _g_ , __FILE__ , __LINE__ , __VA_ARGS__ );
#define WARNLOG( _g_ , ... )            WarnLog( _g_ , __FILE__ , __LINE__ , __VA_ARGS__ );
#define ERRORLOG( _g_ , ... )            ErrorLog( _g_ , __FILE__ , __LINE__ , __VA_ARGS__ );
#define FATALLOG( _g_ , ... )            FatalLog( _g_ , __FILE__ , __LINE__ , __VA_ARGS__ );
#endif
/*
使用示例
INFOLOG( g , "xxx處理完成,結果碼[%d]" , nret );
*/
以上寫法有個不便之處,代碼中處處傳遞日誌句柄g。

在支持線程本地存儲(TLS)的環境中(據我所知Linux、AIX和WINDOWS都支持),可使用函數名追加後綴'G'的函數集合,好處是省略了第一個參數,即不用把日誌句柄在代碼中處處傳遞

#if ( defined _WIN32 ) || ( defined __linux__ ) || ( defined _AIX )
/* 寫日誌函數(基於線程本地存儲的缺省日誌句柄的函數集合版本) */
_WINDLL_FUNC int WriteLogG( char *c_filename , long c_fileline , int log_level , char *format , ... );
_WINDLL_FUNC int DebugLogG( char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int InfoLogG( char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int WarnLogG( char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int ErrorLogG( char *c_filename , long c_fileline , char *format , ... );
_WINDLL_FUNC int FatalLogG( char *c_filename , long c_fileline , char *format , ... );
/*
使用示例
InfoLogG( __FILE__ , __LINE__ , "xxx處理完成,結果碼[%d]" , nret );
*/
/* 寫日誌函數的可變參數宏(基於線程本地存儲的缺省日誌句柄的函數集合版本) */
#if ( defined __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901 )
#define WRITELOGG( _log_level_ , ... )    WriteLogG( __FILE__ , __LINE__ , _log_level_ , __VA_ARGS__ );
#define DEBUGLOGG( ... )        DebugLogG( __FILE__ , __LINE__ , __VA_ARGS__ );
#define INFOLOGG( ... )            InfoLogG( __FILE__ , __LINE__ , __VA_ARGS__ );
#define WARNLOGG( ... )            WarnLogG( __FILE__ , __LINE__ , __VA_ARGS__ );
#define ERRORLOGG( ... )        ErrorLogG( __FILE__ , __LINE__ , __VA_ARGS__ );
#define FATALLOGG( ... )        FatalLogG( __FILE__ , __LINE__ , __VA_ARGS__ );
#endif
#endif
/*
使用示例
INFOLOGG( "xxx處理完成,結果碼[%d]" , nret );
*/
以上日誌輸出函數或宏對應日誌句柄建立銷燬、設置屬性也是函數名追加後綴'G'的函數集合

_WINDLL_FUNC LOG *CreateLogHandleG();
_WINDLL_FUNC void DestroyLogHandleG();

_WINDLL_FUNC int SetLogOutputG( int output , char *log_pathfilename , funcOpenLog *pfuncOpenLogFirst , funcOpenLog *pfuncOpenLog , funcWriteLog *pfuncWriteLog , funcChangeTest *pfuncChangeTest , funcCloseLog *pfuncCloseLog , funcCloseLog *pfuncCloseLogFinally );
_WINDLL_FUNC int SetLogLevelG( int log_level );
_WINDLL_FUNC int SetLogStylesG( long log_styles , funcLogStyle *pfuncLogStyles );

_WINDLL_FUNC int SetLogOptionsG( int log_options );
_WINDLL_FUNC int SetLogFileChangeTestG( long interval );
_WINDLL_FUNC int SetLogCustLabelG( int index , char *cust_label );
_WINDLL_FUNC int SetLogRotateModeG( int rotate_mode );
_WINDLL_FUNC int SetLogRotateSizeG( long log_rotate_size );
_WINDLL_FUNC int SetLogRotatePressureFactorG( long pressure_factor );
_WINDLL_FUNC int SetBeforeRotateFileFuncG( funcAfterRotateFile *pfuncAfterRotateFile );
_WINDLL_FUNC int SetAfterRotateFileFuncG( funcAfterRotateFile *pfuncAfterRotateFile );
_WINDLL_FUNC int SetFilterLogFuncG( funcFilterLog *pfuncFilterLog );
_WINDLL_FUNC int SetLogBufferSizeG( long log_bufsize , long max_log_bufsize );
_WINDLL_FUNC int SetHexLogBufferSizeG( long hexlog_bufsize , long max_log_hexbufsize );
_WINDLL_FUNC int SetLogOutputFuncDirectlyG( funcOpenLog *pfuncOpenLogFirst , funcOpenLog *pfuncOpenLog , funcWriteLog *pfuncWriteLog , funcChangeTest *pfuncChangeTest , funcCloseLog *pfuncCloseLog , funcCloseLog *pfuncCloseLogFinally );
_WINDLL_FUNC int SetLogStyleFuncDirectlyG( funcLogStyle *pfuncLogStyle );
你能夠把線程本地存儲理解成,我聲明瞭一個全局的日誌句柄變量,因爲用線程本地存儲來修飾它,它會在不一樣線程間隔離使用,從而保證線程安全。

輸出塊日誌(十六進制)和行日誌同樣,如下是所有原型

/* 寫十六進制塊日誌函數 */
_WINDLL_FUNC int WriteHexLog( LOG *g , char *c_filename , long c_fileline , int log_level , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int DebugHexLog( LOG *g , char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int InfoHexLog( LOG *g , char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int WarnHexLog( LOG *g , char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int ErrorHexLog( LOG *g , char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int FatalHexLog( LOG *g , char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
/* 寫十六進制塊日誌的可變參數宏 */
#if ( defined __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901 )
#define WRITEHEXLOG( _g_ , _log_level_ , _buf_ , _buf_size_ , ... )    WriteHexLog( _g_ , __FILE__ , __LINE__ , _log_level_ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define DEBUGHEXLOG( _g_ , _buf_ , _buf_size_ , ... )            DebugHexLog( _g_ , __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define INFOHEXLOG( _g_ , _buf_ , _buf_size_ , ... )            InfoHexLog( _g_ , __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define WARNHEXLOG( _g_ , _buf_ , _buf_size_ , ... )            WarnHexLog( _g_ , __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define ERRORHEXLOG( _g_ , _buf_ , _buf_size_ , ... )            ErrorHexLog( _g_ , __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define FATALHEXLOG( _g_ , _buf_ , _buf_size_ , ... )            FatalHexLog( _g_ , __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#endif

#if ( defined _WIN32 ) || ( defined __linux__ ) || ( defined _AIX )
/* 寫十六進制塊日誌函數(基於線程本地存儲的缺省日誌句柄的函數集合版本) */
_WINDLL_FUNC int WriteHexLogG( char *c_filename , long c_fileline , int log_level , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int DebugHexLogG( char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int InfoHexLogG( char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int WarnHexLogG( char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int ErrorHexLogG( char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
_WINDLL_FUNC int FatalHexLogG( char *c_filename , long c_fileline , char *buffer , long buflen , char *format , ... );
/* 寫十六進制塊日誌的可變參數宏(基於線程本地存儲的缺省日誌句柄的函數集合版本) */
#if ( defined __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901 )
#define WRITEHEXLOGG( _log_level_ , _buf_ , _buf_size_ , ... )    WriteHexLogG( __FILE__ , __LINE__ , _log_level_ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define DEBUGHEXLOGG( _buf_ , _buf_size_ , ... )        DebugHexLogG( __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define INFOHEXLOGG( _buf_ , _buf_size_ , ... )            InfoHexLogG( __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define WARNHEXLOGG( _buf_ , _buf_size_ , ... )            WarnHexLogG( __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define ERRORHEXLOGG( _buf_ , _buf_size_ , ... )        ErrorHexLogG( __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#define FATALHEXLOGG( _buf_ , _buf_size_ , ... )        FatalHexLogG( __FILE__ , __LINE__ , _buf_ , _buf_size_ , __VA_ARGS__ );
#endif
#endif
拿函數InfoHexLog來說,當char *format有效(!=NULL)時先輸出行日誌,當char *buffer,long buflen有效(!=NULL,>0)時再輸出塊日誌,輸出函數內部有參數有效性檢查。

給個同時使用日誌輸出宏和線程本地存儲的寫法

#include <stdio.h>
#include <errno.h>

#include "LOG.h"

#define LOG_STYLES_HELLO    ( LOG_STYLE_DATETIMEMS | LOG_STYLE_LOGLEVEL | LOG_STYLE_PID | LOG_STYLE_TID | LOG_STYLE_SOURCE | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE )

int test_hello()
{
    char        buffer[ 64 + 1 ] = "" ;
    long        buflen = sizeof(buffer) - 1 ;
    
    if( CreateLogHandleG() == NULL )
    {
        printf( "建立日誌句柄失敗errno[%d]\n" , errno );
        return -1;
    }
    
    printf( "建立日誌句柄成功\n" );
    
    SetLogOutputG( LOG_OUTPUT_FILE , "test_hello.log" , LOG_NO_OUTPUTFUNC );
    SetLogLevelG( LOG_LEVEL_INFO );
    SetLogStylesG( LOG_STYLES_HELLO , LOG_NO_STYLEFUNC );
    
    DEBUGLOGG( "hello DEBUG" );
    INFOLOGG( "hello INFO" );
    WARNLOGG( "hello WARN" );
    ERRORLOGG( "hello ERROR" );
    FATALLOGG( "hello FATAL" );
    
    DEBUGHEXLOGG( buffer , buflen , "緩衝區[%ld]" , buflen );
    INFOHEXLOGG( buffer , buflen , "緩衝區[%ld]" , buflen );
    WARNHEXLOGG( buffer , buflen , "緩衝區[%ld]" , buflen );
    ERRORHEXLOGG( buffer , buflen , "緩衝區[%ld]" , buflen );
    FATALHEXLOGG( buffer , buflen , "緩衝區[%ld]" , buflen );
    
    DestroyLogHandleG();
    printf( "銷燬日誌句柄\n" );
    
    return 0;
}

int main()
{
    return -test_hello();
}
和第一個示例同樣的輸出效果,但比其簡潔了很多,固然你的環境得支持c99和線程本地存儲。
如下是一些編譯器的支持選項,僅供參考
gcc ... -std=c99 ...
xlc ... -qtls ...

是否是越看越心動了?那就趕忙下載來玩玩吧

首頁傳送門 : http://git.oschina.net/calvinwilliams/iLOG3 源代碼包doc目錄中包含了用戶指南和參考手冊,裏面有更詳盡的說明
相關文章
相關標籤/搜索