Allow binary-to-text conversion to be moved to a background thread (#548)
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 465a51d..8a2526f 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -78,6 +78,7 @@
appenderskeleton.cpp
aprinitializer.cpp
asyncappender.cpp
+ asyncbuffer.cpp
basicconfigurator.cpp
bufferedwriter.cpp
bytearrayinputstream.cpp
diff --git a/src/main/cpp/asyncappender.cpp b/src/main/cpp/asyncappender.cpp
index 2427cb6..d199e39 100644
--- a/src/main/cpp/asyncappender.cpp
+++ b/src/main/cpp/asyncappender.cpp
@@ -498,7 +498,7 @@
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->getMessage());
+ msg.append(maxEvent->getRenderedMessage());
return std::make_shared<LoggingEvent>(
maxEvent->getLoggerName(),
maxEvent->getLevel(),
diff --git a/src/main/cpp/asyncbuffer.cpp b/src/main/cpp/asyncbuffer.cpp
new file mode 100644
index 0000000..b7e5daf
--- /dev/null
+++ b/src/main/cpp/asyncbuffer.cpp
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log4cxx/helpers/asyncbuffer.h>
+
+namespace LOG4CXX_NS
+{
+
+namespace helpers
+{
+
+struct AsyncBuffer::Private
+{
+ std::vector<MessageBufferAppender> data;
+};
+
+/** An empty buffer.
+*/
+AsyncBuffer::AsyncBuffer()
+{}
+
+/** A new buffer with the content of \c other
+*/
+AsyncBuffer::AsyncBuffer(AsyncBuffer&& other)
+ : m_priv(std::move(other.m_priv))
+{
+}
+
+/** Release resources.
+*/
+AsyncBuffer::~AsyncBuffer()
+{
+}
+
+/**
+* Has no item been added to this?
+*/
+bool AsyncBuffer::empty() const { return !m_priv || m_priv->data.empty(); }
+
+/**
+* Add text version of buffered values to \c msg
+*/
+void AsyncBuffer::renderMessage(LogCharMessageBuffer& msg)
+{
+ if (m_priv)
+ for (auto& renderer : m_priv->data)
+ renderer(msg);
+}
+
+/**
+* Remove all message appenders
+*/
+void AsyncBuffer::clear()
+{
+ if (m_priv)
+ m_priv->data.clear();
+}
+
+/**
+ * Append \c function to this buffer.
+ */
+void AsyncBuffer::append(const MessageBufferAppender& f)
+{
+ if (!m_priv)
+ m_priv = std::make_unique<Private>();
+ m_priv->data.push_back(f);
+}
+
+} // namespace helpers
+} // namespace LOG4CXX_NS
+
diff --git a/src/main/cpp/fmtlayout.cpp b/src/main/cpp/fmtlayout.cpp
index faa0d0c..e6c5bf7 100644
--- a/src/main/cpp/fmtlayout.cpp
+++ b/src/main/cpp/fmtlayout.cpp
@@ -89,7 +89,8 @@
const spi::LoggingEventPtr& event,
LOG4CXX_NS::helpers::Pool&) const
{
- output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
+ auto& lsMsg = event->getRenderedMessage();
+ output.reserve(m_priv->expectedPatternLength + lsMsg.size());
auto locationFull = fmt::format("{}({})",
event->getLocationInformation().getFileName(),
event->getLocationInformation().getLineNumber());
@@ -100,7 +101,7 @@
LOG4CXX_ENCODE_CHAR(sPattern, m_priv->conversionPattern);
LOG4CXX_ENCODE_CHAR(sLogger, event->getLoggerName());
LOG4CXX_ENCODE_CHAR(sLevel, event->getLevel()->toString());
- LOG4CXX_ENCODE_CHAR(sMsg, event->getMessage());
+ LOG4CXX_ENCODE_CHAR(sMsg, lsMsg);
LOG4CXX_ENCODE_CHAR(sThread, event->getThreadName());
LOG4CXX_ENCODE_CHAR(endOfLine, LOG4CXX_EOL);
#else
@@ -108,7 +109,7 @@
auto& sPattern = m_priv->conversionPattern;
auto& sLogger = event->getLoggerName();
auto sLevel = event->getLevel()->toString();
- auto& sMsg = event->getMessage();
+ auto& sMsg = lsMsg;
auto& sThread = event->getThreadName();
auto endOfLine = LOG4CXX_EOL;
#endif
diff --git a/src/main/cpp/htmllayout.cpp b/src/main/cpp/htmllayout.cpp
index f1b2747..bcfce2f 100644
--- a/src/main/cpp/htmllayout.cpp
+++ b/src/main/cpp/htmllayout.cpp
@@ -84,7 +84,8 @@
const spi::LoggingEventPtr& event,
Pool& p) const
{
- output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
+ auto& lsMsg = event->getRenderedMessage();
+ output.reserve(m_priv->expectedPatternLength + lsMsg.size());
output.append(LOG4CXX_EOL);
output.append(LOG4CXX_STR("<tr>"));
output.append(LOG4CXX_EOL);
@@ -152,7 +153,7 @@
}
output.append(LOG4CXX_STR("<td title=\"Message\">"));
- Transform::appendEscapingTags(output, event->getRenderedMessage());
+ Transform::appendEscapingTags(output, lsMsg);
output.append(LOG4CXX_STR("</td>"));
output.append(LOG4CXX_EOL);
output.append(LOG4CXX_STR("</tr>"));
diff --git a/src/main/cpp/jsonlayout.cpp b/src/main/cpp/jsonlayout.cpp
index 9b286af..5471235 100644
--- a/src/main/cpp/jsonlayout.cpp
+++ b/src/main/cpp/jsonlayout.cpp
@@ -132,7 +132,8 @@
const spi::LoggingEventPtr& event,
Pool& p) const
{
- output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
+ auto& lsMsg = event->getRenderedMessage();
+ output.reserve(m_priv->expectedPatternLength + lsMsg.size());
output.append(LOG4CXX_STR("{"));
output.append(m_priv->prettyPrint ? LOG4CXX_EOL : LOG4CXX_STR(" "));
@@ -187,7 +188,7 @@
}
output.append(LOG4CXX_STR("\"message\": "));
- appendQuotedEscapedString(output, event->getMessage());
+ appendQuotedEscapedString(output, lsMsg);
appendSerializedMDC(output, event);
appendSerializedNDC(output, event);
diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp
index e814620..9574a14 100644
--- a/src/main/cpp/logger.cpp
+++ b/src/main/cpp/logger.cpp
@@ -173,6 +173,15 @@
}
}
+void Logger::addEvent(const LevelPtr& level, helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ if (!getHierarchy()) // Has removeHierarchy() been called?
+ return;
+ auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(messageAppender));
+ Pool p;
+ callAppenders(event, p);
+}
+
void Logger::addEvent(const LevelPtr& level, std::string&& message, const LocationInfo& location) const
{
if (!getHierarchy()) // Has removeHierarchy() been called?
@@ -192,31 +201,61 @@
addEvent(m_priv->levelData->Fatal, std::move(message), location);
}
+void Logger::addFatalEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Fatal, std::move(messageAppender), location);
+}
+
void Logger::addErrorEvent(std::string&& message, const LocationInfo& location) const
{
addEvent(m_priv->levelData->Error, std::move(message), location);
}
+void Logger::addErrorEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Error, std::move(messageAppender), location);
+}
+
void Logger::addWarnEvent(std::string&& message, const LocationInfo& location) const
{
addEvent(m_priv->levelData->Warn, std::move(message), location);
}
+void Logger::addWarnEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Warn, std::move(messageAppender), location);
+}
+
void Logger::addInfoEvent(std::string&& message, const LocationInfo& location) const
{
addEvent(m_priv->levelData->Info, std::move(message), location);
}
+void Logger::addInfoEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Info, std::move(messageAppender), location);
+}
+
void Logger::addDebugEvent(std::string&& message, const LocationInfo& location) const
{
addEvent(m_priv->levelData->Debug, std::move(message), location);
}
+void Logger::addDebugEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Debug, std::move(messageAppender), location);
+}
+
void Logger::addTraceEvent(std::string&& message, const LocationInfo& location) const
{
addEvent(m_priv->levelData->Trace, std::move(message), location);
}
+void Logger::addTraceEvent(helpers::AsyncBuffer&& messageAppender, const LocationInfo& location) const
+{
+ addEvent(m_priv->levelData->Trace, std::move(messageAppender), location);
+}
+
void Logger::forcedLog(const LevelPtr& level, const std::string& message,
const LocationInfo& location) const
{
diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp
index e1fc11f..ceae144 100644
--- a/src/main/cpp/loggingevent.cpp
+++ b/src/main/cpp/loggingevent.cpp
@@ -29,6 +29,7 @@
#include <log4cxx/helpers/aprinitializer.h>
#include <log4cxx/helpers/threadspecificdata.h>
#include <log4cxx/helpers/bytebuffer.h>
+#include <log4cxx/helpers/messagebuffer.h>
#include <log4cxx/helpers/date.h>
#include <log4cxx/helpers/optional.h>
@@ -61,6 +62,23 @@
{
}
+ LoggingEventPrivate
+ ( const LogString& logger1
+ , const LevelPtr& level1
+ , const LocationInfo& locationInfo1
+ , helpers::AsyncBuffer&& messageAppenderArg
+ , const ThreadSpecificData::NamePairPtr p = ThreadSpecificData::getNames()
+ )
+ : logger(logger1)
+ , level(level1)
+ , timeStamp(Date::currentTime())
+ , locationInfo(locationInfo1)
+ , chronoTimeStamp(std::chrono::microseconds(timeStamp))
+ , pNames(p)
+ , messageAppender(std::move(messageAppenderArg))
+ {
+ }
+
LoggingEventPrivate(
const LogString& logger1, const LevelPtr& level1,
const LogString& message1, const LocationInfo& locationInfo1,
@@ -124,6 +142,21 @@
* of this LoggingEvent exceeds the duration of the logging request.
*/
mutable std::unique_ptr<DiagnosticContext> dc;
+
+ /** Application supplied message builders.
+ */
+ helpers::AsyncBuffer messageAppender;
+
+ void renderMessage()
+ {
+ if (!this->messageAppender.empty())
+ {
+ helpers::LogCharMessageBuffer buf;
+ this->messageAppender.renderMessage(buf);
+ this->message = buf.extract_str(buf);
+ this->messageAppender.clear();
+ }
+ }
};
IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)
@@ -152,6 +185,16 @@
{
}
+LoggingEvent::LoggingEvent
+ ( const LogString& logger
+ , const LevelPtr& level
+ , const LocationInfo& location
+ , helpers::AsyncBuffer&& messageAppender
+ )
+ : m_priv(std::make_unique<LoggingEventPrivate>(logger, level, location, std::move(messageAppender)))
+{
+}
+
LoggingEvent::LoggingEvent(
const LogString& logger1, const LevelPtr& level1,
const LogString& message1, const LocationInfo& locationInfo1) :
@@ -273,6 +316,11 @@
return set;
}
+void LoggingEvent::renderMessage()
+{
+ m_priv->renderMessage();
+}
+
void LoggingEvent::setProperty(const LogString& key, const LogString& value)
{
if (m_priv->properties == 0)
@@ -300,6 +348,7 @@
const LogString& LoggingEvent::getRenderedMessage() const
{
+ m_priv->renderMessage();
return m_priv->message;
}
diff --git a/src/main/cpp/messagebuffer.cpp b/src/main/cpp/messagebuffer.cpp
index 6c7f1a4..df908bf 100644
--- a/src/main/cpp/messagebuffer.cpp
+++ b/src/main/cpp/messagebuffer.cpp
@@ -161,7 +161,7 @@
std::basic_string<char> CharMessageBuffer::extract_str(CharMessageBuffer&)
{
- return std::move(m_priv->buf);
+ return std::move(m_priv->BufFromStream());
}
const std::basic_string<char>& CharMessageBuffer::str(std::basic_ostream<char>&)
@@ -171,7 +171,7 @@
const std::basic_string<char>& CharMessageBuffer::str(CharMessageBuffer&)
{
- return m_priv->buf;
+ return m_priv->BufFromStream();
}
bool CharMessageBuffer::hasStream() const
@@ -306,7 +306,7 @@
std::basic_string<wchar_t> WideMessageBuffer::extract_str(WideMessageBuffer&)
{
- return std::move(m_priv->buf);
+ return std::move(m_priv->BufFromStream());
}
const std::basic_string<wchar_t>& WideMessageBuffer::str(std::basic_ostream<wchar_t>&)
@@ -316,7 +316,7 @@
const std::basic_string<wchar_t>& WideMessageBuffer::str(WideMessageBuffer&)
{
- return m_priv->buf;
+ return m_priv->BufFromStream();
}
bool WideMessageBuffer::hasStream() const
@@ -672,7 +672,7 @@
std::basic_string<LOG4CXX_NS::UniChar> UniCharMessageBuffer::extract_str(UniCharMessageBuffer&)
{
- return std::move(m_priv->buf);
+ return std::move(m_priv->BufFromStream());
}
const std::basic_string<LOG4CXX_NS::UniChar>& UniCharMessageBuffer::str(UniCharMessageBuffer::uostream&)
@@ -682,7 +682,7 @@
const std::basic_string<LOG4CXX_NS::UniChar>& UniCharMessageBuffer::str(UniCharMessageBuffer&)
{
- return m_priv->buf;
+ return m_priv->BufFromStream();
}
bool UniCharMessageBuffer::hasStream() const
diff --git a/src/main/cpp/patternlayout.cpp b/src/main/cpp/patternlayout.cpp
index 371e47d..68d43c5 100644
--- a/src/main/cpp/patternlayout.cpp
+++ b/src/main/cpp/patternlayout.cpp
@@ -122,7 +122,8 @@
const spi::LoggingEventPtr& event,
Pool& pool) const
{
- output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
+ auto& lsMsg = event->getRenderedMessage();
+ output.reserve(m_priv->expectedPatternLength + lsMsg.size());
std::vector<FormattingInfoPtr>::const_iterator formatterIter =
m_priv->patternFields.begin();
diff --git a/src/main/cpp/telnetappender.cpp b/src/main/cpp/telnetappender.cpp
index fcacc40..cc3b143 100644
--- a/src/main/cpp/telnetappender.cpp
+++ b/src/main/cpp/telnetappender.cpp
@@ -230,7 +230,7 @@
if (_priv->layout)
_priv->layout->format(msg, event, p);
else
- msg = event->getMessage();
+ msg = event->getRenderedMessage();
msg.append(LOG4CXX_STR("\r\n"));
size_t bytesSize = msg.size() * 2;
char* bytes = p.pstralloc(bytesSize);
diff --git a/src/main/cpp/xmllayout.cpp b/src/main/cpp/xmllayout.cpp
index 0b7fe07..e26be6c 100644
--- a/src/main/cpp/xmllayout.cpp
+++ b/src/main/cpp/xmllayout.cpp
@@ -78,7 +78,8 @@
const spi::LoggingEventPtr& event,
Pool& p) const
{
- output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
+ auto& lsMsg = event->getRenderedMessage();
+ output.reserve(m_priv->expectedPatternLength + lsMsg.size());
output.append(LOG4CXX_STR("<log4j:event logger=\""));
Transform::appendEscapingTags(output, event->getLoggerName());
output.append(LOG4CXX_STR("\" timestamp=\""));
@@ -93,7 +94,7 @@
output.append(LOG4CXX_STR("<log4j:message><![CDATA["));
// Append the rendered message. Also make sure to escape any
// existing CDATA sections.
- Transform::appendEscapingCDATA(output, event->getRenderedMessage());
+ Transform::appendEscapingCDATA(output, lsMsg);
output.append(LOG4CXX_STR("]]></log4j:message>"));
output.append(LOG4CXX_EOL);
diff --git a/src/main/include/log4cxx/helpers/asyncbuffer.h b/src/main/include/log4cxx/helpers/asyncbuffer.h
new file mode 100644
index 0000000..ebc01a0
--- /dev/null
+++ b/src/main/include/log4cxx/helpers/asyncbuffer.h
@@ -0,0 +1,274 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG4CXX_ASYNC_BUFFER_H
+#define LOG4CXX_ASYNC_BUFFER_H
+
+#include <log4cxx/helpers/messagebuffer.h>
+#include <functional>
+#include <vector>
+
+namespace LOG4CXX_NS
+{
+
+namespace helpers
+{
+
+/**
+ * This class is used by the LOG4CXX_INFO_ASYNC and similar
+ * macros to support insertion operators.
+ * The class is not intended for use outside of that context.
+ */
+class LOG4CXX_EXPORT AsyncBuffer
+{
+public:
+ /** An empty buffer.
+ */
+ AsyncBuffer();
+
+ /** A new buffer with the content of \c other
+ */
+ AsyncBuffer(AsyncBuffer&& other);
+
+ /** Release resources.
+ */
+ ~AsyncBuffer();
+
+ /** Append a function to this buffer that will convert \c value to text.
+ * @param value type must be copy-constructable
+ * @return this buffer.
+ */
+ template<typename T>
+ AsyncBuffer& operator<<(const T& value)
+ {
+ append([value](LogCharMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ return *this;
+ }
+
+#ifdef __cpp_init_captures // C++ >= 14
+ /** Append a function to this buffer that will convert \c value to text.
+ * @param value type must be move-constructable
+ * @return this buffer.
+ */
+ template<typename T>
+ AsyncBuffer& operator<<(const T&& rvalue)
+ {
+ append([value = std::move(rvalue)](LogCharMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ return *this;
+ }
+#endif
+ /**
+ * Has no item been added to this?
+ */
+ bool empty() const;
+
+ /**
+ * Add text version of buffered values to \c msg
+ */
+ void renderMessage(LogCharMessageBuffer& msg);
+
+ /**
+ * Remove all message appenders
+ */
+ void clear();
+
+private:
+ AsyncBuffer(const AsyncBuffer&) = delete;
+ AsyncBuffer& operator=(const AsyncBuffer&) = delete;
+
+ LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(Private, m_priv)
+ using MessageBufferAppender = std::function<void(LogCharMessageBuffer&)>;
+
+ /**
+ * Append \c function to this buffer.
+ */
+ void append(const MessageBufferAppender& f);
+};
+
+} // namespace helpers
+} // namespace LOG4CXX_NS
+
+/** @addtogroup LoggingMacros Logging macros
+@{
+*/
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 10000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>DEBUG</code> events.
+
+\usage
+~~~{.cpp}
+LOG4CXX_DEBUG_ASYNC(m_log, "AddMesh:"
+ << " name " << meshName
+ << " type 0x" << std:: hex << traits.Type
+ << " materialName " << meshObject.GetMaterialName()
+ << " visible? " << traits.IsDefaultVisible
+ << " at " << obj->getBoundingBox().getCenter()
+ << " +/- " << obj->getBoundingBox().getHalfSize()
+ );
+~~~
+
+@param logger the logger that has the enabled status.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+
+*/
+#define LOG4CXX_DEBUG_ASYNC(logger, message) do { \
+ if (LOG4CXX_UNLIKELY(::LOG4CXX_NS::Logger::isDebugEnabledFor(logger))) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ logger->addDebugEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+#else
+#define LOG4CXX_DEBUG_ASYNC(logger, message)
+#endif
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 5000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>TRACE</code> events.
+
+\usage
+~~~{.cpp}
+ LOG4CXX_TRACE_ASYNC(m_log, "AddVertex:" << " at " << p << " n " << n << ' ' << color);
+~~~
+
+@param logger the logger that has the enabled status.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_TRACE_ASYNC(logger, message) do { \
+ if (LOG4CXX_UNLIKELY(::LOG4CXX_NS::Logger::isTraceEnabledFor(logger))) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ logger->addTraceEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+#else
+#define LOG4CXX_TRACE_ASYNC(logger, message)
+#endif
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 20000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>INFO</code> events.
+
+\usage
+~~~{.cpp}
+LOG4CXX_INFO_ASYNC(m_log, surface->GetName()
+ << " successfully planned " << std::fixed << std::setprecision(1) << ((plannedArea / (plannedArea + unplannedArea)) * 100.0) << "%"
+ << " planned area " << std::fixed << std::setprecision(4) << plannedArea << "m^2"
+ << " unplanned area " << unplannedArea << "m^2"
+ << " planned segments " << surface->GetSegmentPlanCount() << " of " << surface->GetSegmentCount()
+ );
+~~~
+
+@param logger the logger that has the enabled status.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_INFO_ASYNC(logger, message) do { \
+ if (::LOG4CXX_NS::Logger::isInfoEnabledFor(logger)) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf;\
+ logger->addInfoEvent(std::move(buf << message), LOG4CXX_LOCATION);\
+ }} while (0)
+
+#endif
+
+#else
+#define LOG4CXX_INFO_ASYNC(logger, message)
+#endif
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 30000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>WARN</code> events.
+
+\usage
+~~~{.cpp}
+catch (const std::exception& ex)
+{
+ LOG4CXX_WARN_ASYNC(m_log, ex.what() << ": in " << m_task->GetParamFilePath());
+}
+~~~
+
+@param logger the logger to be used.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_WARN_ASYNC(logger, message) do { \
+ if (::LOG4CXX_NS::Logger::isWarnEnabledFor(logger)) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ logger->addWarnEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+#else
+#define LOG4CXX_WARN_ASYNC(logger, message)
+#endif
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 40000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>ERROR</code> events.
+
+\usage
+~~~{.cpp}
+catch (std::exception& ex)
+{
+ LOG4CXX_ERROR_ASYNC(m_log, ex.what() << " in AddScanData");
+}
+~~~
+
+@param logger the logger to be used.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_ERROR_ASYNC(logger, message) do { \
+ if (::LOG4CXX_NS::Logger::isErrorEnabledFor(logger)) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ logger->addErrorEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+
+/**
+If \c condition is not true, add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>ERROR</code> events.
+
+@param logger the logger to be used.
+@param condition condition
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_ASSERT_ASYNC(logger, condition, message) do { \
+ if (!(condition) && ::LOG4CXX_NS::Logger::isErrorEnabledFor(logger)) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ LOG4CXX_STACKTRACE \
+ logger->addErrorEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+
+#else
+#define LOG4CXX_ERROR_ASYNC(logger, message)
+#define LOG4CXX_ASSERT_ASYNC(logger, condition, message)
+#endif
+
+#if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 50000
+/**
+Add a new logging event containing \c message to attached appender(s) if \c logger is enabled for <code>FATAL</code> events.
+
+\usage
+~~~{.cpp}
+LOG4CXX_FATAL_ASYNC(m_log, m_renderSystem->getName() << " is not supported");
+~~~
+
+@param logger the logger to be used.
+@param message a valid r-value expression of an <code>operator<<(std::ostream&. ...)</code> overload.
+*/
+#define LOG4CXX_FATAL_ASYNC(logger, message) do { \
+ if (::LOG4CXX_NS::Logger::isFatalEnabledFor(logger)) {\
+ ::LOG4CXX_NS::helpers::AsyncBuffer buf; \
+ logger->addFatalEvent(std::move(buf << message), LOG4CXX_LOCATION); }} while (0)
+
+#else
+#define LOG4CXX_FATAL_ASYNC(logger, message)
+#endif
+
+/**@} Logging macro group */
diff --git a/src/main/include/log4cxx/logger.h b/src/main/include/log4cxx/logger.h
index 9118150..1241d0c 100644
--- a/src/main/include/log4cxx/logger.h
+++ b/src/main/include/log4cxx/logger.h
@@ -23,6 +23,7 @@
#include <log4cxx/helpers/pool.h>
#include <log4cxx/spi/location/locationinfo.h>
#include <log4cxx/helpers/resourcebundle.h>
+#include <log4cxx/helpers/asyncbuffer.h>
#include <log4cxx/helpers/messagebuffer.h>
namespace LOG4CXX_NS
@@ -507,6 +508,16 @@
, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new \c level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param level The logging event level.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addEvent(const LevelPtr& level, helpers::AsyncBuffer&& messageAppender
+ , const spi::LocationInfo& sourceLocation = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new fatal level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -515,6 +526,14 @@
void addFatalEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new FATAL level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addFatalEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new error level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -523,6 +542,14 @@
void addErrorEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new ERROR level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addErrorEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new warning level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -531,6 +558,14 @@
void addWarnEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new WARN level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addWarnEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new info level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -539,6 +574,14 @@
void addInfoEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new INFO level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addInfoEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new debug level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -547,6 +590,14 @@
void addDebugEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new DEBUG level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addDebugEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new trace level logging event containing \c message and \c location to attached appender(s)
without further checks.
@param message The text to add to the logging event.
@@ -555,6 +606,14 @@
void addTraceEvent(std::string&& message, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
/**
+ Add to attached appender(s) a new TRACE level LoggingEvent which was requested at \c sourceLocation where the message is built asynchronously by \c messageAppender
+ without further checks.
+ @param message The text to add to the logging event.
+ @param location The source code location of the logging request.
+ */
+ void addTraceEvent(helpers::AsyncBuffer&& messageAppender, const spi::LocationInfo& location = spi::LocationInfo::getLocationUnavailable()) const;
+
+ /**
Add a new logging event containing \c message and \c location to attached appender(s)
without further checks.
@param level The logging event level.
diff --git a/src/main/include/log4cxx/spi/loggingevent.h b/src/main/include/log4cxx/spi/loggingevent.h
index cd0b81c..e40c8a5 100644
--- a/src/main/include/log4cxx/spi/loggingevent.h
+++ b/src/main/include/log4cxx/spi/loggingevent.h
@@ -87,6 +87,21 @@
, const LocationInfo& location
);
+ /**
+ An event composed using the supplied parameters.
+
+ @param logger The logger used to make the logging request.
+ @param level The severity of this event.
+ @param location The source code location of the logging request.
+ @param messageAppender Builds the message text to add to this event.
+ */
+ LoggingEvent
+ ( const LogString& logger
+ , const LevelPtr& level
+ , const LocationInfo& location
+ , helpers::AsyncBuffer&& messageAppender
+ );
+
~LoggingEvent();
/** The severity level of the logging request that generated this event. */
@@ -195,6 +210,11 @@
*/
void setProperty(const LogString& key, const LogString& value);
+ /**
+ * Use the renderers to construct the message
+ */
+ void renderMessage();
+
private:
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(LoggingEventPrivate, m_priv)
diff --git a/src/site/markdown/change-report-gh.md b/src/site/markdown/change-report-gh.md
index 9d9d93c..4b8b535 100644
--- a/src/site/markdown/change-report-gh.md
+++ b/src/site/markdown/change-report-gh.md
@@ -61,6 +61,8 @@
\[[#520](https://github.com/apache/logging-log4cxx/pull/520)\]
* Console output (Log4cxx internal logging and BasicConfigurator) use a color per message level by default
\[[#529](https://github.com/apache/logging-log4cxx/pull/529)\]
+* New logging macros that defer binary-to-text conversion until used in AsyncAppender's background thread
+ \[[#548](https://github.com/apache/logging-log4cxx/pull/548)\]
The following issues have been addressed:
diff --git a/src/site/markdown/performance.md b/src/site/markdown/performance.md
index 5672350..608e5cc 100644
--- a/src/site/markdown/performance.md
+++ b/src/site/markdown/performance.md
@@ -98,8 +98,10 @@
| Appending int+float using FMT, pattern: \%m\%n/threads:6 | 537 ns | 3036 ns | 212844 |
| Appending int+10float using FMT, pattern: \%m\%n | 1671 ns | 1671 ns | 417402 |
| Appending int+10float using FMT, pattern: \%m\%n/threads:6 | 1275 ns | 7297 ns | 96222 |
-| Async, Sending int+10float using FMT | 1663 ns | 1663 ns | 421796 |
-| Async, Sending int+10float using FMT/threads:6 | 1286 ns | 7368 ns | 88308 |
+| Async, Sending int+10float using FMT | 2190 ns | 2190 ns | 320109 |
+| Async, Sending int+10float using FMT/threads:6 | 1363 ns | 7862 ns | 84306 |
+| Async, Sending int+10float using AsyncBuffer, pattern: \%m\%n | 1226 ns | 1226 ns | 571351 |
+| Async, Sending int+10float using AsyncBuffer, pattern: \%m\%n/threads:6 | 1398 ns | 7902 ns | 89688 |
| Logging int+float using MessageBuffer, pattern: \%d \%m\%n | 1073 ns | 1073 ns | 656652 |
| Logging int+float using MessageBuffer, pattern: \%d \%m\%n/threads:6 | 1083 ns | 4895 ns | 142776 |
| Logging int+float using MessageBuffer, JSON | 1394 ns | 1394 ns | 507493 |
@@ -137,5 +139,6 @@
from the calling thread to the background thread.
When logging floating point values from a high priority thread,
+and you cannot use a background thread to format and write the log data,
the LOG4CXX_[level]_FMT series of macros impose the least overhead.
diff --git a/src/test/cpp/asyncappendertestcase.cpp b/src/test/cpp/asyncappendertestcase.cpp
index 28b2c9e..42a2eaa 100644
--- a/src/test/cpp/asyncappendertestcase.cpp
+++ b/src/test/cpp/asyncappendertestcase.cpp
@@ -104,13 +104,14 @@
LoggerInstancePtr logger{ "LoggingVectorAppender" };
void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) override
{
+ auto lsMsg = event->getRenderedMessage();
VectorAppender::append(event, p);
- if (event->getMessage() == LOG4CXX_STR("Hello, World"))
+ if (LogString::npos != lsMsg.find(LOG4CXX_STR("World")))
{
- LOG4CXX_LOGLS(logger, Level::getError(), LOG4CXX_STR("Some example error"));
- LOG4CXX_LOGLS(logger, Level::getWarn(), LOG4CXX_STR("Some example warning"));
- LOG4CXX_LOGLS(logger, Level::getInfo(), LOG4CXX_STR("Some information"));
- LOG4CXX_LOGLS(logger, Level::getDebug(), LOG4CXX_STR("Some detailed data"));
+ LOG4CXX_LOGLS(logger, Level::getError(), LOG4CXX_STR("Some appender error"));
+ LOG4CXX_LOGLS(logger, Level::getWarn(), LOG4CXX_STR("Some appender warning"));
+ LOG4CXX_LOGLS(logger, Level::getInfo(), LOG4CXX_STR("Some appender information"));
+ LOG4CXX_LOGLS(logger, Level::getDebug(), LOG4CXX_STR("Some appender detailed data"));
}
}
};
@@ -129,6 +130,7 @@
LOGUNIT_TEST(closeTest);
LOGUNIT_TEST(test2);
+ LOGUNIT_TEST(testAutoMessageBufferSelection);
LOGUNIT_TEST(testEventFlush);
LOGUNIT_TEST(testMultiThread);
LOGUNIT_TEST(testBadAppender);
@@ -205,6 +207,37 @@
LOGUNIT_ASSERT(vectorAppender->isClosed());
}
+ // Test behaviour when logging with a char type that is not logchar
+ void testAutoMessageBufferSelection()
+ {
+ VectorAppenderPtr vectorAppender;
+ auto r = LogManager::getLoggerRepository();
+ r->ensureIsConfigured([r, &vectorAppender]()
+ {
+ vectorAppender = std::make_shared<VectorAppender>();
+ r->getRootLogger()->addAppender(vectorAppender);
+ });
+ auto root = r->getRootLogger();
+
+ int expectedMessageCount = 1;
+#ifdef LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
+ ++expectedMessageCount
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ LOG4CXX_INFO_ASYNC(root, L"Some wide string " << 42);
+#else
+ LOG4CXX_INFO_ASYNC(root, "Some narrow string " << 42);
+#endif
+#endif // LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
+
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ LOG4CXX_INFO(root, L"Some wide string " << 42);
+#else
+ LOG4CXX_INFO(root, "Some narrow string " << 42);
+#endif
+ auto& v = vectorAppender->getVector();
+ LOGUNIT_ASSERT_EQUAL(expectedMessageCount, int(v.size()));
+ }
+
// this test checks all messages are delivered when an AsyncAppender is closed
void testEventFlush()
{
@@ -219,7 +252,7 @@
for (size_t i = 0; i < LEN; i++)
{
- LOG4CXX_DEBUG(root, "message" << i);
+ LOG4CXX_DEBUG_ASYNC(root, "message" << i);
}
asyncAppender->close();
@@ -232,7 +265,7 @@
{
LogString m(LOG4CXX_STR("message"));
StringHelper::toString(i, p, m);
- LOGUNIT_ASSERT(v[i]->getMessage() == m);
+ LOGUNIT_ASSERT(v[i]->getRenderedMessage() == m);
}
LOGUNIT_ASSERT_EQUAL(true, vectorAppender->isClosed());
}
@@ -257,7 +290,7 @@
{
for (int i = 0; i < LEN; i++)
{
- LOG4CXX_DEBUG(root, "message" << i);
+ LOG4CXX_DEBUG_ASYNC(root, "message" << i);
}
});
}
@@ -277,7 +310,7 @@
std::vector<int> msgCount(LEN, 0);
for (auto m : v)
{
- auto i = StringHelper::toInt(m->getMessage().substr(7));
+ auto i = StringHelper::toInt(m->getRenderedMessage().substr(7));
LOGUNIT_ASSERT(0 <= i);
LOGUNIT_ASSERT(i < LEN);
++msgCount[i];
@@ -340,17 +373,17 @@
async->activateOptions(p);
auto rootLogger = Logger::getRootLogger();
rootLogger->addAppender(async);
- LOG4CXX_INFO(rootLogger, "Hello, World"); // This causes the dispatch thread creation
+ LOG4CXX_INFO_ASYNC(rootLogger, "Hello, World"); // This causes the dispatch thread creation
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); // Wait for the dispatch thread to be ready
{
std::lock_guard<std::mutex> sync(blockableAppender->getBlocker());
for (int i = 0; i < 140; i++)
{
- LOG4CXX_INFO(rootLogger, "Hello, World");
+ LOG4CXX_INFO_ASYNC(rootLogger, "Hello, World " << i);
}
- LOG4CXX_ERROR(rootLogger, "That's all folks.");
+ LOG4CXX_ERROR_ASYNC(rootLogger, "That's all folks.");
}
async->close();
@@ -359,14 +392,14 @@
LOGUNIT_ASSERT(!events.empty());
LOGUNIT_ASSERT(events.size() <= 142);
LoggingEventPtr initialEvent = events.front();
- LOGUNIT_ASSERT(initialEvent->getMessage() == LOG4CXX_STR("Hello, World"));
+ LOGUNIT_ASSERT(initialEvent->getRenderedMessage() == LOG4CXX_STR("Hello, World"));
std::map<LevelPtr, int> levelCount;
int discardMessageCount{ 0 };
LoggingEventPtr discardEvent;
for (auto& e : events)
{
++levelCount[e->getLevel()];
- if (e->getMessage().substr(0, 10) == LOG4CXX_STR("Discarded "))
+ if (e->getRenderedMessage().substr(0, 10) == LOG4CXX_STR("Discarded "))
{
++discardMessageCount;
discardEvent = e;
@@ -414,45 +447,46 @@
async->activateOptions(p);
auto rootLogger = Logger::getRootLogger();
rootLogger->addAppender(async);
- LOG4CXX_INFO(rootLogger, "Hello, World"); // This causes the dispatch thread creation
+ LOG4CXX_INFO_ASYNC(rootLogger, "Hello, World"); // This causes the dispatch thread creation
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); // Wait for the dispatch thread to be ready
for (int i = 0; i < 10; i++)
{
- LOG4CXX_INFO(rootLogger, "Hello, World");
+ LOG4CXX_INFO_ASYNC(rootLogger, "Hello, World " << i);
}
- LOG4CXX_INFO(rootLogger, "Bye bye World");
+ LOG4CXX_INFO_ASYNC(rootLogger, "Bye bye World");
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); // Wait for the dispatch thread take the above events
async->close();
auto& events = loggingAppender->getVector();
std::map<LevelPtr, int> levelCount;
int discardMessageCount{ 0 };
+ int eventCount[] = { 0, 0 };
for (auto& e : events)
{
++levelCount[e->getLevel()];
- auto message = e->getMessage();
+ auto message = e->getRenderedMessage();
+ LogLog::debug(message);
+ auto isAppenderMessage = (message.npos == message.find(LOG4CXX_STR("World")));
+ ++eventCount[isAppenderMessage];
if (message.substr(0, 10) == LOG4CXX_STR("Discarded "))
{
++discardMessageCount;
- auto isAppenderMessage = (message.npos == message.find(LOG4CXX_STR("World")));
LOGUNIT_ASSERT(isAppenderMessage);
}
}
if (helpers::LogLog::isDebugEnabled())
{
LogString msg{ LOG4CXX_STR("messageCounts:") };
- for (auto& item : levelCount)
- {
- msg += LOG4CXX_STR(" ");
- msg += item.first->toString();
- msg += LOG4CXX_STR(" ");
- StringHelper::toString(item.second, p, msg);
- }
- msg += LOG4CXX_STR(" ");
- msg += LOG4CXX_STR("Discarded ");
+ msg += LOG4CXX_STR(" nonAppender ");
+ StringHelper::toString(eventCount[0], p, msg);
+ msg += LOG4CXX_STR(" appender ");
+ StringHelper::toString(eventCount[1], p, msg);
+ msg += LOG4CXX_STR(" discard ");
StringHelper::toString(discardMessageCount, p, msg);
- helpers::LogLog::debug(msg);
+ 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]);
}
#if LOG4CXX_HAS_DOMCONFIGURATOR
@@ -479,7 +513,7 @@
for (size_t i = 0; i < LEN; i++)
{
- LOG4CXX_DEBUG(root, "message" << i);
+ LOG4CXX_DEBUG_ASYNC(root, "message" << i);
}
asyncAppender->close();
diff --git a/src/test/cpp/benchmark/benchmark.cpp b/src/test/cpp/benchmark/benchmark.cpp
index ac79283..3de48d5 100644
--- a/src/test/cpp/benchmark/benchmark.cpp
+++ b/src/test/cpp/benchmark/benchmark.cpp
@@ -132,7 +132,7 @@
class benchmarker : public ::benchmark::Fixture
{
public: // Attributes
- LoggerPtr m_logger = getLogger();
+ LoggerPtr m_appender = getNullWriter();
LoggerPtr m_asyncLogger = getAsyncLogger();
LoggerPtr m_fileLogger = getFileLogger();
LoggerPtr m_JSONLogger = getJSONFileLogger();
@@ -176,7 +176,7 @@
});
}
- static LoggerPtr getLogger(const LogString& pattern = LogString())
+ static LoggerPtr getNullWriter(const LogString& pattern = LogString())
{
static struct initializer
{
@@ -303,10 +303,10 @@
BENCHMARK_DEFINE_F(benchmarker, logDisabledTrace)(benchmark::State& state)
{
- m_logger->setLevel(Level::getDebug());
+ m_appender->setLevel(Level::getDebug());
for (auto _ : state)
{
- LOG4CXX_TRACE( m_logger, LOG4CXX_STR("Hello: static string message"));
+ LOG4CXX_TRACE( m_appender, LOG4CXX_STR("Hello: static string message"));
}
}
BENCHMARK_REGISTER_F(benchmarker, logDisabledTrace)->Name("Testing disabled logging request")->MinWarmUpTime(benchmarker::warmUpSeconds());
@@ -314,10 +314,10 @@
BENCHMARK_DEFINE_F(benchmarker, logShortString)(benchmark::State& state)
{
- m_logger->setLevel(Level::getInfo());
+ m_appender->setLevel(Level::getInfo());
for (auto _ : state)
{
- LOG4CXX_INFO(m_logger, LOG4CXX_STR("Hello"));
+ LOG4CXX_INFO(m_appender, LOG4CXX_STR("Hello"));
}
}
BENCHMARK_REGISTER_F(benchmarker, logShortString)->Name("Appending 5 char string using MessageBuffer, pattern: %m%n");
@@ -325,10 +325,10 @@
BENCHMARK_DEFINE_F(benchmarker, logLongString)(benchmark::State& state)
{
- m_logger->setLevel(Level::getInfo());
+ m_appender->setLevel(Level::getInfo());
for (auto _ : state)
{
- LOG4CXX_INFO( m_logger, LOG4CXX_STR("Hello: this is a long static string message"));
+ LOG4CXX_INFO( m_appender, LOG4CXX_STR("Hello: this is a long static string message"));
}
}
BENCHMARK_REGISTER_F(benchmarker, logLongString)->Name("Appending 49 char string using MessageBuffer, pattern: %m%n");
@@ -339,7 +339,7 @@
int x = 0;
for (auto _ : state)
{
- LOG4CXX_INFO( m_logger, "Hello: message number " << ++x);
+ LOG4CXX_INFO( m_appender, "Hello: message number " << ++x);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntValueMessageBuffer)->Name("Appending int value using MessageBuffer, pattern: %m%n");
@@ -351,7 +351,7 @@
for (auto _ : state)
{
auto f = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
- LOG4CXX_INFO( m_logger, "Hello: message number " << ++x
+ LOG4CXX_INFO( m_appender, "Hello: message number " << ++x
<< " pseudo-random float " << std::setprecision(3) << std::fixed << f);
}
}
@@ -398,7 +398,7 @@
{
auto args_tuple = std::make_tuple(std::move(args)...);
LogString conversionPattern = std::get<0>(args_tuple);
- auto logger = benchmarker::getLogger(conversionPattern);
+ auto logger = benchmarker::getNullWriter(conversionPattern);
int x = 0;
for (auto _ : state)
{
@@ -413,7 +413,7 @@
{
for (auto _ : state)
{
- LOG4CXX_INFO_FMT(m_logger, "Hello: this is a long static string message", 0);
+ LOG4CXX_INFO_FMT(m_appender, "Hello: this is a long static string message", 0);
}
}
BENCHMARK_REGISTER_F(benchmarker, logLongStringFMT)->Name("Appending 49 char string using FMT, pattern: %m%n");
@@ -424,7 +424,7 @@
int x = 0;
for (auto _ : state)
{
- LOG4CXX_INFO_FMT(m_logger, "Hello: msg number {}", ++x);
+ LOG4CXX_INFO_FMT(m_appender, "Hello: msg number {}", ++x);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntValueFMT)->Name("Appending int value using FMT, pattern: %m%n");
@@ -436,7 +436,7 @@
for (auto _ : state)
{
auto f = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
- LOG4CXX_INFO_FMT(m_logger, "Hello: msg number {} pseudo-random float {:.3f}", ++x, f);
+ LOG4CXX_INFO_FMT(m_appender, "Hello: msg number {} pseudo-random float {:.3f}", ++x, f);
}
}
BENCHMARK_REGISTER_F(benchmarker, logIntPlusFloatValueFMT)->Name("Appending int+float using FMT, pattern: %m%n");
@@ -459,7 +459,7 @@
, static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
, static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
};
- LOG4CXX_INFO_FMT(m_logger, "Hello: msg number {} pseudo-random float {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}"
+ LOG4CXX_INFO_FMT(m_appender, "Hello: msg number {} pseudo-random float {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}"
, ++x
, f[0]
, f[1]
@@ -476,7 +476,6 @@
}
BENCHMARK_REGISTER_F(benchmarker, logIntPlus10FloatValueFMT)->Name("Appending int+10float using FMT, pattern: %m%n");
BENCHMARK_REGISTER_F(benchmarker, logIntPlus10FloatValueFMT)->Name("Appending int+10float using FMT, pattern: %m%n")->Threads(benchmarker::threadCount());
-#endif
BENCHMARK_DEFINE_F(benchmarker, asyncIntPlus10FloatValueFmtBuffer)(benchmark::State& state)
{
@@ -495,7 +494,7 @@
, static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
, static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
};
- LOG4CXX_INFO_FMT(m_logger, "Hello: msg number {} pseudo-random float {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}"
+ LOG4CXX_INFO_FMT(m_asyncLogger, "Hello: msg number {} pseudo-random float {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}"
, ++x
, f[0]
, f[1]
@@ -512,6 +511,42 @@
}
BENCHMARK_REGISTER_F(benchmarker, asyncIntPlus10FloatValueFmtBuffer)->Name("Async, Sending int+10float using FMT");
BENCHMARK_REGISTER_F(benchmarker, asyncIntPlus10FloatValueFmtBuffer)->Name("Async, Sending int+10float using FMT")->Threads(benchmarker::threadCount());
+#endif
+
+BENCHMARK_DEFINE_F(benchmarker, asyncIntPlus10FloatAsyncBuffer)(benchmark::State& state)
+{
+ int x = 0;
+ for (auto _ : state)
+ {
+ float f[] =
+ { static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ , static_cast<float>(rand()) / static_cast<float>(RAND_MAX)
+ };
+ LOG4CXX_INFO_ASYNC(m_asyncLogger, "Hello: message number " << ++x
+ << " pseudo-random float" << std::setprecision(3) << std::fixed
+ << ' ' << f[0]
+ << ' ' << f[1]
+ << ' ' << f[2]
+ << ' ' << f[3]
+ << ' ' << f[4]
+ << ' ' << f[5]
+ << ' ' << f[6]
+ << ' ' << f[7]
+ << ' ' << f[8]
+ << ' ' << f[9]
+ );
+ }
+}
+BENCHMARK_REGISTER_F(benchmarker, asyncIntPlus10FloatAsyncBuffer)->Name("Async, Sending int+10float using AsyncBuffer, pattern: %m%n");
+BENCHMARK_REGISTER_F(benchmarker, asyncIntPlus10FloatAsyncBuffer)->Name("Async, Sending int+10float using AsyncBuffer, pattern: %m%n")->Threads(benchmarker::threadCount());
BENCHMARK_DEFINE_F(benchmarker, fileIntPlusFloatValueMessageBuffer)(benchmark::State& state)
{