You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rm...@apache.org on 2022/12/16 01:42:59 UTC

[logging-log4cxx] branch LOGCXX-567 updated: Turn the stacktrace into a call-site macro instead of inside the library

This is an automated email from the ASF dual-hosted git repository.

rmiddleton pushed a commit to branch LOGCXX-567
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/LOGCXX-567 by this push:
     new 62439b18 Turn the stacktrace into a call-site macro instead of inside the library
62439b18 is described below

commit 62439b188cd7f5d009b6e4f53a95067d6404643b
Author: Robert Middleton <ro...@rm5248.com>
AuthorDate: Thu Dec 15 20:42:53 2022 -0500

    Turn the stacktrace into a call-site macro instead of inside the library
---
 src/main/cpp/CMakeLists.txt                        |   6 ++
 src/main/cpp/logbuilder.cpp                        |  29 ++++++
 src/main/cpp/logger.cpp                            |  54 +++++------
 src/main/cpp/loggingevent.cpp                      |  46 ++++++++--
 src/main/cpp/stacktracepatternconverter.cpp        |   5 +
 src/main/include/log4cxx/log4cxx.h.in              |   1 +
 src/main/include/log4cxx/logbuilder.h              |  55 +++++++++++
 src/main/include/log4cxx/logger.h                  | 102 ++++++++++++++-------
 .../include/log4cxx/private/log4cxx_private.h.in   |   1 -
 .../include/log4cxx/spi/location/locationinfo.h    |   1 -
 src/main/include/log4cxx/spi/loggingevent.h        |  10 ++
 11 files changed, 241 insertions(+), 69 deletions(-)

diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 59276e19..f2ab2796 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -27,6 +27,11 @@ else()
 endif()
 add_dependencies(log4cxx configure_log4cxx)
 
+get_directory_property( HAS_BOOST_STACKTRACE DIRECTORY ../include DEFINITION HAS_BOOST_STACKTRACE )
+if(HAS_BOOST_STACKTRACE)
+    target_compile_definitions(log4cxx PRIVATE LOG4CXX_ENABLE_STACKTRACE)
+endif()
+
 set(extra_classes "")
 
 if(LOG4CXX_NETWORKING_SUPPORT)
@@ -126,6 +131,7 @@ target_sources(log4cxx
   loader.cpp
   locale.cpp
   locationinfo.cpp
+  logbuilder.cpp
   logger.cpp
   loggermatchfilter.cpp
   loggerpatternconverter.cpp
diff --git a/src/main/cpp/logbuilder.cpp b/src/main/cpp/logbuilder.cpp
new file mode 100644
index 00000000..12bda43f
--- /dev/null
+++ b/src/main/cpp/logbuilder.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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/logbuilder.h>
+
+using log4cxx::OptionalLogParams;
+
+OptionalLogParams::OptionalLogParams(){}
+
+#if LOG4CXX_HAS_BOOST_STACKTRACE
+OptionalLogParams OptionalLogParams::setStacktrace(const boost::stacktrace::stacktrace* stacktrace){
+	m_builderParams[ParameterType::BoostStacktrace] = stacktrace;
+	return *this;
+}
+#endif
diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp
index 8c7d8ba5..8233ce65 100644
--- a/src/main/cpp/logger.cpp
+++ b/src/main/cpp/logger.cpp
@@ -158,27 +158,27 @@ void Logger::closeNestedAppenders()
 	}
 }
 
-
 void Logger::forcedLog(const LevelPtr& level1, const std::string& message,
-	const LocationInfo& location) const
+	const LocationInfo& location, const log4cxx::OptionalLogParams& optionalParams) const
 {
 	if (!getHierarchy()) // Has removeHierarchy() been called?
 		return;
 	Pool p;
 	LOG4CXX_DECODE_CHAR(msg, message);
-	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location);
-	callAppenders(event, p);
-}
-
+#if LOG4CXX_HAS_BOOST_STACKTRACE
+	auto it = optionalParams.m_builderParams.find(OptionalLogParams::ParameterType::BoostStacktrace);
+	const boost::stacktrace::stacktrace* stacktrace = nullptr;
+	if( it != optionalParams.m_builderParams.end() ){
+		stacktrace = static_cast<const boost::stacktrace::stacktrace*>(it->second);
+	}
+#endif
+	LoggingEventPtr event;
 
-void Logger::forcedLog(const LevelPtr& level1, const std::string& message) const
-{
-	if (!getHierarchy()) // Has removeHierarchy() been called?
-		return;
-	Pool p;
-	LOG4CXX_DECODE_CHAR(msg, message);
-	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg,
-			LocationInfo::getLocationUnavailable());
+	if(stacktrace){
+		event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location, *stacktrace);
+	}else{
+		event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location);
+	}
 	callAppenders(event, p);
 }
 
@@ -703,24 +703,26 @@ LoggerPtr Logger::getLoggerLS(const LogString& name)
 
 #if LOG4CXX_WCHAR_T_API
 void Logger::forcedLog(const LevelPtr& level1, const std::wstring& message,
-	const LocationInfo& location) const
+	const LocationInfo& location, const log4cxx::OptionalLogParams& optionalParams) const
 {
 	if (!getHierarchy()) // Has removeHierarchy() been called?
 		return;
 	Pool p;
 	LOG4CXX_DECODE_WCHAR(msg, message);
-	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location);
-	callAppenders(event, p);
-}
+#if LOG4CXX_HAS_BOOST_STACKTRACE
+	auto it = optionalParams.m_builderParams.find(OptionalLogParams::ParameterType::BoostStacktrace);
+	const boost::stacktrace::stacktrace* stacktrace = nullptr;
+	if( it != optionalParams.m_builderParams.end() ){
+		stacktrace = static_cast<const boost::stacktrace::stacktrace*>(it->second);
+	}
+#endif
+	LoggingEventPtr event;
 
-void Logger::forcedLog(const LevelPtr& level1, const std::wstring& message) const
-{
-	if (!getHierarchy()) // Has removeHierarchy() been called?
-		return;
-	Pool p;
-	LOG4CXX_DECODE_WCHAR(msg, message);
-	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg,
-			LocationInfo::getLocationUnavailable());
+	if(stacktrace){
+		event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location, *stacktrace);
+	}else{
+		event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg, location);
+	}
 	callAppenders(event, p);
 }
 
diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp
index 0b1f1930..b6f23671 100644
--- a/src/main/cpp/loggingevent.cpp
+++ b/src/main/cpp/loggingevent.cpp
@@ -81,6 +81,27 @@ struct LoggingEvent::LoggingEventPrivate
 	{
 	}
 
+	LoggingEventPrivate(
+		const LogString& logger1, const LevelPtr& level1,
+		const LogString& message1, const LocationInfo& locationInfo1,
+		const boost::stacktrace::stacktrace& stacktrace) :
+		logger(logger1),
+		level(level1),
+		ndc(0),
+		mdcCopy(0),
+		properties(0),
+		ndcLookupRequired(true),
+		mdcCopyLookupRequired(true),
+		message(message1),
+		timeStamp(Date::currentTime()),
+		locationInfo(locationInfo1),
+		threadName(getCurrentThreadName()),
+		threadUserName(getCurrentThreadUserName()),
+		chronoTimeStamp(std::chrono::microseconds(timeStamp)),
+		stacktrace(std::make_unique<boost::stacktrace::stacktrace>(stacktrace))
+	{
+	}
+
 	~LoggingEventPrivate()
 	{
 		delete ndc;
@@ -148,7 +169,10 @@ struct LoggingEvent::LoggingEventPrivate
 	std::chrono::time_point<std::chrono::system_clock> chronoTimeStamp;
 
 #if LOG4CXX_HAS_BOOST_STACKTRACE
-	boost::stacktrace::stacktrace stacktrace;
+	// we make this a unique_ptr so we can avoid constructing it by default.
+	// This should add only a small amount of overhead when stacktraces are
+	// enabled in order to dereference the pointer.
+	std::unique_ptr<boost::stacktrace::stacktrace> stacktrace;
 #endif
 };
 
@@ -175,6 +199,16 @@ LoggingEvent::LoggingEvent(
 {
 }
 
+#if LOG4CXX_HAS_BOOST_STACKTRACE
+LoggingEvent::LoggingEvent(
+	const LogString& logger1, const LevelPtr& level1,
+	const LogString& message1, const LocationInfo& locationInfo1,
+	const boost::stacktrace::stacktrace& stacktrace) :
+	m_priv(std::make_unique<LoggingEventPrivate>(logger1, level1, message1, locationInfo1, stacktrace))
+{
+}
+#endif
+
 LoggingEvent::~LoggingEvent()
 {
 }
@@ -449,11 +483,11 @@ std::chrono::time_point<std::chrono::system_clock> LoggingEvent::getChronoTimeSt
 }
 
 LogString LoggingEvent::getStacktrace() const{
-#if !LOG4CXX_HAS_BOOST_STACKTRACE
-	return LogString();
-#else
-	::log4cxx::helpers::MessageBuffer oss_;
-	return oss_.str(oss_ << m_priv->stacktrace);
+#if LOG4CXX_HAS_BOOST_STACKTRACE
+	if(m_priv->stacktrace){
+		return boost::stacktrace::to_string(*m_priv->stacktrace);
+	}
 #endif
+	return LogString();
 }
 
diff --git a/src/main/cpp/stacktracepatternconverter.cpp b/src/main/cpp/stacktracepatternconverter.cpp
index 5fb71db4..75e48962 100644
--- a/src/main/cpp/stacktracepatternconverter.cpp
+++ b/src/main/cpp/stacktracepatternconverter.cpp
@@ -45,6 +45,11 @@ void StacktracePatternConverter::format(
 	LogString& toAppendTo,
 	Pool& /* p */) const
 {
+	LogString stacktrace = event->getStacktrace();
+	if(stacktrace.empty()){
+		return;
+	}
+	toAppendTo.append(LOG4CXX_EOL);
 	toAppendTo.append(event->getStacktrace());
 }
 
diff --git a/src/main/include/log4cxx/log4cxx.h.in b/src/main/include/log4cxx/log4cxx.h.in
index 12ed0dbc..c67fd99d 100644
--- a/src/main/include/log4cxx/log4cxx.h.in
+++ b/src/main/include/log4cxx/log4cxx.h.in
@@ -50,6 +50,7 @@
 #define LOG4CXX_CFSTRING_API @CFSTRING_API@
 #define LOG4CXX_HAS_NETWORKING @NETWORKING_SUPPORT@
 #define LOG4CXX_HAS_MULTIPROCESS_ROLLING_FILE_APPENDER @MULTIPROCESS_RFA@
+#define LOG4CXX_HAS_BOOST_STACKTRACE @HAS_BOOST_STACKTRACE@
 
 typedef long long log4cxx_int64_t;
 #define LOG4CXX_USE_GLOBAL_SCOPE_TEMPLATE 0
diff --git a/src/main/include/log4cxx/logbuilder.h b/src/main/include/log4cxx/logbuilder.h
new file mode 100644
index 00000000..7e3dbbe2
--- /dev/null
+++ b/src/main/include/log4cxx/logbuilder.h
@@ -0,0 +1,55 @@
+/*
+ * 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_LOGBUILDER_H
+#define _LOG4CXX_LOGBUILDER_H
+
+#include <log4cxx/spi/location/locationinfo.h>
+#include <log4cxx/level.h>
+#include <map>
+
+#if defined(LOG4CXX_ENABLE_STACKTRACE) && LOG4CXX_HAS_BOOST_STACKTRACE
+#include <boost/stacktrace.hpp>
+#endif
+
+namespace log4cxx {
+
+/**
+ * The OptionalLogParams class provides a way of providing optional log parameters,
+ * depending on if the feature is enabled by client code or not.
+ */
+class OptionalLogParams{
+public:
+	enum class ParameterType{
+	BoostStacktrace,
+    };
+
+	OptionalLogParams();
+
+#if defined(LOG4CXX_ENABLE_STACKTRACE) && LOG4CXX_HAS_BOOST_STACKTRACE
+	OptionalLogParams setStacktrace(const boost::stacktrace::stacktrace* stacktrace);
+#endif
+
+private:
+    std::map<ParameterType,const void*> m_builderParams;
+
+    friend class Logger;
+};
+
+}
+
+#endif
diff --git a/src/main/include/log4cxx/logger.h b/src/main/include/log4cxx/logger.h
index 27eb93d1..c0e3b19a 100644
--- a/src/main/include/log4cxx/logger.h
+++ b/src/main/include/log4cxx/logger.h
@@ -24,6 +24,7 @@
 #include <log4cxx/spi/location/locationinfo.h>
 #include <log4cxx/helpers/resourcebundle.h>
 #include <log4cxx/helpers/messagebuffer.h>
+#include <log4cxx/logbuilder.h>
 
 namespace log4cxx
 {
@@ -457,15 +458,10 @@ class LOG4CXX_EXPORT Logger :
 		@param message message.
 		@param location location of source of logging request.
 		*/
-		void forcedLog(const LevelPtr& level, const std::string& message,
-			const log4cxx::spi::LocationInfo& location) const;
-		/**
-		This method creates a new logging event and logs the event
-		without further checks.
-		@param level the level to log.
-		@param message message.
-		*/
-		void forcedLog(const LevelPtr& level, const std::string& message) const;
+		void forcedLog(const LevelPtr& level,
+			const std::string& message,
+			const log4cxx::spi::LocationInfo& location = log4cxx::spi::LocationInfo::getLocationUnavailable(),
+			const log4cxx::OptionalLogParams& optionalParams = log4cxx::OptionalLogParams()) const;
 
 #if LOG4CXX_WCHAR_T_API
 		/**
@@ -475,15 +471,11 @@ class LOG4CXX_EXPORT Logger :
 		@param message message.
 		@param location location of source of logging request.
 		*/
-		void forcedLog(const LevelPtr& level, const std::wstring& message,
-			const log4cxx::spi::LocationInfo& location) const;
-		/**
-		This method creates a new logging event and logs the event
-		without further checks.
-		@param level the level to log.
-		@param message message.
-		*/
-		void forcedLog(const LevelPtr& level, const std::wstring& message) const;
+		void forcedLog(const LevelPtr& level,
+			const std::wstring& message,
+			const log4cxx::spi::LocationInfo& location = log4cxx::spi::LocationInfo::getLocationUnavailable(),
+			const log4cxx::OptionalLogParams& optionalParams = log4cxx::OptionalLogParams()) const;
+
 #endif
 #if LOG4CXX_UNICHAR_API || LOG4CXX_CFSTRING_API
 		/**
@@ -1718,6 +1710,12 @@ LOG4CXX_LIST_DEF(LoggerList, LoggerPtr);
 	#endif
 #endif
 
+#if defined(LOG4CXX_ENABLE_STACKTRACE) && LOG4CXX_HAS_BOOST_STACKTRACE
+#define LOG4CXX_STACKTRACE const boost::stacktrace::stacktrace stack_trace; \
+	builder.setStacktrace(&stack_trace);
+#else
+#define LOG4CXX_STACKTRACE
+#endif
 
 /**
 Logs a message to a specified logger with a specified level.
@@ -1729,7 +1727,9 @@ Logs a message to a specified logger with a specified level.
 #define LOG4CXX_LOG(logger, level, message) do { \
 		if (logger->isEnabledFor(level)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(level, oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(level, oss_.str(oss_ << message), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a message to a specified logger with a specified level, formatting utilizing libfmt
@@ -1740,7 +1740,9 @@ Logs a message to a specified logger with a specified level, formatting utilizin
 */
 #define LOG4CXX_LOG_FMT(logger, level, ...) do { \
 		if (logger->isEnabledFor(level)) {\
-			logger->forcedLog(level, fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(level, fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a message to a specified logger with a specified level.
@@ -1752,7 +1754,9 @@ Logs a message to a specified logger with a specified level.
 #define LOG4CXX_LOGLS(logger, level, message) do { \
 		if (logger->isEnabledFor(level)) {\
 			::log4cxx::helpers::LogCharMessageBuffer oss_; \
-			logger->forcedLog(level, oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(level, oss_.str(oss_ << message), LOG4CXX_LOCATION, builder); }} while (0)
 
 #if !defined(LOG4CXX_THRESHOLD) || LOG4CXX_THRESHOLD <= 10000
 /**
@@ -1764,7 +1768,9 @@ Logs a message to a specified logger with the DEBUG level.
 #define LOG4CXX_DEBUG(logger, message) do { \
 		if (LOG4CXX_UNLIKELY(::log4cxx::Logger::isDebugEnabledFor(logger))) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getDebug(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getDebug(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a message to a specified logger with the DEBUG level, formatting with libfmt
@@ -1774,7 +1780,9 @@ Logs a message to a specified logger with the DEBUG level, formatting with libfm
 */
 #define LOG4CXX_DEBUG_FMT(logger, ...) do { \
 		if (LOG4CXX_UNLIKELY(::log4cxx::Logger::isDebugEnabledFor(logger))) {\
-			logger->forcedLog(::log4cxx::Level::getDebug(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getDebug(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder);  }} while (0)
 #else
 #define LOG4CXX_DEBUG(logger, message)
 #define LOG4CXX_DEBUG_FMT(logger, ...)
@@ -1790,7 +1798,9 @@ Logs a message to a specified logger with the TRACE level.
 #define LOG4CXX_TRACE(logger, message) do { \
 		if (LOG4CXX_UNLIKELY(::log4cxx::Logger::isTraceEnabledFor(logger))) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getTrace(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getTrace(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a message to a specified logger with the TRACE level, formatting with libfmt.
@@ -1800,7 +1810,9 @@ Logs a message to a specified logger with the TRACE level, formatting with libfm
 */
 #define LOG4CXX_TRACE_FMT(logger, ...) do { \
 		if (LOG4CXX_UNLIKELY(::log4cxx::Logger::isTraceEnabledFor(logger))) {\
-			logger->forcedLog(::log4cxx::Level::getTrace(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getTrace(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 #else
 #define LOG4CXX_TRACE(logger, message)
 #define LOG4CXX_TRACE_FMT(logger, ...)
@@ -1816,7 +1828,9 @@ Logs a message to a specified logger with the INFO level.
 #define LOG4CXX_INFO(logger, message) do { \
 		if (::log4cxx::Logger::isInfoEnabledFor(logger)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getInfo(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder);  }} while (0)
 
 /**
 Logs a message to a specified logger with the INFO level, formatting with libfmt.
@@ -1827,7 +1841,9 @@ Logs a message to a specified logger with the INFO level, formatting with libfmt
 */
 #define LOG4CXX_INFO_FMT(logger, ...) do { \
 		if (::log4cxx::Logger::isInfoEnabledFor(logger)) {\
-			logger->forcedLog(::log4cxx::Level::getInfo(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getInfo(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 #else
 #define LOG4CXX_INFO(logger, message)
 #define LOG4CXX_INFO_FMT(logger, ...)
@@ -1843,7 +1859,9 @@ Logs a message to a specified logger with the WARN level.
 #define LOG4CXX_WARN(logger, message) do { \
 		if (::log4cxx::Logger::isWarnEnabledFor(logger)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getWarn(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getWarn(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder);  }} while (0)
 
 /**
 Logs a message to a specified logger with the WARN level, formatting with libfmt
@@ -1853,7 +1871,9 @@ Logs a message to a specified logger with the WARN level, formatting with libfmt
 */
 #define LOG4CXX_WARN_FMT(logger, ...) do { \
 		if (::log4cxx::Logger::isWarnEnabledFor(logger)) {\
-			logger->forcedLog(::log4cxx::Level::getWarn(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getWarn(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 #else
 #define LOG4CXX_WARN(logger, message)
 #define LOG4CXX_WARN_FMT(logger, ...)
@@ -1869,7 +1889,9 @@ Logs a message to a specified logger with the ERROR level.
 #define LOG4CXX_ERROR(logger, message) do { \
 		if (::log4cxx::Logger::isErrorEnabledFor(logger)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getError(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getError(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder);  }} while (0)
 
 /**
 Logs a message to a specified logger with the ERROR level, formatting with libfmt
@@ -1879,7 +1901,9 @@ Logs a message to a specified logger with the ERROR level, formatting with libfm
 */
 #define LOG4CXX_ERROR_FMT(logger, ...) do { \
 		if (::log4cxx::Logger::isErrorEnabledFor(logger)) {\
-			logger->forcedLog(::log4cxx::Level::getError(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getError(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a error if the condition is not true.
@@ -1891,7 +1915,9 @@ Logs a error if the condition is not true.
 #define LOG4CXX_ASSERT(logger, condition, message) do { \
 		if (!(condition) && ::log4cxx::Logger::isErrorEnabledFor(logger)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getError(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getError(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder); }} while (0)
 
 /**
 Logs a error if the condition is not true, formatting with libfmt
@@ -1902,7 +1928,9 @@ Logs a error if the condition is not true, formatting with libfmt
 */
 #define LOG4CXX_ASSERT_FMT(logger, condition, ...) do { \
 		if (!(condition) && ::log4cxx::Logger::isErrorEnabledFor(logger)) {\
-			logger->forcedLog(::log4cxx::Level::getError(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getError(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 
 #else
 #define LOG4CXX_ERROR(logger, message)
@@ -1921,7 +1949,9 @@ Logs a message to a specified logger with the FATAL level.
 #define LOG4CXX_FATAL(logger, message) do { \
 		if (::log4cxx::Logger::isFatalEnabledFor(logger)) {\
 			::log4cxx::helpers::MessageBuffer oss_; \
-			logger->forcedLog(::log4cxx::Level::getFatal(), oss_.str(oss_ << message), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getFatal(), oss_.str(oss_ << message), LOG4CXX_LOCATION, builder);  }} while (0)
 
 /**
 Logs a message to a specified logger with the FATAL level, formatting with libfmt
@@ -1931,7 +1961,9 @@ Logs a message to a specified logger with the FATAL level, formatting with libfm
 */
 #define LOG4CXX_FATAL_FMT(logger, ...) do { \
 		if (::log4cxx::Logger::isFatalEnabledFor(logger)) {\
-			logger->forcedLog(::log4cxx::Level::getFatal(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION); }} while (0)
+			::log4cxx::OptionalLogParams builder; \
+			LOG4CXX_STACKTRACE \
+			logger->forcedLog(::log4cxx::Level::getFatal(), fmt::format( __VA_ARGS__ ), LOG4CXX_LOCATION, builder); }} while (0)
 #else
 #define LOG4CXX_FATAL(logger, message)
 #define LOG4CXX_FATAL_FMT(logger, ...)
diff --git a/src/main/include/log4cxx/private/log4cxx_private.h.in b/src/main/include/log4cxx/private/log4cxx_private.h.in
index b6ad1bdb..9eb5ec23 100644
--- a/src/main/include/log4cxx/private/log4cxx_private.h.in
+++ b/src/main/include/log4cxx/private/log4cxx_private.h.in
@@ -63,6 +63,5 @@
 #define LOG4CXX_HAS_SETTHREADDESCRIPTION @HAS_SETTHREADDESCRIPTION@
 #define LOG4CXX_HAS_GETTHREADDESCRIPTION @HAS_GETTHREADDESCRIPTION@
 #define LOG4CXX_HAS_THREAD_LOCAL @HAS_THREAD_LOCAL@
-#define LOG4CXX_HAS_BOOST_STACKTRACE @HAS_BOOST_STACKTRACE@
 
 #endif
diff --git a/src/main/include/log4cxx/spi/location/locationinfo.h b/src/main/include/log4cxx/spi/location/locationinfo.h
index 51b1ce4c..eac4861d 100644
--- a/src/main/include/log4cxx/spi/location/locationinfo.h
+++ b/src/main/include/log4cxx/spi/location/locationinfo.h
@@ -169,7 +169,6 @@ class LOG4CXX_EXPORT LocationInfo
 	#define __LOG4CXX_FUNC__ ""
 #endif
 
-
 #define LOG4CXX_LOCATION ::log4cxx::spi::LocationInfo(__FILE__,         \
 	::log4cxx::spi::LocationInfo::calcShortFileName(__FILE__), \
 	__LOG4CXX_FUNC__, \
diff --git a/src/main/include/log4cxx/spi/loggingevent.h b/src/main/include/log4cxx/spi/loggingevent.h
index 1e14764b..d649d9c1 100644
--- a/src/main/include/log4cxx/spi/loggingevent.h
+++ b/src/main/include/log4cxx/spi/loggingevent.h
@@ -26,6 +26,9 @@
 #include <vector>
 #include <chrono>
 
+#if defined(LOG4CXX_ENABLE_STACKTRACE) && LOG4CXX_HAS_BOOST_STACKTRACE
+#include <boost/stacktrace.hpp>
+#endif
 
 namespace log4cxx
 {
@@ -76,6 +79,13 @@ class LOG4CXX_EXPORT LoggingEvent :
 			const LevelPtr& level,   const LogString& message,
 			const log4cxx::spi::LocationInfo& location);
 
+#if defined(LOG4CXX_ENABLE_STACKTRACE) && LOG4CXX_HAS_BOOST_STACKTRACE
+		LoggingEvent(const LogString& logger,
+			const LevelPtr& level,   const LogString& message,
+			const log4cxx::spi::LocationInfo& location,
+			const boost::stacktrace::stacktrace& stacktrace);
+#endif
+
 		~LoggingEvent();
 
 		/** Return the level of this event. */