关键词: 日志系统 、日志分类、自动分文件夹、按时间(月/周/日/小时/分)轮替
一、引言
这里我默认看此文的我的朋友们都已经具备一定的基础,所以,我们本篇不打算讲关于log4cplus
的基础内容,文中如果涉及到没有吃透的点,需要朋友们动动自己聪明的脑袋和发财的手指,进一步寻找答案。
如标题所示,本篇我们不是单纯的在应用程序中集成log4cplus
,然后按照配置的日志生成规则生成日志文件;再此基础上我们玩点儿高级的(只能说是log4cplus
已经提供高级的模块),对,没错,我们要使用log4cplus
快速打造一个支持分布式的日志系统。
这里,我们有如下图所示的简单设计目标:
多个机台的服务数据,通过tcp 网络发送到日志服务器,然后日志服务处理日志信息存储到日志数据库或者文件中(本文以存储到文件为例)
想想,聪明的你肯定也觉得超级简单,一个C/S的框架足以搞定一切;只需要一点时间编写一个客户端,编写一个高性能的服务端,编写同一的日志接口;最多再额外的添加点扩展功能,譬如脚本的拓展,配置文件的拓展(脚本也好,配置文件也好,都是小case,自己写点解析的接口)… 诸多的小问题放在一起,就变成了时间成本。
所以,本文将基于log4plus
,教你如何快速打造一个高性能、可定制化的分布式日志系统。
二、日志服务端
这里不多说,无非是创建一个tcp的服务端,循环监听和读日志信息,数据分发处理(写文件)。
#include <cstdlib>
#include <list>
#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>
#include <log4cplus/thread/syncprims.h>
#include <log4cplus/log4cplus.h>
namespace loggingserver
{
typedef std::list<log4cplus::thread::AbstractThreadPtr> ThreadQueueType;
class ReaperThread
: public log4cplus::thread::AbstractThread
{
public:
ReaperThread (log4cplus::thread::Mutex & mtx_,
log4cplus::thread::ManualResetEvent & ev_,
ThreadQueueType & queue_)
: mtx (mtx_)
, ev (ev_)
, queue (queue_)
, stop (false)
{
}
virtual
~ReaperThread ()
{
}
virtual void run ();
void signal_exit ();
private:
log4cplus::thread::Mutex & mtx;
log4cplus::thread::ManualResetEvent & ev;
ThreadQueueType & queue;
bool stop;
};
typedef log4cplus::helpers::SharedObjectPtr<ReaperThread> ReaperThreadPtr;
void
ReaperThread::signal_exit ()
{
log4cplus::thread::MutexGuard guard (mtx);
stop = true;
ev.signal ();
}
void
ReaperThread::run ()
{
ThreadQueueType q;
while (true)
{
ev.timed_wait (30 * 1000);
{
log4cplus::thread::MutexGuard guard (mtx);
// Check exit condition as the very first thing.
if (stop)
{
std::cout << "Reaper thread is stopping..." << std::endl;
return;
}
ev.reset ();
q.swap (queue);
}
if (! q.empty ())
{
std::cout << "Reaper thread is reaping " << q.size () << " threads."
<< std::endl;
for (ThreadQueueType::iterator it = q.begin (), end_it = q.end ();
it != end_it; ++it)
{
AbstractThread & t = **it;
t.join ();
}
q.clear ();
}
}
}
/**
This class wraps ReaperThread thread and its queue.
*/
class Reaper
{
public:
Reaper ()
{
reaper_thread = ReaperThreadPtr (new ReaperThread (mtx, ev, queue));
reaper_thread->start ();
}
~Reaper ()
{
reaper_thread->signal_exit ();
reaper_thread->join ();
}
void visit (log4cplus::thread::AbstractThreadPtr const & thread_ptr);
private:
log4cplus::thread::Mutex mtx;
log4cplus::thread::ManualResetEvent ev;
ThreadQueueType queue;
ReaperThreadPtr reaper_thread;
};
void
Reaper::visit (log4cplus::thread::AbstractThreadPtr const & thread_ptr)
{
log4cplus::thread::MutexGuard guard (mtx);
queue