使用 log4cxx 配置自定义和动态附加程序

Configuration with custom and dynamic appender with log4cxx

我想在代码中为记录器创建一个附加程序,但同时我想在属性文件中进行配置。我正在以这种方式创建 appender:

class Foo {
private:
    LoggerPtr logger;
public:
    Foo(int id) {
        logger = LoggerPtr(Logger::getLogger("foo." + std::to_string(id)));
        RollingFileAppender* appender = new RollingFileAppender();
        appender->setAppend(true);
        appender->setMaxFileSize("1MB");
        appender->setMaxBackupIndex(1);
        appender->setFile("foo." + std::to_string(id) + ".log");
        PatternLayout* layOut = new PatternLayout();
        layOut->setConversionPattern(
                "%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n");
        appender->setLayout(LayoutPtr(layOut));
        appender->setName("fooAppender");
        Pool p;
        appender->activateOptions(p);
        logger->addAppender(AppenderPtr(appender));
        logger->setAdditivity(false);
    }
    const LoggerPtr& getLogger() const {
        return logger;
    }
};

这里的目标是为 Foo class 的每个实例创建不同的文件,并且由于数字是动态的,我无法在属性文件中创建记录器(也许我可以从0 到 2*1024*1024 但这太疯狂了)。为了实现这个目标,我需要几个附加程序,但是我希望在属性文件中有类似的东西:

log4j.appender.foo=org.apache.log4j.RollingFileAppender
log4j.appender.foo.MaxFileSize=50MB
log4j.appender.foo.MaxBackupIndex=1
log4j.appender.foo.layout=org.apache.log4j.PatternLayout
log4j.appender.foo.layout.ConversionPattern=%p %t %c - %m%n

是否可以让自定义附加程序继续从属性文件中读取配置?

我自己回复。你需要什么:你需要创建一个新的自定义附加程序并将其设置为第一级记录器中的附加程序,而不是在代码中你可以克隆附加程序。作为奖励,在您的自定义附加程序中,您可以管理延迟的文件创建,因此如果没有日志,则不再有空文件;)这里的代码:

class MyLogger {
private:
    MyLogger() {
    }
public:
    static void cloneParentLogger(const std::string& parentName,
            const std::string& parentAppenderName, LoggerPtr& child,
            const std::string& childName) {
        std::string newName = parentName + "." + childName;
        LoggerPtr loggerMst = LoggerPtr(Logger::getLogger(parentName));
        Appender* app = loggerMst->getAppender(parentAppenderName);
        app->close();
        AppenderPtr newAppender = app->getClass().newInstance();
        if (newAppender->instanceof(FileAppender::getStaticClass())) {
            Appender* p = newAppender;
            reinterpret_cast<FileAppender*>(p)->setFile(newName + ".log");
        }
        child = LoggerPtr(Logger::getLogger(newName));
        newAppender->setName(childName);
        newAppender->setLayout(app->getLayout());
        Pool p;
        newAppender->activateOptions(p);
        child->addAppender(newAppender);
        child->setAdditivity(false);
    }
};
class Foo {
private:
    LoggerPtr logger;
public:
    Foo(int id) {
        MyLogger::cloneParentLogger("foo", "R1", logger, std::to_string(id));
    }
    const LoggerPtr& getLogger() const {
        return logger;
    }
};

属性文件

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG

log4j.logger.foo=DEBUG, R1

log4j.appender.R1=DelayedRollingFileAppender
log4j.appender.R1.MaxFileSize=50MB
log4j.appender.R1.MaxBackupIndex=1
log4j.appender.R1.layout=org.apache.log4j.PatternLayout
log4j.appender.R1.layout.ConversionPattern=%p %t %c - %m%n

带有延迟文件创建的自定义 appender:

#ifndef DELAYEDROLLINGFILEAPPENDER_H_
#define DELAYEDROLLINGFILEAPPENDER_H_

#include <log4cxx/rollingfileappender.h>
#include <log4cxx/helpers/object.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/helpers/classregistration.h>
#include <log4cxx/logstring.h>

namespace log4cxx {

class DelayedRollingFileAppender: public RollingFileAppender {
private:
    bool firstAppend;
    LogString file;
    bool app;
    bool bufferedIo;
    size_t bufferSize;
public:
    //DECLARE_LOG4CXX_OBJECT(DelayedRollingFileAppender)
    class ClazzDelayedRollingFileAppender: public helpers::Class {
    public:
        ClazzDelayedRollingFileAppender() :
                helpers::Class() {
        }
        virtual ~ClazzDelayedRollingFileAppender() {
        }
        virtual LogString getName() const {
            return LOG4CXX_STR("DelayedRollingFileAppender");
        }
        virtual helpers::ObjectPtr newInstance() const {
            return new DelayedRollingFileAppender();
        }
    };
    virtual const helpers::Class& getClass() const;
    static const helpers::Class& getStaticClass();
    static const helpers::ClassRegistration& registerClass();

    DelayedRollingFileAppender();
    virtual ~DelayedRollingFileAppender();
    virtual void append(const spi::LoggingEventPtr& event,
            helpers::Pool& pool1);
    virtual void setFile(const LogString& file, bool append, bool bufferedIO,
            size_t bufferSize, helpers::Pool& p);
};

} /* namespace log4cxx */

#endif /* DELAYEDROLLINGFILEAPPENDER_H_ */

Cpp 文件:

#include "DelayedRollingFileAppender.h"

#include <log4cxx/writerappender.h>
#include <log4cxx/helpers/fileoutputstream.h>
#include <log4cxx/helpers/bufferedwriter.h>

namespace log4cxx {

using namespace helpers;

//IMPLEMENT_LOG4CXX_OBJECT(DelayedRollingFileAppender)
const ::log4cxx::helpers::Class& DelayedRollingFileAppender::getClass() const {
    return getStaticClass();
}
const ::log4cxx::helpers::Class& DelayedRollingFileAppender::getStaticClass() {
    static ClazzDelayedRollingFileAppender theClass;
    return theClass;
}
const helpers::ClassRegistration& DelayedRollingFileAppender::registerClass() {
    static helpers::ClassRegistration classReg(
            DelayedRollingFileAppender::getStaticClass);
    return classReg;
}

namespace classes {
const ::log4cxx::helpers::ClassRegistration& DelayedRollingFileAppenderRegistration =
        DelayedRollingFileAppender::registerClass();
}

DelayedRollingFileAppender::DelayedRollingFileAppender() {
    firstAppend = true;
    this->app = false;
    this->bufferSize = 0;
    this->bufferedIo = false;
}

DelayedRollingFileAppender::~DelayedRollingFileAppender() {
}

void DelayedRollingFileAppender::append(const spi::LoggingEventPtr& event,
        helpers::Pool& pool1) {
    if (firstAppend) {
        firstAppend = false;
        FileAppender::setFile(file, app, bufferedIo, bufferSize, pool1);
    }
    WriterAppender::append(event, pool1);
}

void DelayedRollingFileAppender::setFile(const LogString& file, bool append,
        bool bufferedIO, size_t bufferSize, helpers::Pool& p) {
    this->file = file;
    this->app = append;
    this->bufferSize = bufferSize;
    this->bufferedIo = bufferedIO;

    OutputStreamPtr outStream;
    try {
        outStream = new FileOutputStream("/dev/null", false);
    } catch (IOException& ex) {
        throw;
    }

    WriterPtr newWriter(createWriter(outStream));

    if (bufferedIo) {
        newWriter = new BufferedWriter(newWriter, bufferSize);
    }
    setWriter(newWriter);
}

} /* namespace log4cxx */