C++日誌庫log4cplus:SocketAppender記錄日誌到log Server

轉載請註明出處:http://blog.csdn.net/jmppok/article/details/17375057
ios

1.問題

C++程序在後臺運行時,可經過log4cplus記錄日誌。當C++程序運行在遠程服務器上時,咱們就須要遠程登錄到該服務器才能查看日誌。進一步,若是該C++程序一個並行程序或者分佈式程序,爲了查看程序的運行狀態,咱們就須要登錄到N臺服務器上,tail -f xx.log.這種情形聽起來就很使人不爽,而實際上,不少服務端開發者都遇到過或正在遭受這個問題的困擾。express


2.LoggingServer

做爲Log4J的翻版,Log4cplus也提供了SockeAppender,能夠經過SocketAppender將日誌輸出到一個指定的log server上,從而解決上述問題。apache

關於Log4cplus的介紹,請參考C++開源日誌庫log4cplus服務器


在Log4cplus的源碼包中,有一個loggingServer目錄,該目錄中實現了一個LoggingServer。app

在編譯Log4cplus時,會自動編譯該目錄,在目錄中生成loggingServer可執行文件,固然能夠本身make(須要依賴log4cplus庫)。框架

loggingServer使用方式以下:less

./loggingserver 9000 log4cplus.properties

9000表示監聽的端口號(不須要地址,默認監聽本機地址)

log4cplus.properties是一個log4cplus的配置文件,和普通的log4cplus配置文件相同,loggingserver收到各個socket發來的日誌後,根據配置文件信息,將其寫入文件。socket

下面是一個簡單的配置文件示例:分佈式

log4cplus.rootLogger=DEBUG, STDOUT, ALL_MSGS


log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
#log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
log4cplus.appender.STDOUT.layout.ConversionPattern=[%-5p %d{%y-%m-%d %H:%M:%S}] [%l]%n%m%n%n


#設置日誌追加到文件尾
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender  

#設置日誌文件大小
log4cplus.appender.ALL_MSGS.MaxFileSize=100MB

#設置生成日誌最大個數
log4cplus.appender.ALL_MSGS.MaxBackupIndex=10

#設置輸出日誌路徑
log4cplus.appender.ALL_MSGS.File=log/test.log
log4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout
#設置日誌打印格式
#log4cplus.appender.ALL_MSGS.layout.ConversionPattern=|%D:%d{%Q}|%p|%t|%l|%m|%n
log4cplus.appender.ALL_MSGS.layout.ConversionPattern=[%-5p %d{%y-%m-%d %H:%M:%S}] [%l]%n%m%n%n
#匹配相同日誌級別,只有debug日誌才輸入到該文件中
#log4cplus.appender.ALL_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
#log4cplus.appender.DEBUG_MSGS.filters.1.LogLevelToMatch=DEBUG
#log4cplus.appender.DEBUG_MSGS.filters.1.AcceptOnMatch=true
#log4cplus.appender.DEBUG_MSGS.filters.2=log4cplus::spi::DenyAllFilter

loggingserver自己十分簡單,其代碼以下(固然若是以爲它不爽,你也能夠本身實現一個更cool的):

// Module:  LOG4CPLUS
// File:    loggingserver.cxx
// Created: 5/2003
// Author:  Tad E. Smith
//
//
// Copyright 2003-2010 Tad E. Smith
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstdlib>
#include <iostream>
#include <log4cplus/configurator.h>
#include <log4cplus/socketappender.h>
#include <log4cplus/helpers/socket.h>
#include <log4cplus/thread/threads.h>
#include <log4cplus/spi/loggingevent.h>


namespace loggingserver
{

class ClientThread : public log4cplus::thread::AbstractThread
{
public:
    ClientThread(log4cplus::helpers::Socket clientsock)
    : clientsock(clientsock) 
    {
        std::cout << "Received a client connection!!!!" << std::endl;
    }

    ~ClientThread()
    {
        std::cout << "Client connection closed." << std::endl;
    }

    virtual void run();

private:
    log4cplus::helpers::Socket clientsock;
};

}




int
main(int argc, char** argv)
{
    if(argc < 3) {
        std::cout << "Usage: port config_file" << std::endl;
        return 1;
    }
    int port = std::atoi(argv[1]);
    const log4cplus::tstring configFile = LOG4CPLUS_C_STR_TO_TSTRING(argv[2]);

    log4cplus::PropertyConfigurator config(configFile);
    config.configure();

    log4cplus::helpers::ServerSocket serverSocket(port);
    if (!serverSocket.isOpen()) {
        std::cout << "Could not open server socket, maybe port "
            << port << " is already in use." << std::endl;
        return 2;
    }

    while(1) {
        loggingserver::ClientThread *thr = 
            new loggingserver::ClientThread(serverSocket.accept());
        thr->start();
    }

    return 0;
}


////////////////////////////////////////////////////////////////////////////////
// loggingserver::ClientThread implementation
////////////////////////////////////////////////////////////////////////////////


void
loggingserver::ClientThread::run()
{
    while(1) {
        if(!clientsock.isOpen()) {
            return;
        }
        log4cplus::helpers::SocketBuffer msgSizeBuffer(sizeof(unsigned int));
        if(!clientsock.read(msgSizeBuffer)) {
            return;
        }

        unsigned int msgSize = msgSizeBuffer.readInt();

        log4cplus::helpers::SocketBuffer buffer(msgSize);
        if(!clientsock.read(buffer)) {
            return;
        }
        
        log4cplus::spi::InternalLoggingEvent event
            = log4cplus::helpers::readFromBuffer(buffer);
        log4cplus::Logger logger
            = log4cplus::Logger::getInstance(event.getLoggerName());
        logger.callAppenders(event);   
    }
}

3.應用程序中SocketAppender配置

前面啓動了LoggingServer,下面說一下須要收集其日誌的各個應用程序中配置。工具

說白了,就是在原來的基礎上加一個SocketAppender,SocketAppender會自動將日誌發送給loggingserver。這樣直接在loggingserver上就能夠查看全部服務器上的日誌信息啦。哥終於不用再擔憂大家的運行狀態啦!

log4cplus.rootLogger=DEBUG, STDOUT, ALL_MSGS,RemoteServer


log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout
#log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n
log4cplus.appender.STDOUT.layout.ConversionPattern=[%-5p %d{%y-%m-%d %H:%M:%S}] [%l]%n%m%n%n


#設置日誌追加到文件尾
log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender  

#設置日誌文件大小
log4cplus.appender.ALL_MSGS.MaxFileSize=100MB

#設置生成日誌最大個數
log4cplus.appender.ALL_MSGS.MaxBackupIndex=10

#設置輸出日誌路徑
log4cplus.appender.ALL_MSGS.File=log/test.log
log4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout
#設置日誌打印格式
#log4cplus.appender.ALL_MSGS.layout.ConversionPattern=|%D:%d{%Q}|%p|%t|%l|%m|%n
log4cplus.appender.ALL_MSGS.layout.ConversionPattern=[%-5p %d{%y-%m-%d %H:%M:%S}] [%l]%n%m%n%n
#匹配相同日誌級別,只有debug日誌才輸入到該文件中
#log4cplus.appender.ALL_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter
#log4cplus.appender.DEBUG_MSGS.filters.1.LogLevelToMatch=DEBUG
#log4cplus.appender.DEBUG_MSGS.filters.1.AcceptOnMatch=true
#log4cplus.appender.DEBUG_MSGS.filters.2=log4cplus::spi::DenyAllFilter

log4cplus.appender.RemoteServer=log4cplus::SocketAppender
log4cplus.appender.RemoteServer.host=localhost
log4cplus.appender.RemoteServer.port=9000

上面第一行的RemoteServer和最後三行即爲添加一個SocketAppender。將日誌發送到遠端的loggingserver。

固然對本地的日誌記錄沒有影響,本地仍正常記錄。

同時咱們還能夠設置多個RemoetServer....,不過貌似也沒這個必要...


4.更加高端大氣上檔次

固然咱們能夠實現本身的loggingserver,更加的高端大氣上檔次。

        a.未來自不一樣客戶端的日誌分別存儲;

        b.不一樣級別的日誌單獨存儲;

        c.在發現錯誤時,郵件通知;

        d.實現一個B/S的日誌瀏覽工具;

        e.日誌入庫;

        f.存入HDFS,用Hadoop Map/Reduce挖掘;

        g.接入Storm(實時流處理框架)對其進行分析;

        ...

相關文章
相關標籤/搜索