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 ab11809c Discard messages from an appender that sends logging requests
to itself (#551)
ab11809c is described below
commit ab11809c57addecb63271ff60c3a54481697613c
Author: Stephen Webb <[email protected]>
AuthorDate: Tue Oct 7 12:54:09 2025 +1100
Discard messages from an appender that sends logging requests to itself
(#551)
* Collect more information in BufferOverflowBehavior unit test
---
src/main/cpp/asyncappender.cpp | 91 +++++++++++++++++++++++++---------
src/test/cpp/asyncappendertestcase.cpp | 7 +--
2 files changed, 71 insertions(+), 27 deletions(-)
diff --git a/src/main/cpp/asyncappender.cpp b/src/main/cpp/asyncappender.cpp
index 35ae409a..8443d46f 100644
--- a/src/main/cpp/asyncappender.cpp
+++ b/src/main/cpp/asyncappender.cpp
@@ -58,7 +58,28 @@ class DiscardSummary
*/
int count;
+ /**
+ * Why created
+ */
+ LogString reason;
+
public:
+ /**
+ * Create new instance.
+ *
+ * @param event must not be null.
+ */
+ DiscardSummary(const LoggingEventPtr& event, const LogString&
reason);
+
+ /** Move values from \c src into a new instance.
+ */
+ DiscardSummary(DiscardSummary&& src);
+#if 15 < LOG4CXX_ABI_VERSION
+ /** Copy constructor. */
+ DiscardSummary(const DiscardSummary&) = delete;
+ /** Assignment operator. */
+ DiscardSummary& operator=(const DiscardSummary&) = delete;
+#else
/**
* Create new instance.
*
@@ -69,6 +90,7 @@ class DiscardSummary
DiscardSummary(const DiscardSummary& src);
/** Assignment operator. */
DiscardSummary& operator=(const DiscardSummary& src);
+#endif
/**
* Add discarded event to summary.
@@ -297,8 +319,17 @@ void AsyncAppender::append(const spi::LoggingEventPtr&
event, Pool& p)
if (!priv->dispatcher.joinable())
priv->dispatcher =
ThreadUtility::instance()->createThread( LOG4CXX_STR("AsyncAppender"),
&AsyncAppender::dispatch, this );
}
- bool isDispatchThread = (priv->dispatcher.get_id() ==
std::this_thread::get_id());
- while (true)
+ if (priv->dispatcher.get_id() == std::this_thread::get_id()) // From an
appender attached to this?
+ {
+ std::unique_lock<std::mutex> lock(priv->bufferMutex);
+ auto loggerName = event->getLoggerName();
+ auto iter = priv->discardMap.find(loggerName);
+ if (priv->discardMap.end() == iter)
+ priv->discardMap.emplace(loggerName, DiscardSummary{
event, LOG4CXX_STR("from an attached appender") });
+ else
+ iter->second.add(event);
+ }
+ else while (true)
{
auto pendingCount = priv->eventCount - priv->dispatchedCount;
if (0 <= pendingCount && pendingCount < priv->bufferSize)
@@ -307,7 +338,7 @@ void AsyncAppender::append(const spi::LoggingEventPtr&
event, Pool& p)
auto oldEventCount = priv->eventCount++;
auto index = oldEventCount % priv->buffer.size();
// Wait for a free slot
- while (priv->bufferSize <= oldEventCount -
priv->dispatchedCount && !isDispatchThread)
+ while (priv->bufferSize <= oldEventCount -
priv->dispatchedCount)
std::this_thread::yield(); // Allow the
dispatch thread to free a slot
// Write to the ring buffer
priv->buffer[index] =
AsyncAppenderPriv::EventData{event, pendingCount};
@@ -335,8 +366,7 @@ void AsyncAppender::append(const spi::LoggingEventPtr&
event, Pool& p)
bool discard = true;
if (priv->blocking
- && !priv->closed
- && !isDispatchThread)
+ && !priv->closed)
{
++priv->blockedCount;
priv->bufferNotFull.wait(lock, [this]()
@@ -358,12 +388,11 @@ void AsyncAppender::append(const spi::LoggingEventPtr&
event, Pool& p)
if (iter == priv->discardMap.end())
{
- DiscardSummary summary(event);
-
priv->discardMap.insert(DiscardMap::value_type(loggerName, summary));
+ priv->discardMap.emplace(loggerName,
DiscardSummary{ event, LOG4CXX_STR("due to a full event buffer") });
}
else
{
- (*iter).second.add(event);
+ iter->second.add(event);
}
break;
@@ -466,6 +495,21 @@ bool AsyncAppender::getBlocking() const
return priv->blocking;
}
+DiscardSummary::DiscardSummary(const LoggingEventPtr& event, const LogString&
reasonArg)
+ : maxEvent(event)
+ , count(1)
+ , reason(reasonArg)
+{
+}
+
+DiscardSummary::DiscardSummary(DiscardSummary&& other)
+ : maxEvent(std::move(other.maxEvent))
+ , count(other.count)
+ , reason(std::move(other.reason))
+{
+}
+
+#if LOG4CXX_ABI_VERSION <= 15
DiscardSummary::DiscardSummary(const LoggingEventPtr& event) :
maxEvent(event), count(1)
{
@@ -482,28 +526,27 @@ DiscardSummary& DiscardSummary::operator=(const
DiscardSummary& src)
count = src.count;
return *this;
}
+#endif
void DiscardSummary::add(const LoggingEventPtr& event)
{
- if (event->getLevel()->toInt() > maxEvent->getLevel()->toInt())
- {
- maxEvent = event;
- }
-
- count++;
+ if (this->maxEvent->getLevel()->toInt() < event->getLevel()->toInt())
+ this->maxEvent = event;
+ ++this->count;
}
LoggingEventPtr DiscardSummary::createEvent(Pool& p)
- {
+{
LogString msg(LOG4CXX_STR("Discarded "));
- StringHelper::toString(count, p, msg);
- msg.append(LOG4CXX_STR(" messages due to a full event buffer including:
"));
- msg.append(maxEvent->getRenderedMessage());
- return std::make_shared<LoggingEvent>(
- maxEvent->getLoggerName(),
- maxEvent->getLevel(),
- msg,
- LocationInfo::getLocationUnavailable() );
+ StringHelper::toString(this->count, p, msg);
+ msg.append(LOG4CXX_STR(" messages ") + this->reason + LOG4CXX_STR("
including: "));
+ msg.append(this->maxEvent->getRenderedMessage());
+ return std::make_shared<LoggingEvent>
+ ( this->maxEvent->getLoggerName()
+ , this->maxEvent->getLevel()
+ , msg
+ , LocationInfo::getLocationUnavailable()
+ );
}
#if LOG4CXX_ABI_VERSION <= 15
@@ -563,7 +606,7 @@ void AsyncAppender::dispatch()
{
std::lock_guard<std::mutex> lock(priv->bufferMutex);
blockedCount += priv->blockedCount;
- for (auto discardItem : priv->discardMap)
+ for (auto& discardItem : priv->discardMap)
{
events.push_back(discardItem.second.createEvent(p));
discardCount += discardItem.second.getCount();
diff --git a/src/test/cpp/asyncappendertestcase.cpp
b/src/test/cpp/asyncappendertestcase.cpp
index f4e5d909..1faa7c81 100644
--- a/src/test/cpp/asyncappendertestcase.cpp
+++ b/src/test/cpp/asyncappendertestcase.cpp
@@ -429,8 +429,10 @@ class AsyncAppenderTestCase : public
AppenderSkeletonTestCase
LoggingEventPtr discardEvent;
for (auto& e : events)
{
+ auto message = e->getRenderedMessage();
+ LogLog::debug(message);
++levelCount[e->getLevel()];
- if (e->getRenderedMessage().substr(0, 10) ==
LOG4CXX_STR("Discarded "))
+ if (message.substr(0, 10) ==
LOG4CXX_STR("Discarded "))
{
++discardMessageCount;
discardEvent = e;
@@ -529,8 +531,7 @@ class AsyncAppenderTestCase : public
AppenderSkeletonTestCase
LogLog::debug(msg);
}
LOGUNIT_ASSERT(12 < events.size());
- // A race condition in AsyncAppender can result in a
lost message when the dispatch thread is logging events
- LOGUNIT_ASSERT(10 <= eventCount[0]);
+ LOGUNIT_ASSERT_EQUAL(12, eventCount[0]);
}
#if LOG4CXX_HAS_DOMCONFIGURATOR