Allow silencing failed-loading-resource warnings

When a referenced audio resource is not found in a DSL or XDXF
dictionary, GoldenDict searches for this resource by filename in all
other dictionaries within the current group. Naturally, the file is
absent from most dictionaries (see #970). Therefore a "Failed loading
resource" warning is printed for almost every dictionary in the current
group.

These warnings are by far the most frequent on my system. And in the
scenario described above there is nothing wrong at all. So the user may
want to silence these warnings to help notice less frequent and more
important messages. Implement categorized logging to enable this
customization. These warnings can now be disabled by adding the
following line in the [Rules] section of a logging configuration file
(e.g. ~/.config/QtProject/qtlogging.ini on GNU/Linux):
    goldendict.dictionary.resource.warning=false
See also https://doc.qt.io/qt-5/qloggingcategory.html#logging-rules
This commit is contained in:
Igor Kushnir 2022-11-25 18:17:03 +02:00 committed by Abs62
parent a61b203de7
commit 5034348c1a
10 changed files with 127 additions and 14 deletions

60
categorized_logging.hh Normal file
View file

@ -0,0 +1,60 @@
/* This file is (c) 2022 Igor Kushnir <igorkuo@gmail.com>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#ifndef CATEGORIZED_LOGGING_HH_INCLUDED
#define CATEGORIZED_LOGGING_HH_INCLUDED
// Lots of changes have been made to Qt's implementation of categorized logging in versions 5.3 and 5.4.
// __VA_ARGS__ was introduced in C++11.
#if QT_VERSION >= QT_VERSION_CHECK( 5, 4, 0 ) && __cplusplus >= 201103L
#include <QLoggingCategory>
#define GD_CATEGORIZED_LOGGING
#endif
#ifdef GD_CATEGORIZED_LOGGING
Q_DECLARE_LOGGING_CATEGORY( dictionaryResourceLc )
#if !defined(QT_NO_WARNING_OUTPUT)
/// Print a categorized warning message.
# define gdCWarning(category, ...) \
for (bool qt_category_enabled = category().isWarningEnabled(); qt_category_enabled; qt_category_enabled = false) \
gdCWarningImpl( category(), __VA_ARGS__ )
#else
# define qCWarning(category, ...) QT_NO_QDEBUG_MACRO()
#endif
#if !defined(QT_NO_DEBUG_OUTPUT)
/// Print a categorized debug message.
# define gdCDebug(category, ...) \
for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \
gdCDebugImpl( category(), __VA_ARGS__ )
#else
# define qCDebug(category, ...) QT_NO_QDEBUG_MACRO()
#endif
void gdCWarningImpl( QLoggingCategory const & category, char const * message, ... ) Q_ATTRIBUTE_FORMAT_PRINTF( 2, 3 );
void gdCDebugImpl( QLoggingCategory const & category, char const * message, ... ) Q_ATTRIBUTE_FORMAT_PRINTF( 2, 3 );
#else // GD_CATEGORIZED_LOGGING
// Compatibility shims.
enum GdLoggingCategory
{
dictionaryResourceLc,
};
/// Equivalent to gdWarning( @p message, ... )
void gdCWarning( GdLoggingCategory, char const * message, ... )
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
/// Equivalent to gdDebug( @p message, ... )
void gdCDebug( GdLoggingCategory, char const * message, ... )
#if defined(Q_CC_GNU) && !defined(__INSURE__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
#endif // GD_CATEGORIZED_LOGGING
#endif // CATEGORIZED_LOGGING_HH_INCLUDED

5
dsl.cc
View file

@ -17,6 +17,7 @@
#include "wstring_qt.hh" #include "wstring_qt.hh"
#include "zipfile.hh" #include "zipfile.hh"
#include "indexedzip.hh" #include "indexedzip.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "tiff.hh" #include "tiff.hh"
#include "fulltextsearch.hh" #include "fulltextsearch.hh"
@ -1992,8 +1993,8 @@ void DslResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "DSL: Failed loading resource \"%s\" for \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "DSL: Failed loading resource \"%s\" for \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }

View file

@ -15,6 +15,7 @@
#include "btreeidx.hh" #include "btreeidx.hh"
#include "folding.hh" #include "folding.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "fsencoding.hh" #include "fsencoding.hh"
#include "chunkedstorage.hh" #include "chunkedstorage.hh"
@ -777,8 +778,8 @@ void EpwingResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "Epwing: Failed loading resource \"%s\" for \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "Epwing: Failed loading resource \"%s\" for \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }

View file

@ -5,6 +5,7 @@
#include <QMutexLocker> #include <QMutexLocker>
#include <QTextCodec> #include <QTextCodec>
#include <QString> #include <QString>
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#define TO_LOG_MESSAGE( msg, ap ) QString().vsprintf( msg, ap ).toUtf8().constData() #define TO_LOG_MESSAGE( msg, ap ) QString().vsprintf( msg, ap ).toUtf8().constData()
@ -83,6 +84,50 @@ void gdDebug(const char *msg, ...)
va_end(ap); va_end(ap);
} }
#ifdef GD_CATEGORIZED_LOGGING
Q_LOGGING_CATEGORY( dictionaryResourceLc, "goldendict.dictionary.resource" )
#endif
#ifdef GD_CATEGORIZED_LOGGING
void gdCWarningImpl( QLoggingCategory const & category, char const * msg, ... )
#else
void gdCWarning( GdLoggingCategory, char const * msg, ... )
#endif
{
va_list ap;
va_start( ap, msg );
{
Utf8CodecForLocaleReplacer codecReplacer;
#ifdef GD_CATEGORIZED_LOGGING
QMessageLogger( QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category.categoryName() )
.warning( "%s", TO_LOG_MESSAGE( msg, ap ) );
#else
qWarning( "%s", TO_LOG_MESSAGE( msg, ap ) );
#endif
}
va_end( ap );
}
#ifdef GD_CATEGORIZED_LOGGING
void gdCDebugImpl( QLoggingCategory const & category, char const * msg, ... )
#else
void gdCDebug( GdLoggingCategory, char const * msg, ... )
#endif
{
va_list ap;
va_start( ap, msg );
{
Utf8CodecForLocaleReplacer codecReplacer;
#ifdef GD_CATEGORIZED_LOGGING
QMessageLogger( QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category.categoryName() )
.debug( "%s", TO_LOG_MESSAGE( msg, ap ) );
#else
qDebug( "%s", TO_LOG_MESSAGE( msg, ap ) );
#endif
}
va_end( ap );
}
QTextCodec * gdCodecForLocale() QTextCodec * gdCodecForLocale()
{ {
return Utf8CodecForLocaleReplacer::originalCodecForLocale(); return Utf8CodecForLocaleReplacer::originalCodecForLocale();

5
gls.cc
View file

@ -8,6 +8,7 @@
#include "ufile.hh" #include "ufile.hh"
#include "btreeidx.hh" #include "btreeidx.hh"
#include "folding.hh" #include "folding.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "utf8.hh" #include "utf8.hh"
#include "wstring_qt.hh" #include "wstring_qt.hh"
@ -1541,8 +1542,8 @@ void GlsResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "GLS: Failed loading resource \"%s\" for \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "GLS: Failed loading resource \"%s\" for \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }

View file

@ -367,6 +367,7 @@ HEADERS += folding.hh \
articleinspector.hh \ articleinspector.hh \
delegate.hh \ delegate.hh \
zim.hh \ zim.hh \
categorized_logging.hh \
gddebug.hh \ gddebug.hh \
qt4x5.hh \ qt4x5.hh \
gestures.hh \ gestures.hh \

View file

@ -7,6 +7,7 @@
#include "btreeidx.hh" #include "btreeidx.hh"
#include "fsencoding.hh" #include "fsencoding.hh"
#include "folding.hh" #include "folding.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "utf8.hh" #include "utf8.hh"
#include "decompress.hh" #include "decompress.hh"
@ -1679,8 +1680,8 @@ void SlobResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "SLOB: Failed loading resource \"%s\" from \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "SLOB: Failed loading resource \"%s\" from \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }

View file

@ -10,6 +10,7 @@
#include "xdxf2html.hh" #include "xdxf2html.hh"
#include "htmlescape.hh" #include "htmlescape.hh"
#include "langcoder.hh" #include "langcoder.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "fsencoding.hh" #include "fsencoding.hh"
#include "filetype.hh" #include "filetype.hh"
@ -1912,8 +1913,8 @@ void StardictResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "Stardict: Failed loading resource \"%s\" for \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "Stardict: Failed loading resource \"%s\" for \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }
catch( ... ) catch( ... )

View file

@ -16,6 +16,7 @@
#include <list> #include <list>
#include <wctype.h> #include <wctype.h>
#include <stdlib.h> #include <stdlib.h>
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "wstring_qt.hh" #include "wstring_qt.hh"
#include "xdxf2html.hh" #include "xdxf2html.hh"
@ -1133,8 +1134,8 @@ void XdxfResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "XDXF: Failed loading resource \"%s\" for \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "XDXF: Failed loading resource \"%s\" for \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }

5
zim.cc
View file

@ -7,6 +7,7 @@
#include "btreeidx.hh" #include "btreeidx.hh"
#include "fsencoding.hh" #include "fsencoding.hh"
#include "folding.hh" #include "folding.hh"
#include "categorized_logging.hh"
#include "gddebug.hh" #include "gddebug.hh"
#include "utf8.hh" #include "utf8.hh"
#include "decompress.hh" #include "decompress.hh"
@ -1634,8 +1635,8 @@ void ZimResourceRequest::run()
} }
catch( std::exception &ex ) catch( std::exception &ex )
{ {
gdWarning( "ZIM: Failed loading resource \"%s\" from \"%s\", reason: %s\n", gdCWarning( dictionaryResourceLc, "ZIM: Failed loading resource \"%s\" from \"%s\", reason: %s\n",
resourceName.c_str(), dict.getName().c_str(), ex.what() ); resourceName.c_str(), dict.getName().c_str(), ex.what() );
// Resource not loaded -- we don't set the hasAnyData flag then // Resource not loaded -- we don't set the hasAnyData flag then
} }