開源純C日誌函數庫iLOG3快速入門(3、日誌過濾和轉檔後壓縮)

開源純C日誌函數庫iLOG3快速入門(3、日誌過濾和轉檔後壓縮)

前面一篇講了開源日誌函數庫iLOG3實際上是實現了一個日誌控制框架,經過大量回調函數鉤子,你徹底能夠編寫本身的函數來替代和擴展內部默認實現的功能。這篇介紹另外兩個鉤子:日誌過濾鉤子和轉檔先後鉤子。

某些場合下,日誌須要過濾後才真正輸出,好比捕獲某些關鍵詞,或想本身來檢查日誌等級等組合判斷,利用iLOG3的日誌過濾鉤子徹底能夠實現你的需求。
(今天的示例都到VC6上開發,VC6不支持c99,因此用不了日誌輸出宏,就用日誌輸出函數吧)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#if defined(_WIN32)
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#elif defined(__linux__) || defined(__unix)
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#endif

#include "LOG.h"

funcFilterLog FilterLog ;
int FilterLog( LOG *g , void **open_handle , int log_level , char *buf , long len )
{
    if( log_level == LOG_LEVEL_ERROR )
        return 0;
    
    if( strstr( buf , "FATAL" ) )
        return 0;
    
    return -1;
}

#define LOG_STYLES_FILTERLOG    ( LOG_STYLE_DATETIME | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE )

int test_filterlog()
{
    if( CreateLogHandleG() == NULL )
    {
        printf( "建立日誌句柄失敗errno[%d]\n" , errno );
        return -1;
    }
    else
    {
        printf( "建立日誌句柄成功\n" );
    }
    
    SetLogOutputG( LOG_OUTPUT_FILE , "test_filterlog.log" , LOG_NO_OUTPUTFUNC );
    SetLogLevelG( LOG_LEVEL_INFO );
    SetLogStylesG( LOG_STYLES_FILTERLOG , LOG_NO_STYLEFUNC );
    SetFilterLogFuncG( & FilterLog );
    
    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" );
    
    DestroyLogHandleG();
    printf( "銷燬句柄環境\n" );
    
    return 0;
}

int main()
{
    return -test_filterlog();
}
若是看過前面幾篇你應該能看出以上示例和之前相比只是多個一行代碼:掛接日誌過濾函數FilterLog
SetFilterLogFuncG( & FilterLog );

函數FilterLog實現了只要輸出日誌等級爲ERROR或日誌信息中出現了關鍵詞"FATAL"就照常輸出,其它都過濾掉。
在VC6中編譯,連接(加上庫iLOG3.lib),運行,打開日誌文件
test_filterlogfunc.log
2014-02-15 09:54:47 | hello ERROR
2014-02-15 09:54:47 | hello FATAL
很簡單吧? 下面介紹很重要的功能,日誌轉檔後壓縮,經過轉檔先後回調函數鉤子來實現。
轉檔後壓縮能夠減輕系統在存儲上的壓力,和轉檔功能配合能夠實現長時間自動運維。
上示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#if defined(_WIN32)
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#elif defined(__linux__) || defined(__unix)
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#endif

#include "LOG.h"

funcBeforeRotateFile BeforeRotateFile ;
int BeforeRotateFile( LOG *g , char *rotate_log_pathfilename )
{
    strcat( rotate_log_pathfilename , ".rar" );
    return 0;
}

funcAfterRotateFile AfterRotateFile ;
int AfterRotateFile( LOG *g , char *rotate_log_pathfilename )
{
    char    cmd[ 256 + 1 ] ;
    
    memset( cmd , 0x00 , sizeof(cmd) );
    SNPRINTF( cmd , sizeof(cmd)-1 , "Rar.exe m %s.rar %s" , rotate_log_pathfilename , rotate_log_pathfilename );
    system( cmd );
    
    return 0;
}

#define LOG_STYLES_PRESS    ( LOG_STYLE_DATETIME | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE )

int test_afterrotatefile()
{
    long        l ;
    
    if( CreateLogHandleG() == NULL )
    {
        printf( "建立日誌句柄失敗errno[%d]\n" , errno );
        return -1;
    }
    else
    {
        printf( "建立日誌句柄成功\n" );
    }
    
    SetLogOutputG( LOG_OUTPUT_FILE , "test_afterrotatefile.log" , LOG_NO_OUTPUTFUNC );
    SetLogLevelG( LOG_LEVEL_INFO );
    SetLogStylesG( LOG_STYLES_PRESS , LOG_NO_STYLEFUNC );
    SetLogRotateModeG( LOG_ROTATEMODE_SIZE );
    SetLogRotateSizeG( 100*1024 );
    SetBeforeRotateFileFuncG( & BeforeRotateFile );
    SetAfterRotateFileFuncG( & AfterRotateFile );
    
    for( l = 1 ; l <= 10000 ; l++ )
    {
        InfoLogG( __FILE__ , __LINE__ , "log" );
    }
    
    DestroyLogHandleG();  printf( "銷燬句柄環境\n" );

    return 0;
}
int main()
{
    return -test_afterrotatefile();
}
只是多了兩行代碼,設置了轉檔先後回調函數
SetBeforeRotateFileFuncG( & BeforeRotateFile );
SetAfterRotateFileFuncG( & AfterRotateFile );
轉檔前回調函數鉤子給予一個機會微調日誌文件名用於檢查文件是否存在,是否存在影響了按大小轉檔時的轉檔後綴數字。轉檔後回調函數鉤子在轉檔後給予一個機會用於處理轉檔後的日誌文件。
由於在WINDOWS上,我選擇了用WinRAR壓縮,那麼我寫的函數BeforeRotateFile把轉檔日誌文件名微調爲追加後綴.rar,函數AfterRotateFile組織一條壓縮命令並執行之。

編譯、連接、運行
輸出
建立日誌句柄成功

RAR 3.80    版權 (C) 1993-2008 Alexander Roshal    16 九月 2008
已註冊給 Federal Agency for Education

正在建立  壓縮文件 test_afterrotatefile.log.1.rar

正在添加    test_afterrotatefile.log.1                                  完成
正在刪除 test_afterrotatefile.log.1        已刪除
完成

RAR 3.80    版權 (C) 1993-2008 Alexander Roshal    16 九月 2008
已註冊給 Federal Agency for Education

正在建立  壓縮文件 test_afterrotatefile.log.2.rar

正在添加    test_afterrotatefile.log.2                                  完成
正在刪除 test_afterrotatefile.log.2        已刪除
完成
銷燬句柄環境
再看一下日誌輸出目錄下
2014-02-14  21:15            65,178 test_afterrotatefile.log
2014-02-14  21:15               207 test_afterrotatefile.log.1.rar
2014-02-14  21:15               207 test_afterrotatefile.log.2.rar
OK,轉檔的文件通通都被壓縮了,演示成功

個人工做環境絕大多數在Linux上,通常用gzip壓縮,那麼兩個回調函數能夠改爲(未編譯驗證)
funcBeforeRotateFile BeforeRotateFile ;
int BeforeRotateFile( LOG *g , char *rotate_log_pathfilename )
{
    strcat( rotate_log_pathfilename , ".gz" );
    return 0;
}

funcAfterRotateFile AfterRotateFile ;
int AfterRotateFile( LOG *g , char *rotate_log_pathfilename )
{
    char    cmd[ 256 + 1 ] ;
    
    memset( cmd , 0x00 , sizeof(cmd) );
    SNPRINTF( cmd , sizeof(cmd)-1 , "gzip %s" , rotate_log_pathfilename );
    system( cmd );
    
    return 0;
}
若是你寫的是跨平臺軟件,能夠用操做系統宏條件編譯。

若是轉檔大小設置很大,會致使轉檔後壓縮耗時很長,你能夠建立(fork)一個分離進程或建立一個分離線程(pthread_create或_beginthread、CreateThread)來並行壓縮而不影響日誌輸出函數的同步返回。

如今你又進一步理解了「開源日誌函數庫iLOG3實際上是實現了一個日誌控制框架」的意思了吧。
是否是越看越心動了?那就趕忙下載來玩玩吧

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