[log4cplus]: 快速搭建分布式日志系统

发布于:2024-08-15 ⋅ 阅读:(83) ⋅ 点赞:(0)

关键词: 日志系统 、日志分类、自动分文件夹、按时间(月/周/日/小时/分)轮替

一、引言

这里我默认看此文的我的朋友们都已经具备一定的基础,所以,我们本篇不打算讲关于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