转载请注明出处: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_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(实时流处理框架)对其进行分析;
...
分享到:
相关推荐
自定义 Log4J 的 SocketAppender,在日志服务器和调用事件的各种客户端之间进行通信。 如何使用:AsynchListener - 通知程序 - 当日志服务器在特定端口和机器上准备就绪时,通知日志客户端是否准备好调用通知。 ...
Web4Log是一个基于java的web应用项目,使用Apache Wicket作为其前端框架,使用SocketAppender Log4J logger模拟其他应用的日志输出的tail命令。 它可以帮助您在一个基于 Web 的界面中监控来自一个或多个应用程序的 ...
Lilith ( ) 是 、 :trade_mark:、 :trade_mark: 和的日志记录和访问事件查看器。 它具有与 for log4j:trade_mark: 大致相当的功能,但强调稳定性、高性能和吞吐量。 与 Chainsaw 相比,它使用硬盘处理接收到的日志...
这是一个非常简单的库,用于向应用程序的 SocketAppender 添加全局上下文。 对于所有将日志写入 LogStash 服务器的分布式计算环境非常有用。 查看 src/main/resources/log4j.properties 以获取示例配置。 发展 使用...
Chainsaw是一个Log4J软件包的GUI日志查看器和过滤器。 它侦听使用SocketAppender发送的LoggingEvent对象,并将它们显示在表中。 可以根据优先级,线程名称,类别名称和消息来过滤事件。 它可以
使用日志进行编码的 Appender,并通过 TCP 将结果发送到远程主机。 为什么不使用普通的 SocketAppender? 奇怪的是,默认的 logback 并没有让你控制日志的编码方式。 相反,它使用 java 对象序列化并将结果发送到...
Eclipse 的简单 log4j 插件。 log4eclipse 打开一个端口,侦听 SocketAppender 输入流并在表中显示日志事件,根据它们的级别突出显示。
野生蝇 使用作为格式化程序的Wildfly Logstash... 通过在日志记录配置中添加格式化程序并在处理程序中引用该格式化程序,来在standalone/configuration/standalone.xml修改JBoss配置。 /subsystem=logging/custom-for
目录 ..........................................................................................................................I ...4. Appender ..........................................