This is an automated email from the ASF dual-hosted git repository.
swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/master by this push:
new b452c0ea Ensure log events are sent to an appender during a
reconfiguration event (#491)
b452c0ea is described below
commit b452c0eaaef1c2d10bfca276d8776fd2995b3b85
Author: Stephen Webb <[email protected]>
AuthorDate: Fri Mar 28 09:59:34 2025 +1100
Ensure log events are sent to an appender during a reconfiguration event
(#491)
* Do not add the fallback appender to a logger without a reference to the
failed appender
---
src/main/cpp/appenderattachableimpl.cpp | 32 +++++++++++++++
src/main/cpp/asyncappender.cpp | 10 +++++
src/main/cpp/domconfigurator.cpp | 20 ++++-----
src/main/cpp/fallbackerrorhandler.cpp | 18 ++++----
src/main/cpp/logger.cpp | 30 ++++++++++----
src/main/cpp/rollingfileappender.cpp | 6 +--
src/main/include/log4cxx/asyncappender.h | 11 +++++
.../log4cxx/helpers/appenderattachableimpl.h | 11 +++++
src/main/include/log4cxx/logger.h | 23 ++++++++---
src/main/include/log4cxx/spi/appenderattachable.h | 18 ++++++++
src/test/cpp/varia/errorhandlertestcase.cpp | 48 ++++++++++++++++------
src/test/resources/input/xml/fallback1.xml | 12 +-----
src/test/resources/input/xml/fallback2.xml | 11 +----
13 files changed, 176 insertions(+), 74 deletions(-)
diff --git a/src/main/cpp/appenderattachableimpl.cpp
b/src/main/cpp/appenderattachableimpl.cpp
index ddd4cc3c..73d67355 100644
--- a/src/main/cpp/appenderattachableimpl.cpp
+++ b/src/main/cpp/appenderattachableimpl.cpp
@@ -167,4 +167,36 @@ void AppenderAttachableImpl::removeAppender(const
LogString& name)
}
}
+bool AppenderAttachableImpl::replaceAppender(const AppenderPtr& oldAppender,
const AppenderPtr& newAppender)
+{
+ bool found = false;
+ if (m_priv && oldAppender && newAppender)
+ {
+ auto oldName = oldAppender->getName();
+ std::lock_guard<std::mutex> lock( m_priv->m_mutex );
+ auto it = std::find_if(m_priv->appenderList.begin(),
m_priv->appenderList.end()
+ , [&oldName](const AppenderPtr& appender) -> bool
+ {
+ return oldName == appender->getName();
+ });
+ if (it != m_priv->appenderList.end())
+ {
+ *it = newAppender;
+ found = true;
+ }
+ }
+ return found;
+}
+
+void AppenderAttachableImpl::replaceAppenders(const AppenderList& newList)
+{
+ auto oldAppenders = getAllAppenders();
+ if (!m_priv)
+ m_priv = std::make_unique<AppenderAttachableImpl::priv_data>();
+ std::lock_guard<std::mutex> lock( m_priv->m_mutex );
+ for (auto a : oldAppenders)
+ a->close();
+ m_priv->appenderList = newList;
+}
+
diff --git a/src/main/cpp/asyncappender.cpp b/src/main/cpp/asyncappender.cpp
index 7c7caa8d..cec9f359 100644
--- a/src/main/cpp/asyncappender.cpp
+++ b/src/main/cpp/asyncappender.cpp
@@ -413,6 +413,16 @@ void AsyncAppender::removeAppender(const LogString& n)
priv->appenders.removeAppender(n);
}
+bool AsyncAppender::replaceAppender(const AppenderPtr& oldAppender, const
AppenderPtr& newAppender)
+{
+ return priv->appenders.replaceAppender(oldAppender, newAppender);
+}
+
+void AsyncAppender::replaceAppenders( const AppenderList& newList)
+{
+ priv->appenders.replaceAppenders(newList);
+}
+
bool AsyncAppender::getLocationInfo() const
{
return priv->locationInfo;
diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp
index 12648642..b8d5cc8f 100644
--- a/src/main/cpp/domconfigurator.cpp
+++ b/src/main/cpp/domconfigurator.cpp
@@ -535,10 +535,6 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
PropertySetter propSetter(logger);
std::vector<AppenderPtr> newappenders;
- // Remove all existing appenders from logger. They will be
- // reconstructed if need be.
- logger->removeAllAppenders();
-
for (apr_xml_elem* currentElement = loggerElement->first_child;
currentElement;
currentElement = currentElement->next)
@@ -550,12 +546,12 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
AppenderPtr appender = findAppenderByReference(p,
utf8Decoder, currentElement, doc, appenders);
LogString refName = subst(getAttribute(utf8Decoder,
currentElement, REF_ATTR));
- if (!LogLog::isDebugEnabled())
- ;
- else if (appender != 0)
+ if (appender)
{
- LogLog::debug(LOG4CXX_STR("Adding appender
named [") + refName +
- LOG4CXX_STR("] to logger [") +
logger->getName() + LOG4CXX_STR("]."));
+ if (LogLog::isDebugEnabled())
+ LogLog::debug(LOG4CXX_STR("Adding
appender named [") + refName +
+ LOG4CXX_STR("] to logger [") +
logger->getName() + LOG4CXX_STR("]."));
+ newappenders.push_back(appender);
}
else
{
@@ -563,8 +559,6 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
LOG4CXX_STR("] not found."));
}
- logger->addAppender(appender);
-
}
else if (tagName == LEVEL_TAG)
{
@@ -579,6 +573,10 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
setParameter(p, utf8Decoder, currentElement,
propSetter);
}
}
+ if (newappenders.empty())
+ logger->removeAllAppenders();
+ else
+ logger->replaceAppenders(newappenders);
propSetter.activate(p);
}
diff --git a/src/main/cpp/fallbackerrorhandler.cpp
b/src/main/cpp/fallbackerrorhandler.cpp
index 0b5f7d93..3d5f2bef 100644
--- a/src/main/cpp/fallbackerrorhandler.cpp
+++ b/src/main/cpp/fallbackerrorhandler.cpp
@@ -87,22 +87,18 @@ void FallbackErrorHandler::error(const LogString& message,
{
if (LogLog::isDebugEnabled())
{
- LogLog::debug(((LogString) LOG4CXX_STR("FB: Searching
for ["))
- + primaryLocked->getName() + LOG4CXX_STR("] in
logger [")
- + l->getName() + LOG4CXX_STR("]."));
- LogLog::debug(((LogString) LOG4CXX_STR("FB: Replacing
["))
- + primaryLocked->getName() + LOG4CXX_STR("] by
[")
+ LogLog::debug(LOG4CXX_STR("FB: Replacing [")
+ + primaryLocked->getName() + LOG4CXX_STR("]
with [")
+ backupLocked->getName() + LOG4CXX_STR("] in
logger [")
+ l->getName() + LOG4CXX_STR("]."));
}
- l->removeAppender(primaryLocked);
- if (LogLog::isDebugEnabled())
+ if (!l->replaceAppender(primaryLocked, backupLocked))
{
- LogLog::debug(((LogString) LOG4CXX_STR("FB: Adding
appender ["))
- + backupLocked->getName() + LOG4CXX_STR("] to
logger ")
- + l->getName());
+ LogLog::debug(LOG4CXX_STR("FB: Failed to replace [")
+ + primaryLocked->getName() + LOG4CXX_STR("]
with [")
+ + backupLocked->getName() + LOG4CXX_STR("] in
logger [")
+ + l->getName() + LOG4CXX_STR("]."));
}
- l->addAppender(backupLocked);
}
m_priv->errorReported = true;
}
diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp
index 75781453..e814620f 100644
--- a/src/main/cpp/logger.cpp
+++ b/src/main/cpp/logger.cpp
@@ -112,23 +112,35 @@ void Logger::addAppender(const AppenderPtr newAppender)
}
}
-void Logger::reconfigure( const std::vector<AppenderPtr>& appenders, bool
additive1 )
+bool Logger::replaceAppender(const AppenderPtr& oldAppender, const
AppenderPtr& newAppender)
{
- m_priv->additive = additive1;
+ bool result = m_priv->aai.replaceAppender(oldAppender, newAppender);
+ if (result)
+ {
+ if (auto rep = getHierarchy())
+ rep->fireAddAppenderEvent(this, newAppender.get());
+ }
+ return result;
+}
- m_priv->aai.removeAllAppenders();
+void Logger::replaceAppenders( const AppenderList& newList)
+{
+ m_priv->aai.replaceAppenders(newList);
- for (auto const& item : appenders)
+ if (auto rep = getHierarchy())
{
- m_priv->aai.addAppender(item);
-
- if (auto rep = getHierarchy())
- {
+ for (auto const& item : newList)
rep->fireAddAppenderEvent(this, item.get());
- }
}
}
+void Logger::reconfigure( const AppenderList& newList, bool newAdditivity )
+{
+ m_priv->additive = newAdditivity;
+
+ replaceAppenders(newList);
+}
+
void Logger::callAppenders(const spi::LoggingEventPtr& event, Pool& p) const
{
int writes = 0;
diff --git a/src/main/cpp/rollingfileappender.cpp
b/src/main/cpp/rollingfileappender.cpp
index f4c78ed5..954cd929 100644
--- a/src/main/cpp/rollingfileappender.cpp
+++ b/src/main/cpp/rollingfileappender.cpp
@@ -253,11 +253,9 @@ void RollingFileAppender::activateOptions(Pool& p)
FileAppender::activateOptionsInternal(p);
}
- catch (std::exception&)
+ catch (std::exception& ex)
{
- LogLog::warn(
- LogString(LOG4CXX_STR("Exception will
initializing RollingFileAppender named "))
- + getName());
+ LogLog::warn(LOG4CXX_STR("Exception activating
RollingFileAppender ") + getName(), ex);
}
}
}
diff --git a/src/main/include/log4cxx/asyncappender.h
b/src/main/include/log4cxx/asyncappender.h
index b957d03a..e1ea6c8e 100644
--- a/src/main/include/log4cxx/asyncappender.h
+++ b/src/main/include/log4cxx/asyncappender.h
@@ -152,6 +152,17 @@ class LOG4CXX_EXPORT AsyncAppender :
*/
void removeAppender(const LogString& name) override;
+ /**
+ * Replace \c oldAppender with \c newAppender.
+ * @return true if oldAppender was replaced with newAppender.
+ */
+ bool replaceAppender(const AppenderPtr& oldAppender, const
AppenderPtr& newAppender) LOG4CXX_16_VIRTUAL_SPECIFIER;
+
+ /**
+ * Replace any previously added appenders with \c newList.
+ */
+ void replaceAppenders(const AppenderList& newList)
LOG4CXX_16_VIRTUAL_SPECIFIER;
+
/**
* The <b>LocationInfo</b> attribute is provided for
compatibility
* with log4j and has no effect on the log output.
diff --git a/src/main/include/log4cxx/helpers/appenderattachableimpl.h
b/src/main/include/log4cxx/helpers/appenderattachableimpl.h
index 73c370ec..289512e9 100644
--- a/src/main/include/log4cxx/helpers/appenderattachableimpl.h
+++ b/src/main/include/log4cxx/helpers/appenderattachableimpl.h
@@ -101,6 +101,17 @@ class LOG4CXX_EXPORT AppenderAttachableImpl :
*/
void removeAppender(const LogString& name) override;
+ /**
+ * Replace \c oldAppender with \c newAppender.
+ * @return true if oldAppender was replaced with newAppender.
+ */
+ bool replaceAppender(const AppenderPtr& oldAppender, const
AppenderPtr& newAppender) LOG4CXX_16_VIRTUAL_SPECIFIER;
+
+ /**
+ * Replace any previously added appenders with \c newList.
+ */
+ void replaceAppenders(const AppenderList& newList)
LOG4CXX_16_VIRTUAL_SPECIFIER;
+
private:
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(priv_data, m_priv)
diff --git a/src/main/include/log4cxx/logger.h
b/src/main/include/log4cxx/logger.h
index f16aaf58..91181504 100644
--- a/src/main/include/log4cxx/logger.h
+++ b/src/main/include/log4cxx/logger.h
@@ -788,8 +788,7 @@ class LOG4CXX_EXPORT Logger
Return the the LoggerRepository where this
<code>Logger</code> is attached.
*/
- LOG4CXX_NS::spi::LoggerRepository* getLoggerRepository() const;
-
+ spi::LoggerRepository* getLoggerRepository() const;
/**
* Get the logger name.
@@ -1791,6 +1790,17 @@ class LOG4CXX_EXPORT Logger
*/
void removeAppender(const LogString& name) override;
+ /**
+ * Replace \c oldAppender with \c newAppender.
+ * @return true if oldAppender was replaced with newAppender.
+ */
+ bool replaceAppender(const AppenderPtr& oldAppender, const
AppenderPtr& newAppender) LOG4CXX_16_VIRTUAL_SPECIFIER;
+
+ /**
+ * Replace all previously added appenders with \c newList.
+ */
+ void replaceAppenders(const AppenderList& newList)
LOG4CXX_16_VIRTUAL_SPECIFIER;
+
/**
Set the additivity flag for this logger.
*/
@@ -2095,12 +2105,13 @@ class LOG4CXX_EXPORT Logger
void trace(const std::string& msg) const;
/**
- * Reconfigure this logger by configuring all of the appenders.
+ * Replace all current appenders with \c newList and
+ * set the additivity flag to \c newAdditivity.
*
- * @param appenders The appenders to set. Any currently
existing appenders are removed.
- * @param additivity The additivity of this logger
+ * @param newList The appenders to set.
+ * @param newAdditivity Whether this logger should send events
to its parent.
*/
- void reconfigure( const std::vector<AppenderPtr>& appenders,
bool additivity );
+ void reconfigure( const AppenderList& newList, bool
newAdditivity );
private:
//
diff --git a/src/main/include/log4cxx/spi/appenderattachable.h
b/src/main/include/log4cxx/spi/appenderattachable.h
index 93f77605..2498dc96 100644
--- a/src/main/include/log4cxx/spi/appenderattachable.h
+++ b/src/main/include/log4cxx/spi/appenderattachable.h
@@ -72,6 +72,19 @@ class LOG4CXX_EXPORT AppenderAttachable : public virtual
helpers::Object
*/
virtual void removeAppender(const LogString& name) = 0;
+#if 15 < LOG4CXX_ABI_VERSION
+ /**
+ * Replace \c oldAppender with \c newAppender.
+ * @return true if oldAppender was replaced with newAppender.
+ */
+ virtual bool replaceAppender(const AppenderPtr& oldAppender,
const AppenderPtr& newAppender) = 0;
+
+ /**
+ * Replace any previously added appenders with \c newList.
+ */
+ virtual void replaceAppenders(const AppenderList& newList) = 0;
+#endif
+
// Dtor
virtual ~AppenderAttachable() {}
};
@@ -80,5 +93,10 @@ LOG4CXX_PTR_DEF(AppenderAttachable);
}
}
+#if 15 < LOG4CXX_ABI_VERSION
+#define LOG4CXX_16_VIRTUAL_SPECIFIER override
+#else
+#define LOG4CXX_16_VIRTUAL_SPECIFIER
+#endif
#endif //_LOG4CXX_SPI_APPENDER_ATTACHABLE_H_
diff --git a/src/test/cpp/varia/errorhandlertestcase.cpp
b/src/test/cpp/varia/errorhandlertestcase.cpp
index c8cf517f..468ab4bf 100644
--- a/src/test/cpp/varia/errorhandlertestcase.cpp
+++ b/src/test/cpp/varia/errorhandlertestcase.cpp
@@ -21,6 +21,7 @@
#include <log4cxx/varia/fallbackerrorhandler.h>
#include <log4cxx/appender.h>
#include <log4cxx/helpers/loglog.h>
+#include <log4cxx/helpers/pool.h>
#include "../logunit.h"
#include "../util/transformer.h"
#include "../util/compare.h"
@@ -28,6 +29,20 @@
#include "../util/linenumberfilter.h"
#include <iostream>
+namespace
+{
+ /*
+ The following path is carefully designed to fail on Linux and Windows,
+ so that the appender FALLBACK is used instead and the test succeeds in
+ the end. Linux considers "." as current directory, which can not be
+ created as a file, while Windows strips "/."[1] internally and fails at
+ ":", which is an invalid name.
+
+ [1]:
https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations
+ */
+ log4cxx::LogString BadPath{ LOG4CXX_STR("output/xyz/:/.") };
+}
+
using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::xml;
@@ -71,16 +86,19 @@ public:
void test1()
{
DOMConfigurator::configure("input/xml/fallback1.xml");
- AppenderPtr appender =
root->getAppender(LOG4CXX_STR("PRIMARY"));
- FileAppenderPtr primary = log4cxx::cast<FileAppender>(appender);
- log4cxx::varia::FallbackErrorHandlerPtr eh;
- log4cxx::spi::ErrorHandlerPtr errHandle =
primary->getErrorHandler();
- eh =
log4cxx::cast<log4cxx::varia::FallbackErrorHandler>(errHandle);
+ auto appender = root->getAppender(LOG4CXX_STR("PRIMARY"));
+ auto primary = log4cxx::cast<FileAppender>(appender);
+ auto errHandle = primary->getErrorHandler();
+ auto eh =
log4cxx::cast<log4cxx::varia::FallbackErrorHandler>(errHandle);
LOGUNIT_ASSERT(eh != 0);
- common();
+ primary->setOption(LOG4CXX_STR("FILE"), BadPath);
+ Pool p;
+ primary->activateOptions(p);
LOGUNIT_ASSERT(eh->errorReported());
+ common();
+
std::string TEST1_PAT =
"FALLBACK - (root|test) - Message {0-9}";
@@ -110,16 +128,22 @@ public:
void test2()
{
DOMConfigurator::configure("input/xml/fallback2.xml");
- AppenderPtr appender =
root->getAppender(LOG4CXX_STR("PRIMARY"));
- FileAppenderPtr primary = log4cxx::cast<FileAppender>(appender);
- log4cxx::varia::FallbackErrorHandlerPtr eh;
- log4cxx::spi::ErrorHandlerPtr errHandle =
primary->getErrorHandler();
- eh =
log4cxx::cast<log4cxx::varia::FallbackErrorHandler>(errHandle);
+ auto appender = root->getAppender(LOG4CXX_STR("PRIMARY"));
+ auto primary = log4cxx::cast<FileAppender>(appender);
+ auto errHandle = primary->getErrorHandler();
+ auto eh = log4cxx::cast<varia::FallbackErrorHandler>(errHandle);
LOGUNIT_ASSERT(eh != 0);
+
+ // Also check the logger named "test" for a reference to
"PRIMARY" when "PRIMARY" fails
eh->setLogger(logger);
- common();
+
+ primary->setOption(LOG4CXX_STR("FILE"), BadPath);
+ Pool p;
+ primary->activateOptions(p);
LOGUNIT_ASSERT(eh->errorReported());
+ common();
+
std::string TEST1_PAT =
"FALLBACK - (root|test) - Message {0-9}";
diff --git a/src/test/resources/input/xml/fallback1.xml
b/src/test/resources/input/xml/fallback1.xml
index 83ed810e..5b21911c 100644
--- a/src/test/resources/input/xml/fallback1.xml
+++ b/src/test/resources/input/xml/fallback1.xml
@@ -26,17 +26,7 @@
<root-ref/>
<appender-ref ref="FALLBACK" />
</errorHandler>
-
- <!--
- The following path is carefully designed to fail on Linux and Windows,
- so that the appender FALLBACK is used instead and the test succeeds in
- the end. Linux considers "." as current directory, which can not be
- created as a file, while Windows strips "/."[1] internally and fails at
- ":", which is an invalid name.
-
- [1]:
https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations
- -->
- <param name="File" value="output/xyz/:/." />
+ <param name="File" value="output/xyz/x.log" />
<param name="Append" value="false" />
<layout class="org.apache.log4j.PatternLayout">
diff --git a/src/test/resources/input/xml/fallback2.xml
b/src/test/resources/input/xml/fallback2.xml
index e0f37003..4fc6e5bc 100644
--- a/src/test/resources/input/xml/fallback2.xml
+++ b/src/test/resources/input/xml/fallback2.xml
@@ -27,16 +27,7 @@
<appender-ref ref="FALLBACK" />
</errorHandler>
- <!--
- The following path is carefully designed to fail on Linux and Windows,
- so that the appender FALLBACK is used instead and the test succeeds in
- the end. Linux considers "." as current directory, which can not be
- created as a file, while Windows strips "/."[1] internally and fails at
- ":", which is an invalid name.
-
- [1]:
https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations
- -->
- <param name="File" value="output/xyz/:/." />
+ <param name="File" value="output/xyz/x.log" />
<param name="Append" value="false" />
<layout class="org.apache.log4j.PatternLayout">