C++日志库log4cplus:SocketAppender记录日志到log Server

来源:互联网 发布:期货数据接口 编辑:程序博客网 时间:2024/06/06 17:54

转载请注明出处:http://blog.csdn.net/jmppok/article/details/17375057

1.问题

C++程序在后台运行时,可通过log4cplus记录日志。当C++程序运行在远程服务器上时,我们就需要远程登陆到该服务器才能查看日志。进一步,如果该C++程序一个并行程序或者分布式程序,为了查看程序的运行状态,我们就需要登陆到N台服务器上,tail -f xx.log.这种情形听起来就很令人不爽,而实际上,很多服务端开发者都遇到过或正在遭受这个问题的困扰。


2.LoggingServer

作为Log4J的翻版,Log4cplus也提供了SockeAppender,可以通过SocketAppender将日志输出到一个指定的log server上,从而解决上述问题。

关于Log4cplus的介绍,请参考C++开源日志库log4cplus


在Log4cplus的源码包中,有一个loggingServer目录,该目录中实现了一个LoggingServer。

在编译Log4cplus时,会自动编译该目录,在目录中生成loggingServer可执行文件,当然可以自己make(需要依赖log4cplus库)。

loggingServer使用方式如下:

 ./loggingserver 9000 log4cplus.properties

9000表示监听的端口号(不需要地址,默认监听本机地址)

log4cplus.properties是一个log4cplus的配置文件,和普通的log4cplus配置文件相同,loggingserver收到各个socket发来的日志后,根据配置文件信息,将其写入文件。

下面是一个简单的配置文件示例:

log4cplus.rootLogger=DEBUG, STDOUT, ALL_MSGSlog4cplus.appender.STDOUT=log4cplus::ConsoleAppenderlog4cplus.appender.STDOUT.layout=log4cplus::PatternLayout#log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%nlog4cplus.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.loglog4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout#设置日志打印格式#log4cplus.appender.ALL_MSGS.layout.ConversionPattern=|%D:%d{%Q}|%p|%t|%l|%m|%nlog4cplus.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;};}intmain(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////////////////////////////////////////////////////////////////////////////////voidloggingserver::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,RemoteServerlog4cplus.appender.STDOUT=log4cplus::ConsoleAppenderlog4cplus.appender.STDOUT.layout=log4cplus::PatternLayout#log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%nlog4cplus.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.loglog4cplus.appender.ALL_MSGS.layout=log4cplus::PatternLayout#设置日志打印格式#log4cplus.appender.ALL_MSGS.layout.ConversionPattern=|%D:%d{%Q}|%p|%t|%l|%m|%nlog4cplus.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::DenyAllFilterlog4cplus.appender.RemoteServer=log4cplus::SocketAppenderlog4cplus.appender.RemoteServer.host=localhostlog4cplus.appender.RemoteServer.port=9000

上面第一行的RemoteServer和最后三行即为添加一个SocketAppender。将日志发送到远端的loggingserver。

当然对本地的日志记录没有影响,本地仍正常记录。

同时我们还可以设置多个RemoetServer....,不过貌似也没这个必要...


4.更加高端大气上档次

当然我们可以实现自己的loggingserver,更加的高端大气上档次。

        a.将来自不同客户端的日志分别存储;

        b.不同级别的日志单独存储;

        c.在发现错误时,邮件通知;

        d.实现一个B/S的日志浏览工具;

        e.日志入库;

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

        g.接入Storm(实时流处理框架)对其进行分析;

        ...


2 2
原创粉丝点击