Log4cxx custom appender

2019-02-14 00:46发布

问题:

Is it possible to write a custom appender for log4cxx and have it configurable via a properties file (like the built-in appenders)? I'd prefer doing this without having to rebuild log4cxx (e.g. by deriving/extending an existing appender), if possible.

Can you point me toward an example?

回答1:

You can inherit from AppenderSkeleton or WriterAppender and get the same underlying behaviors without having to rebuilt log4cxx.

http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/test/cpp/vectorappender.h?view=markup http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/test/cpp/vectorappender.cpp?view=markup



回答2:

brlcad's suggestion is correct - at my company we've used this method for our own custom appenders.

You can in fact already configure these from a configuration file - the macros like DECLARE_LOG4CXX_OBJECT(CustomAppenderClassName) in the class definition set up the log4cxx environment. You can refer to your appender type by your "CustomAppenderClassName". A configfile (old-style) showing a standard and custom appender, using the standard layouts for the custom appender:

# Set "realtime" logger level to DEBUG and create two appenders - one to be
# a standard rolling file appender, the other custom.
log4j.logger.realtime=ERROR, StandardAppender, CustomAppender

# StandardAppenderis set to be a RollingFileAppender
log4j.appender.StandardAppender=org.apache.log4j.RollingFileAppender
log4j.appender.StandardAppender.File=example.log

log4j.appender.StandardAppender.MaxFileSize=100KB
# Keep one backup file
log4j.appender.StandardAppender.MaxBackupIndex=1

# StandardAppender uses PatternLayout.
log4j.appender.StandardAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.StandardAppender.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

# CustomAppender uses PatternLayout too
log4j.appender.CustomAppender=CustomAppenderClassName
log4j.appender.CustomAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.CustomAppender.layout.ConversionPattern=%m


回答3:

I am adding this answer as the the links in the most rated answer appear to be from an older version. I have created a custom appender using version 1.2.0 following what was done in their SysLogAppender. At a high level you will need to do these steps:

  • Create an your own class which inherits their Appender class.
  • Implement the pure virtual functions void close() and void append(const spi::InternalLoggingEvent& event)
  • Register your appender class with the AppenderFactoryRegistry.

Here is an example class with code for class with the namespace yournamespace::ExampleCustomAppender:

#include <log4cplus/appender.h>

namespace yournamespace {
    class ExampleCustomAppender : public Appender
    {
    public:
        ExampleCustomAppender(const log4cplus::helpers::Properties & properties);

        // Dtor
        virtual ~ExampleCustomAppender();

        // Methods
        virtual void close();

        /** Register the appender with the factory registry. */
        static void registerAppender();

    protected:
        virtual void append(const spi::InternalLoggingEvent& event);
    };
}

Then the implementation of the methods:

#include <log4cplus/spi/factory.h>
#include <sstream>

namespace yournamespace {

    ExampleCustomAppender::ExampleCustomAppender(const helpers::Properties & properties)
        : Appender(properties)
    {
    // if you want to use properties to configure your object do so here
    }

    ExampleCustomAppender::~ExampleCustomAppender()
    {
    }

    void ExampleCustomAppender::registerAppender()
    {
        log4cplus::spi::AppenderFactoryRegistry & reg
            = log4cplus::spi::getAppenderFactoryRegistry();
        LOG4CPLUS_REG_PRODUCT(reg, "log4cplus::", ExampleCustomAppender, 
            yournamespace::, log4cplus::spi::AppenderFactory);
    }

    void ExampleCustomAppender::close()
    {
        // do anything you need to close the appender
        closed = true;
    }

    // This method does not need to be locked since it is called by
    // doAppend() which performs the locking
    void LoggingCallbackAppender::append(const spi::InternalLoggingEvent& event)
    {
        if (!closed) {
            std::stringstream logOutput;
            layout->formatAndAppend(logOutput, event);
            std::string outputString = logOutput.str();
        }
    }
}

and lastly an example of how it may be used in the configuration file:

log4cplus.rootLogger=INFO, STDOUT, ROLLING, EXAMPLE
// other definitions for STDOUT and ROLLING here and then  ...
log4cplus.appender.EXAMPLE=log4cplus::ExampleCustomAppender
log4cplus.appender.EXAMPLE.layout=log4cplus::PatternLayout
log4cplus.appender.EXAMPLE.layout.ConversionPattern=%d{%m/%d %H:%M:%S} [%t] %-5p %c{2} - %m%n

I did this code by cutting up some other code so it has not been compiled per se in this exact format. Let me know of any issues and I will correct it.