This is an automated email from the ASF dual-hosted git repository.
swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/master by this push:
new c1b4b97e Ensure a Qt fatal message is flushed when using
buffered/async output (#571)
c1b4b97e is described below
commit c1b4b97e29365202b8be29bde6cc48efd820459e
Author: Stephen Webb <[email protected]>
AuthorDate: Fri Dec 26 11:22:17 2025 +1100
Ensure a Qt fatal message is flushed when using buffered/async output (#571)
* Use qt::messageHandler() in web-site examples
* Improve the web-site properties file examples
* Avoid double character conversion when LOG4CXX_CHAR=wchar_t
---
src/examples/cpp/MyApp.properties | 11 +++++-----
src/examples/cpp/com/foo/config-qt.cpp | 23 +++++++++-----------
src/main/cpp-qt/configuration.cpp | 39 ++++++++++++++++++----------------
src/main/cpp-qt/messagehandler.cpp | 30 +++++++++++++++-----------
src/site/markdown/example-programs.md | 28 +++++++++++++++---------
5 files changed, 73 insertions(+), 58 deletions(-)
diff --git a/src/examples/cpp/MyApp.properties
b/src/examples/cpp/MyApp.properties
index da4840cd..dd8ab234 100644
--- a/src/examples/cpp/MyApp.properties
+++ b/src/examples/cpp/MyApp.properties
@@ -3,12 +3,12 @@ log4j.rootLogger=DEBUG, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-
-# Pattern to output the caller's file name and line number.
-log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%f:%L) - %m%n
+# Color the logging level and message and prefix with the logging request file
name, line number and thread.
+log4j.appender.stdout.layout.ConversionPattern=%f:%L [%t] - %Y%p %m%y%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
-log4j.appender.R.File=example.log
+# Store the log file in the same directory as the program
+log4j.appender.R.File=${PROGRAM_FILE_PATH.PARENT_PATH}/${PROGRAM_FILE_PATH.STEM}.log
# Move example.log to example.log.1 at 100 KB in size
log4j.appender.R.MaxFileSize=100KB
@@ -16,4 +16,5 @@ log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
-log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
+# Output the date, thread, logging level, logger name and message
+log4j.appender.R.layout.ConversionPattern=%d %t %-5p %c - %m%n
diff --git a/src/examples/cpp/com/foo/config-qt.cpp
b/src/examples/cpp/com/foo/config-qt.cpp
index 4a1dfcc1..afa50149 100644
--- a/src/examples/cpp/com/foo/config-qt.cpp
+++ b/src/examples/cpp/com/foo/config-qt.cpp
@@ -18,23 +18,27 @@
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/logmanager.h>
#include <log4cxx-qt/configuration.h>
-#include <log4cxx/helpers/loglog.h>
+#include <log4cxx-qt/messagehandler.h>
#include <QCoreApplication>
-#include <QVector>
#include <QFileInfo>
#include <QDir>
namespace com { namespace foo {
+using namespace log4cxx;
+
// Provide the name of the configuration file to Log4cxx.
// Reload the configuration on a QFileSystemWatcher::fileChanged event.
void ConfigureLogging() {
- using namespace log4cxx;
- static struct log4cxx_finalizer {
- ~log4cxx_finalizer() {
+ static struct log4cxx_initializer {
+ log4cxx_initializer() {
+ qInstallMessageHandler(qt::messageHandler);
+ }
+ ~log4cxx_initializer() {
LogManager::shutdown();
}
- } finaliser;
+ } initialiser;
+
QFileInfo app{QCoreApplication::applicationFilePath()};
QString basename{app.baseName()};
QVector<QString> paths =
@@ -47,12 +51,7 @@ void ConfigureLogging() {
, QString("MyApp.properties")
, QString("log4cxx.xml")
, QString("log4cxx.properties")
- , QString("log4j.xml")
- , QString("log4j.properties")
};
-#if defined(_DEBUG)
- helpers::LogLog::setInternalDebugging(true);
-#endif
auto status = spi::ConfigurationStatus::NotConfigured;
auto selectedPath = QString();
std::tie(status, selectedPath) =
qt::Configuration::configureFromFileAndWatch(paths, names);
@@ -62,7 +61,6 @@ void ConfigureLogging() {
// Retrieve the \c name logger pointer.
auto getLogger(const QString& name) -> LoggerPtr {
- using namespace log4cxx;
return name.isEmpty()
? LogManager::getRootLogger()
: LogManager::getLogger(name.toStdString());
@@ -70,7 +68,6 @@ auto getLogger(const QString& name) -> LoggerPtr {
// Retrieve the \c name logger pointer.
auto getLogger(const char* name) -> LoggerPtr {
- using namespace log4cxx;
return name
? LogManager::getLogger(name)
: LogManager::getRootLogger();
diff --git a/src/main/cpp-qt/configuration.cpp
b/src/main/cpp-qt/configuration.cpp
index 10f8de3d..29ab7fe9 100644
--- a/src/main/cpp-qt/configuration.cpp
+++ b/src/main/cpp-qt/configuration.cpp
@@ -30,7 +30,7 @@ namespace LOG4CXX_NS
{
namespace qt
{
-using LOG4CXX_NS::helpers::LogLog;
+using helpers::LogLog;
static std::unique_ptr<QFileSystemWatcher> watcher;
static QString configFilename;
@@ -40,7 +40,8 @@ static void loadXMLFile(const QString& path){
if(!fi.exists()){
return;
}
- LOG4CXX_NS::xml::DOMConfigurator::configure(path.toStdString());
+ LOG4CXX_DECODE_QSTRING(lsPath, path);
+ xml::DOMConfigurator::configure(lsPath);
}
static void loadPropertiesFile(const QString& path){
@@ -48,7 +49,8 @@ static void loadPropertiesFile(const QString& path){
if(!fi.exists()){
return;
}
- LOG4CXX_NS::PropertyConfigurator::configure(path.toStdString());
+ LOG4CXX_DECODE_QSTRING(lsPath, path);
+ PropertyConfigurator::configure(lsPath);
}
static void dirChanged(const QString&){
@@ -68,18 +70,19 @@ static void dirChanged(const QString&){
Configuration::Configuration(){}
-LOG4CXX_NS::spi::ConfigurationStatus Configuration::tryLoadFile(const QString&
filename){
- LOG4CXX_NS::spi::ConfigurationStatus stat
=LOG4CXX_NS::spi::ConfigurationStatus::NotConfigured;
- bool isXML = false;
+spi::ConfigurationStatus Configuration::tryLoadFile(const QString& filename){
+ auto stat = spi:: ConfigurationStatus::NotConfigured;
+ auto isXML = false;
+ LOG4CXX_DECODE_QSTRING(lsFilename, filename);
if(filename.endsWith(".xml")){
- stat =
LOG4CXX_NS::xml::DOMConfigurator::configure(filename.toStdString());
+ stat = xml::DOMConfigurator::configure(lsFilename);
isXML = true;
}else if(filename.endsWith(".properties")){
- stat =
LOG4CXX_NS::PropertyConfigurator::configure(filename.toStdString());
+ stat = PropertyConfigurator::configure(lsFilename);
}
- if( stat == LOG4CXX_NS::spi::ConfigurationStatus::Configured ){
+ if( stat == spi::ConfigurationStatus::Configured ){
watcher = std::make_unique<QFileSystemWatcher>();
configFilename = filename;
QFileInfo fi(filename);
@@ -100,35 +103,35 @@ LOG4CXX_NS::spi::ConfigurationStatus
Configuration::tryLoadFile(const QString& f
return stat;
}
-std::tuple<LOG4CXX_NS::spi::ConfigurationStatus,QString>
+std::tuple<spi::ConfigurationStatus,QString>
Configuration::configureFromFileAndWatch(const QVector<QString>& directories,
const QVector<QString>& filenames){
for( QString dir : directories ){
for( QString fname : filenames ){
- QString canidate_str = dir + "/" + fname;
- QFile candidate(canidate_str);
+ QString candidate_str = dir + "/" + fname;
+ QFile candidate(candidate_str);
if (LogLog::isDebugEnabled())
{
- LOG4CXX_DECODE_QSTRING(msg, "Checking file " +
canidate_str);
+ LOG4CXX_DECODE_QSTRING(msg, "Checking file " +
candidate_str);
LogLog::debug(msg);
}
if (candidate.exists())
{
- LOG4CXX_NS::spi::ConfigurationStatus
configStatus = tryLoadFile(canidate_str);
- if( configStatus ==
LOG4CXX_NS::spi::ConfigurationStatus::Configured ){
- return {configStatus, canidate_str};
+ auto configStatus = tryLoadFile(candidate_str);
+ if( configStatus ==
spi::ConfigurationStatus::Configured ){
+ return {configStatus, candidate_str};
}
if (LogLog::isDebugEnabled())
{
- LOG4CXX_DECODE_QSTRING(failmsg, "Unable
to load " + canidate_str + ": trying next");
+ LOG4CXX_DECODE_QSTRING(failmsg, "Unable
to load " + candidate_str + ": trying next");
LogLog::debug(failmsg);
}
}
}
}
- return {LOG4CXX_NS::spi::ConfigurationStatus::NotConfigured, QString()};
+ return {spi::ConfigurationStatus::NotConfigured, QString()};
}
} //namespace helpers
diff --git a/src/main/cpp-qt/messagehandler.cpp
b/src/main/cpp-qt/messagehandler.cpp
index 67580935..29fd8ebc 100644
--- a/src/main/cpp-qt/messagehandler.cpp
+++ b/src/main/cpp-qt/messagehandler.cpp
@@ -15,7 +15,9 @@
* limitations under the License.
*/
#include <log4cxx-qt/messagehandler.h>
+#include <log4cxx-qt/transcoder.h>
#include <log4cxx/logger.h>
+#include <log4cxx/logmanager.h>
#include <log4cxx/spi/location/locationinfo.h>
namespace LOG4CXX_NS {
@@ -23,34 +25,38 @@ namespace qt {
void messageHandler(QtMsgType type, const QMessageLogContext& context, const
QString& message )
{
- LOG4CXX_NS::LoggerPtr qtLogger = LOG4CXX_NS::Logger::getLogger(
context.category );
- LOG4CXX_NS::spi::LocationInfo location( context.file,
-
LOG4CXX_NS::spi::LocationInfo::calcShortFileName(context.file),
-
context.function,
-
context.line );
-
+ spi::LocationInfo location
+ ( context.file
+ , spi::LocationInfo::calcShortFileName(context.file)
+ , context.function
+ , context.line
+ );
+ LOG4CXX_DECODE_QSTRING(lsMsg, message);
+ auto qtLogger = Logger::getLogger( context.category );
switch ( type )
{
case QtMsgType::QtDebugMsg:
- qtLogger->debug( message.toStdString(), location );
+ qtLogger->debug(lsMsg, location);
break;
case QtMsgType::QtWarningMsg:
- qtLogger->warn( message.toStdString(), location );
+ default:
+ qtLogger->warn(lsMsg, location);
break;
-#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
case QtMsgType::QtInfoMsg:
- qtLogger->info( message.toStdString(), location );
+ qtLogger->info(lsMsg, location);
break;
#endif
case QtMsgType::QtCriticalMsg:
- qtLogger->error( message.toStdString(), location );
+ qtLogger->error(lsMsg, location);
break;
case QtMsgType::QtFatalMsg:
- qtLogger->fatal( message.toStdString(), location );
+ qtLogger->fatal(lsMsg, location);
+ LogManager::shutdown();
std::abort();
}
}
diff --git a/src/site/markdown/example-programs.md
b/src/site/markdown/example-programs.md
index 35ae215e..ea17b662 100644
--- a/src/site/markdown/example-programs.md
+++ b/src/site/markdown/example-programs.md
@@ -145,10 +145,10 @@ configuration file shows one possible way of achieving
this.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
- # Print the date in ISO 8601 format
+ # Include the date (in ISO 8601 format), the thread, logging level, logger
name and message
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
- # Print only messages of level WARN or above in the package com.foo.
+ # Output only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN
~~~
@@ -165,16 +165,16 @@ file. The log statement from the *Bar::doIt* method has
the level *DEBUG*,
lower than the logger level WARN. Consequently, *doIt()* method's log
request is suppressed.
-Here is another configuration file that uses multiple appenders.
+Here is a *MyApp.properties* configuration file that uses multiple appenders.
\include MyApp.properties
-Calling the enhanced MyApp with the this configuration file will output
+Using the enhanced \ref MyApp.properties configuration file will output
the following on the console.
~~~
- INFO [12345] (MyApp.cpp:8) - Entering application.
- DEBUG [12345] (bar.cpp:8) - Did it again!
- INFO [12345] (MyApp.cpp:11) - Exiting application.
+ MyApp2.cpp:8 [0x00012345] - INFO Entering application.
+ bar.cpp:8 [0x00012345] - DEBUG Did it again!
+ MyApp2.cpp:11 [0x00012345] - INFO Exiting application.
~~~
In addition, as the root logger has been allocated a second appender,
@@ -197,10 +197,18 @@ This header file is for encapsulating Log4cxx
configuration.
\example com/foo/config1.cpp
This file is a simplified example of encapsulated Log4cxx configuration.
-\example com/foo/config3.cpp
-This file is an example of how to use the current module name to select the
Log4cxx configuration file.
+\example MyApp.properties
+This is a configuration file that uses multiple appenders.
+
+\example MyApp2.cpp
+This example can be built with \ref com/foo/config2.cpp or \ref
com/foo/config4.cpp
+to configure Log4cxx on the first call the com::foo::getLogger.
+
+\example com/foo/config2.cpp
+This file is a simplified example of encapsulated Log4cxx configuration.
\example com/foo/config4.cpp
-This file is a simpler example of how to use the current module name to select
the Log4cxx configuration file.
+This file is a example of how provide application specific values for use in
the configuration file
+and to use the current module name to select the Log4cxx configuration file.
[Configuration Samples]:configuration-files.html#configuration-samples