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(

Reply via email to