This is an automated email from the ASF dual-hosted git repository. swebb2066 pushed a commit to branch asynchronous_loggers in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
commit 4b94a352aa3853bb9e21fc3a19f35389a39df8ca Author: Stephen Webb <[email protected]> AuthorDate: Sat Oct 4 16:59:41 2025 +1000 Provide a configuration file option to make all logging asynchronous --- src/main/cpp/domconfigurator.cpp | 29 ++++++++++++++++++++++++++++- src/main/cpp/propertyconfigurator.cpp | 34 +++++++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp index 7c940858..f54fcd71 100644 --- a/src/main/cpp/domconfigurator.cpp +++ b/src/main/cpp/domconfigurator.cpp @@ -17,6 +17,7 @@ #include <log4cxx/logstring.h> #include <log4cxx/xml/domconfigurator.h> #include <log4cxx/appender.h> +#include <log4cxx/asyncappender.h> #include <log4cxx/layout.h> #include <log4cxx/logger.h> #include <log4cxx/logmanager.h> @@ -132,6 +133,7 @@ IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator) #define ERROR_HANDLER_TAG "errorHandler" #define REF_ATTR "ref" #define ADDITIVITY_ATTR "additivity" +#define ASYNCHRONOUS_ATTR "asynchronous-logging" #define THRESHOLD_ATTR "threshold" #define STRINGSTREAM_ATTR "stringstream" #define CONFIG_DEBUG_ATTR "configDebug" @@ -561,6 +563,10 @@ void DOMConfigurator::parseChildrenOfLoggerElement( { PropertySetter propSetter(logger); std::vector<AppenderPtr> newappenders; + AsyncAppenderPtr async; + auto pAppender = appenders.find(LOG4CXX_STR(ASYNCHRONOUS_ATTR)); + if (appenders.end() != pAppender) + async = log4cxx::cast<AsyncAppender>(pAppender->second); for (apr_xml_elem* currentElement = loggerElement->first_child; currentElement; @@ -572,6 +578,8 @@ void DOMConfigurator::parseChildrenOfLoggerElement( { if (auto appender = findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders)) { + if (log4cxx::cast<AsyncAppender>(appender)) // An explicitly configured AsyncAppender? + async.reset(); // Not required if (LogLog::isDebugEnabled()) { LogLog::debug(LOG4CXX_STR("Adding ") + Appender::getStaticClass().getName() @@ -579,6 +587,8 @@ void DOMConfigurator::parseChildrenOfLoggerElement( + LOG4CXX_STR(" to logger [") + logger->getName() + LOG4CXX_STR("]")); } newappenders.push_back(appender); + if (async) + async->addAppender(appender); } } else if (tagName == LEVEL_TAG) @@ -594,7 +604,12 @@ void DOMConfigurator::parseChildrenOfLoggerElement( setParameter(p, utf8Decoder, currentElement, propSetter); } } - if (newappenders.empty()) + if (async) + { + logger->replaceAppenders({async}); + m_priv->appenderAdded = true; + } + else if (newappenders.empty()) logger->removeAllAppenders(); else { @@ -1087,6 +1102,18 @@ void DOMConfigurator::parse( } } + auto lsAsynchronous = subst(getAttribute(utf8Decoder, element, ASYNCHRONOUS_ATTR)); + if (!lsAsynchronous.empty() && OptionConverter::toBoolean(lsAsynchronous, true)) + { + appenders[LOG4CXX_STR(ASYNCHRONOUS_ATTR)] = std::make_shared<AsyncAppender>(); + if (LogLog::isDebugEnabled()) + { + LogLog::debug(LOG4CXX_STR("Asynchronous logging =[") + + LogString(LOG4CXX_STR("true")) + + LOG4CXX_STR("]")); + } + } + LogString threadSignalValue = subst(getAttribute(utf8Decoder, element, THREAD_CONFIG_ATTR)); if ( !threadSignalValue.empty() && threadSignalValue != LOG4CXX_STR("NULL") ) diff --git a/src/main/cpp/propertyconfigurator.cpp b/src/main/cpp/propertyconfigurator.cpp index b1c1d939..95b7902d 100644 --- a/src/main/cpp/propertyconfigurator.cpp +++ b/src/main/cpp/propertyconfigurator.cpp @@ -17,6 +17,7 @@ #include <log4cxx/logstring.h> #include <log4cxx/propertyconfigurator.h> +#include <log4cxx/asyncappender.h> #include <log4cxx/helpers/properties.h> #include <log4cxx/helpers/loglog.h> #include <log4cxx/helpers/exception.h> @@ -231,6 +232,18 @@ spi::ConfigurationStatus PropertyConfigurator::doConfigure(helpers::Properties& } } + auto lsAsynchronous = OptionConverter::findAndSubst(LOG4CXX_STR("log4j.asynchronous-logging"), properties); + if (!lsAsynchronous.empty() && OptionConverter::toBoolean(lsAsynchronous, true)) + { + (*m_priv->registry)[LOG4CXX_STR("log4j.asynchronous-logging")] = std::make_shared<AsyncAppender>(); + if (LogLog::isDebugEnabled()) + { + LogLog::debug(LOG4CXX_STR("Asynchronous logging =[") + + LogString(LOG4CXX_STR("true")) + + LOG4CXX_STR("]")); + } + } + LogString threadConfigurationValue(properties.getProperty(LOG4CXX_STR("log4j.threadConfiguration"))); if ( threadConfigurationValue == LOG4CXX_STR("NoConfiguration") ) @@ -413,13 +426,15 @@ void PropertyConfigurator::parseLogger( } - AppenderPtr appender; - LogString appenderName; std::vector<AppenderPtr> newappenders; + AsyncAppenderPtr async; + auto pAppender = m_priv->registry->find(LOG4CXX_STR("log4j.asynchronous-logging")); + if (m_priv->registry->end() != pAppender) + async = log4cxx::cast<AsyncAppender>(pAppender->second); while (st.hasMoreTokens()) { - appenderName = StringHelper::trim(st.nextToken()); + auto appenderName = StringHelper::trim(st.nextToken()); if (appenderName.empty() || appenderName == LOG4CXX_STR(",")) { @@ -431,18 +446,23 @@ void PropertyConfigurator::parseLogger( LogLog::debug(LOG4CXX_STR("Parsing ") + Appender::getStaticClass().getName() + LOG4CXX_STR(" named [") + appenderName + LOG4CXX_STR("]")); } - appender = parseAppender(props, appenderName); - - if (appender != 0) + if (auto appender = parseAppender(props, appenderName)) { newappenders.push_back(appender); + if (log4cxx::cast<AsyncAppender>(appender)) // An explicitly configured AsyncAppender? + async.reset(); // Not required + if (async) + async->addAppender(appender); } } #if 15 < LOG4CXX_ABI_VERSION if (!newappenders.empty()) m_priv->appenderAdded = true; #endif - logger->reconfigure( newappenders, additivity ); + if (async) + logger->reconfigure( {async}, additivity ); + else + logger->reconfigure( newappenders, additivity ); } AppenderPtr PropertyConfigurator::parseAppender(
