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/08/06 05:37:56 UTC

[logging-log4cxx] 01/01: Allow a QString in a LOG4CXX_ macro when 'Qt support/integration' is ON

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

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

commit 5419017124464677ebfbc145d8a2aa29f2bb979e
Author: Stephen Webb <sw...@gmail.com>
AuthorDate: Sun Aug 6 15:37:05 2023 +1000

    Allow a QString in a LOG4CXX_ macro when 'Qt support/integration' is ON
---
 src/examples/cpp/CMakeLists.txt              |  7 +++
 src/examples/cpp/MyApp-qt.cpp                | 20 ++++++++
 src/examples/cpp/com/foo/bar-qt.cpp          | 11 ++++
 src/examples/cpp/com/foo/config-qt.cpp       | 71 +++++++++++++++++++++++++
 src/examples/cpp/com/foo/config-qt.h         | 22 ++++++++
 src/main/include/log4cxx-qt/logger.h         | 77 ++++++++++++++++++++++++++++
 src/site/markdown/development/build-cmake.md |  1 +
 src/site/markdown/qt-support.md              | 11 +++-
 8 files changed, 218 insertions(+), 2 deletions(-)

diff --git a/src/examples/cpp/CMakeLists.txt b/src/examples/cpp/CMakeLists.txt
index f1cf57d3..0a6c0a80 100644
--- a/src/examples/cpp/CMakeLists.txt
+++ b/src/examples/cpp/CMakeLists.txt
@@ -16,6 +16,9 @@
 #
 
 set(ALL_LOG4CXX_EXAMPLES auto-configured console delayedloop stream trivial custom-appender MyApp1 MyApp2)
+if(LOG4CXX_QT_SUPPORT)
+  list(APPEND ALL_LOG4CXX_EXAMPLES MyApp-qt)
+endif(LOG4CXX_QT_SUPPORT)
 if( WIN32 )
     include(win32_target_environment_path)
     get_target_environment_path(ESCAPED_PATH)
@@ -34,6 +37,10 @@ foreach(exampleName IN LISTS ALL_LOG4CXX_EXAMPLES)
     if(${exampleName} STREQUAL MyApp2)
         target_sources(${PROGRAM_NAME} PRIVATE com/foo/config2.cpp com/foo/bar.cpp)
     endif()
+    if(${exampleName} STREQUAL MyApp-qt)
+        target_sources(${PROGRAM_NAME} PRIVATE com/foo/config-qt.cpp com/foo/bar-qt.cpp)
+        target_link_libraries(${PROGRAM_NAME} PRIVATE log4cxx-qt)
+    endif()
     if(${exampleName} STREQUAL auto-configured)
         target_sources(${PROGRAM_NAME} PRIVATE com/foo/config3.cpp )
     endif()
diff --git a/src/examples/cpp/MyApp-qt.cpp b/src/examples/cpp/MyApp-qt.cpp
new file mode 100644
index 00000000..3d7ac609
--- /dev/null
+++ b/src/examples/cpp/MyApp-qt.cpp
@@ -0,0 +1,20 @@
+#include <QCoreApplication>
+#include "com/foo/config-qt.h"
+#include "com/foo/bar.h"
+
+int main(int argc, char **argv) {
+	int result = EXIT_SUCCESS;
+	QCoreApplication app(argc, argv);
+	com::foo::ConfigureLogging();
+	try {
+		auto logger = com::foo::getLogger("MyApp");
+		LOG4CXX_INFO(logger, "Entering application.");
+		com::foo::Bar bar;
+		bar.doIt();
+		LOG4CXX_INFO(logger, "Exiting application.");
+	}
+	catch(std::exception&) {
+		result = EXIT_FAILURE;
+	}
+	return result;
+}
diff --git a/src/examples/cpp/com/foo/bar-qt.cpp b/src/examples/cpp/com/foo/bar-qt.cpp
new file mode 100644
index 00000000..961513df
--- /dev/null
+++ b/src/examples/cpp/com/foo/bar-qt.cpp
@@ -0,0 +1,11 @@
+#include "com/foo/config-qt.h"
+#include "com/foo/bar.h"
+#include <log4cxx-qt/logger.h>
+
+using namespace com::foo;
+
+LoggerPtr Bar::m_logger(getLogger("com.foo.bar"));
+
+void Bar::doIt() {
+	LOG4CXX_DEBUG(m_logger, QString("Did it again!"));
+}
diff --git a/src/examples/cpp/com/foo/config-qt.cpp b/src/examples/cpp/com/foo/config-qt.cpp
new file mode 100644
index 00000000..64889087
--- /dev/null
+++ b/src/examples/cpp/com/foo/config-qt.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "config-qt.h"
+#include <log4cxx/logmanager.h>
+#include <log4cxx-qt/configuration.h>
+#include <log4cxx/helpers/loglog.h>
+#include <QCoreApplication>
+#include <QVector>
+#include <QFileInfo>
+#include <QDir>
+
+namespace com { namespace foo {
+
+// Provide the name of the configuration file to Log4cxx.
+// Reload the configuration on a QFileSystemWatcher::fileChanged event.
+void ConfigureLogging() {
+	static struct log4cxx_finalizer {
+		~log4cxx_finalizer() {
+			log4cxx::LogManager::shutdown();
+		}
+	} finaliser;
+	QFileInfo app{QCoreApplication::applicationFilePath()};
+	QString basename{app.baseName()};
+	QVector<QString> paths =
+		{ QString(".")
+		, app.absoluteDir().absolutePath()
+		};
+	QVector<QString> names =
+		{ QString(basename + ".xml")
+		, QString(basename + ".properties")
+		, QString("MyApp.properties")
+		, QString("log4cxx.xml")
+		, QString("log4cxx.properties")
+		, QString("log4j.xml")
+		, QString("log4j.properties")
+	};
+#if defined(_DEBUG)
+	log4cxx::helpers::LogLog::setInternalDebugging(true);
+#endif
+	log4cxx::qt::Configuration::configureFromFileAndWatch(paths, names);
+}
+
+// Retrieve the \c name logger pointer.
+auto getLogger(const QString& name) -> LoggerPtr {
+	return name.isEmpty()
+		? log4cxx::LogManager::getRootLogger()
+		: log4cxx::LogManager::getLogger(name.toStdString());
+}
+
+// Retrieve the \c name logger pointer.
+auto getLogger(const char* name) -> LoggerPtr {
+	return name
+		? log4cxx::LogManager::getLogger(name)
+		: log4cxx::LogManager::getRootLogger();
+}
+
+} } // namespace com::foo
diff --git a/src/examples/cpp/com/foo/config-qt.h b/src/examples/cpp/com/foo/config-qt.h
new file mode 100644
index 00000000..1faf35b0
--- /dev/null
+++ b/src/examples/cpp/com/foo/config-qt.h
@@ -0,0 +1,22 @@
+#ifndef COM_FOO_CONFIG_H_
+#define COM_FOO_CONFIG_H_
+#include <QString>
+#include <log4cxx/logger.h>
+
+/// Methods specific to foo.com
+namespace com { namespace foo {
+
+// Provide the name of the configuration file to Log4cxx.
+void ConfigureLogging();
+
+/// The logger pointer we use
+using LoggerPtr = log4cxx::LoggerPtr;
+
+/// Retrieve the \c name logger pointer.
+extern auto getLogger(const QString& name) -> LoggerPtr;
+
+/// Retrieve the \c name logger pointer.
+extern auto getLogger(const char* name = NULL) -> LoggerPtr;
+
+} } // namespace com::foo
+#endif // COM_FOO_CONFIG_H_
diff --git a/src/main/include/log4cxx-qt/logger.h b/src/main/include/log4cxx-qt/logger.h
new file mode 100644
index 00000000..e83d8db9
--- /dev/null
+++ b/src/main/include/log4cxx-qt/logger.h
@@ -0,0 +1,77 @@
+/*
+ * 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_QT_LOGGER_H
+#define _LOG4CXX_QT_LOGGER_H
+#include <log4cxx/logger.h>
+#include <QString>
+
+#if LOG4CXX_LOGCHAR_IS_UTF8
+#define LOG4CXX_DECODE_QSTRING(var, src) \
+	log4cxx::LogString var;                      \
+	log4cxx::helpers::Transcoder::decode((src).toStdString(), var)
+
+#define LOG4CXX_ENCODE_QSTRING(var, src) \
+	QString var = QString::fromStdString(log4cxx::helpers::Transcoder::encode(src))
+#endif // LOG4CXX_LOGCHAR_IS_UTF8
+
+#if LOG4CXX_LOGCHAR_IS_WCHAR
+#define LOG4CXX_DECODE_QSTRING(var, src) \
+	log4cxx::LogString var;                      \
+	log4cxx::helpers::Transcoder::decode((src).toStdWString(), var)
+
+#define LOG4CXX_ENCODE_QSTRING(var, src) \
+	QString var = QString::fromStdWString(log4cxx::helpers::Transcoder::encode(src))
+#endif // LOG4CXX_LOGCHAR_IS_WCHAR
+
+#if LOG4CXX_LOGCHAR_IS_UNICHAR
+#define LOG4CXX_DECODE_QSTRING(var, src) \
+	log4cxx::LogString var;                      \
+	log4cxx::helpers::Transcoder::decode((src).utf16(), var)
+
+#define LOG4CXX_ENCODE_QSTRING(var, src) \
+	QString var = QString::fromUtf16(log4cxx::helpers::Transcoder::encode(src.c_str()))
+#endif // LOG4CXX_LOGCHAR_IS_UNICHAR
+
+#if LOG4CXX_UNICHAR_API
+log4cxx::helpers::UniCharMessageBuffer& operator<<(log4cxx::helpers::UniCharMessageBuffer& mb, const QString& msg)
+{
+	return mb << msg.utf16();
+}
+
+log4cxx::helpers::UniCharMessageBuffer& operator<<(log4cxx::helpers::MessageBuffer& mb, const QString& msg)
+{
+	return mb << msg;
+}
+#else // !LOG4CXX_UNICHAR_API
+log4cxx::helpers::CharMessageBuffer& operator<<(log4cxx::helpers::CharMessageBuffer& mb, const QString& msg)
+{
+	LOG4CXX_DECODE_QSTRING(tmp, msg);
+	return mb << tmp;
+}
+
+#if LOG4CXX_WCHAR_T_API
+log4cxx::helpers::CharMessageBuffer& operator<<(log4cxx::helpers::MessageBuffer& mb, const QString& msg)
+{
+	LOG4CXX_DECODE_QSTRING(tmp, msg);
+	return mb << tmp;
+}
+#endif // LOG4CXX_WCHAR_T_API
+
+#endif // !LOG4CXX_UNICHAR_API
+
+#endif // _LOG4CXX_QT_LOGGER_H
diff --git a/src/site/markdown/development/build-cmake.md b/src/site/markdown/development/build-cmake.md
index 242430b9..e8601183 100644
--- a/src/site/markdown/development/build-cmake.md
+++ b/src/site/markdown/development/build-cmake.md
@@ -71,6 +71,7 @@ $ cmake --build buildtrees/Log4cxx --target install --config Release
 | -DAPR_STATIC=yes       | Link to the APR static library. By default, the Log4cxx shared library is linked to the APR shared library. If BUILD_SHARED_LIBS=off, the static APR library is always used.        |
 |-DLOG4CXX_TEST_PROGRAM_PATH=path| An extra path to prepend to the PATH for test programs.  Log4cxx requires zip, sed, and grep on the PATH in order for the tests to work properly.                          |
 | -DPREFER_BOOST=on      | Prefer the Boost version of dependent libraries over standard library |
+| -DLOG4CXX_QT_SUPPORT=ON | Enable QString API and log4cxx::qt namespace methods, requires QtCore, choice of ON, OFF (default).                   |
 
 ## A note on C++ version and Boost
 
diff --git a/src/site/markdown/qt-support.md b/src/site/markdown/qt-support.md
index a324a261..1b7b7cc9 100644
--- a/src/site/markdown/qt-support.md
+++ b/src/site/markdown/qt-support.md
@@ -26,8 +26,11 @@ may use the `QDebug` classes.  By default, this will print to stderr,
 thus bypassing the logger entirely.  In order to have these messages
 routed to Log4cxx, a message handler for Qt must be installed.
 
-Log4cxx provides a separate library, log4cxx-qt, which contains useful
-utilities for working with Qt.
+Log4cxx provides a cmake build option `LOG4CXX_QT_SUPPORT=ON`
+which adds allows you to use QString values in a logging request.
+Building with LOG4CXX_QT_SUPPORT=ON also adds the log4cxx::qt namespace methods
+for directing Qt messages to Log4cxx and
+using the Qt event loop to process a configuration file change.
 
 To install a message handler that will route the Qt logging messages
 through Log4cxx, include the messagehandler.h and call
@@ -43,3 +46,7 @@ qInstallMessageHandler( log4cxx::qt::messageHandler );
 
 Note that by default, this message handler also calls `abort` upon a
 fatal message.
+
+To use the Qt event loop to monitor the configuration file
+do your Log4cxx configuration as follows:
+\include com/foo/config-qt.cpp
\ No newline at end of file