You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by sw...@apache.org on 2023/04/21 05:13:16 UTC

[logging-log4cxx] 01/01: Allow message strings containing quote characters to be logged to a database

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

swebb2066 pushed a commit to branch add-sql-message
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git

commit 2dd631130f517953bb4044dd09797c9269cd68d8
Author: Stephen Webb <sw...@gmail.com>
AuthorDate: Fri Apr 21 15:12:46 2023 +1000

    Allow message strings containing quote characters to be logged to a database
---
 src/main/cpp/messagepatternconverter.cpp           | 67 +++++++++++++++++-----
 src/main/include/log4cxx/db/odbcappender.h         |  2 +-
 src/test/cpp/db/odbcappendertestcase.cpp           |  2 +-
 .../input/xml/odbcAppenderDSN-Log4cxxTest.xml      |  2 +-
 4 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/src/main/cpp/messagepatternconverter.cpp b/src/main/cpp/messagepatternconverter.cpp
index 83269d97..c31e3ef2 100644
--- a/src/main/cpp/messagepatternconverter.cpp
+++ b/src/main/cpp/messagepatternconverter.cpp
@@ -20,31 +20,70 @@
 #include <log4cxx/spi/loggingevent.h>
 #include <log4cxx/spi/location/locationinfo.h>
 
-using namespace log4cxx;
-using namespace log4cxx::pattern;
-using namespace log4cxx::spi;
-using namespace log4cxx::helpers;
+namespace log4cxx
+{
+namespace pattern
+{
 
 IMPLEMENT_LOG4CXX_OBJECT(MessagePatternConverter)
+/**
+ * Formats the message of an logging event for a quoted context
+  */
+class QuotedMessagePatternConverter : public LoggingEventPatternConverter
+{
+	logchar m_quote;
+	public:
+		QuotedMessagePatternConverter(logchar quote)
+			: LoggingEventPatternConverter(LOG4CXX_STR("Message"), LOG4CXX_STR("quoted"))
+			, m_quote(quote)
+			{}
 
-MessagePatternConverter::MessagePatternConverter() :
-	LoggingEventPatternConverter(LOG4CXX_STR("Message"),
-		LOG4CXX_STR("message"))
+		using LoggingEventPatternConverter::format;
+
+		void format
+			( const spi::LoggingEventPtr& event
+			, LogString&                  toAppendTo
+			, helpers::Pool&              p
+			) const override
+		{
+			auto& input = event->getRenderedMessage();
+			size_t endIndex, startIndex = 0;
+			while ((endIndex = input.find(m_quote, startIndex)) != input.npos)
+			{
+				toAppendTo.append(input.substr(startIndex, endIndex - startIndex + 1));
+				toAppendTo += m_quote;
+				startIndex = endIndex + 1;
+			}
+			toAppendTo.append(input.substr(startIndex));
+		}
+};
+
+MessagePatternConverter::MessagePatternConverter()
+	: LoggingEventPatternConverter(LOG4CXX_STR("Message")
+	, LOG4CXX_STR("message"))
 {
 }
 
 PatternConverterPtr MessagePatternConverter::newInstance(
-	const std::vector<LogString>& /* options */)
+	const std::vector<LogString>& options)
 {
-	static PatternConverterPtr def = std::make_shared<MessagePatternConverter>();
-	return def;
+	if (options.empty() || options.front().empty())
+	{
+		static PatternConverterPtr def = std::make_shared<MessagePatternConverter>();
+		return def;
+	}
+	return std::make_shared<QuotedMessagePatternConverter>(options.front().front());
 }
 
-void MessagePatternConverter::format(
-	const LoggingEventPtr& event,
-	LogString& toAppendTo,
-	Pool& /* p */) const
+void MessagePatternConverter::format
+	( const spi::LoggingEventPtr& event
+	, LogString&                  toAppendTo
+	, helpers::Pool&           /* p */
+	) const
 {
 	toAppendTo.append(event->getRenderedMessage());
 }
 
+} // namespace pattern
+} // namespace log4cxx
+
diff --git a/src/main/include/log4cxx/db/odbcappender.h b/src/main/include/log4cxx/db/odbcappender.h
index f50f64b8..aa85aaf6 100644
--- a/src/main/include/log4cxx/db/odbcappender.h
+++ b/src/main/include/log4cxx/db/odbcappender.h
@@ -103,7 +103,7 @@ An example configuration that writes to the data source named "LoggingDSN" is:
 <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 appender name="SqlAppender" class="ODBCAppender">
  <param name="DSN" value="LoggingDSN"/>
- <param name="sql" value="INSERT INTO [SomeDatabaseName].[SomeUserName].[SomeTableName] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message]) VALUES ('%t', '%c','%d{dd MMM yyyy HH:mm:ss.SSS}','%p','%f','%L','%m')" />
+ <param name="sql" value="INSERT INTO [SomeDatabaseName].[SomeUserName].[SomeTableName] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message]) VALUES ('%t', '%c','%d{dd MMM yyyy HH:mm:ss.SSS}','%p','%f','%L','%m{'}')" />
 </appender>
 <appender name="ASYNC" class="AsyncAppender">
   <param name="BufferSize" value="1000"/>
diff --git a/src/test/cpp/db/odbcappendertestcase.cpp b/src/test/cpp/db/odbcappendertestcase.cpp
index 14c91328..ca568aed 100644
--- a/src/test/cpp/db/odbcappendertestcase.cpp
+++ b/src/test/cpp/db/odbcappendertestcase.cpp
@@ -88,7 +88,7 @@ class ODBCAppenderTestCase : public AppenderSkeletonTestCase
 			auto odbc = Logger::getLogger("DB.UnitTest");
 			for (int i = 0; i < 100; ++i)
 			{
-				LOG4CXX_INFO(odbc, "Message " << i);
+				LOG4CXX_INFO(odbc, "Message '" << i << "'");
 				apr_sleep(30000);
 			}
 			LOG4CXX_INFO(odbc, "Last message");
diff --git a/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml b/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
index 3e035869..ff5bcbe2 100644
--- a/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
+++ b/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
@@ -27,7 +27,7 @@
 </appender>
 <appender name="SqlAppender" class="ODBCAppender">
  <param name="DSN" value="Log4cxxTest"/>
- <param name="sql" value="INSERT INTO [ApplicationLogs].[dbo].[UnitTestLog] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message]) VALUES ('%t', '%c','%d{dd MMM yyyy HH:mm:ss.SSS}','%p','%f','%L','%m')" />
+ <param name="sql" value="INSERT INTO [ApplicationLogs].[dbo].[UnitTestLog] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message]) VALUES ('%t', '%c','%d{dd MMM yyyy HH:mm:ss.SSS}','%p','%f','%L','%m{'}')" />
  <!--param name="User" value="dbo"/-->
  <!--param name="Password" value="myLog4cxxTestPassword"/-->
 </appender>