Skip to content

Commit

Permalink
Place the blame where it lies
Browse files Browse the repository at this point in the history
When a QGIS crash is caused by a plugin, custom processing script,
or some command entered into the Python console, reflect this
in the crash report dialog.

E.g. if it was caused by a plugin, we state that the plugin caused
QGIS to crash and remove all the links to report the issue on the
QGIS issue tracker.
  • Loading branch information
nyalldawson committed Dec 7, 2021
1 parent 80c7778 commit e811a47
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/crashhandler/main.cpp
Expand Up @@ -94,6 +94,7 @@ int main( int argc, char *argv[] )

QgsCrashDialog dlg;
dlg.setReloadArgs( reloadArgs );
dlg.setPythonFault( report.pythonFault() );
dlg.setBugReport( report.toHtml() );
dlg.setModal( true );
dlg.show();
Expand Down
31 changes: 31 additions & 0 deletions src/crashhandler/qgscrashdialog.cpp
Expand Up @@ -56,6 +56,37 @@ void QgsCrashDialog::setReloadArgs( const QString &reloadArgs )
mReloadArgs = reloadArgs;
}

void QgsCrashDialog::setPythonFault( const QgsCrashReport::PythonFault &fault )
{
switch ( fault.cause )
{
case QgsCrashReport::LikelyPythonFaultCause::Unknown:
break;

case QgsCrashReport::LikelyPythonFaultCause::ProcessingScript:
mCrashHeaderMessage->setText( tr( "User script crashed QGIS" ).arg( fault.title ) );
mCrashMessage->setText( tr( "The user script <b>%1</b> caused QGIS to crash." ).arg( fault.filePath )
+ "<br><br>"
+ tr( "This is a third party custom script, and this issue should be reported to the author of that script." ) );
splitter->setSizes( { 0, splitter->width() } );
break;

case QgsCrashReport::LikelyPythonFaultCause::Plugin:
mCrashHeaderMessage->setText( tr( "Plugin %1 crashed QGIS" ).arg( fault.title ) );
mCrashMessage->setText( tr( "The plugin <b>%1</b> caused QGIS to crash." ).arg( fault.title )
+ "<br><br>"
+ tr( "Please report this issue to the author of that plugin." ) );
splitter->setSizes( { 0, splitter->width() } );
break;

case QgsCrashReport::LikelyPythonFaultCause::ConsoleCommand:
mCrashHeaderMessage->setText( tr( "Command crashed QGIS" ).arg( fault.title ) );
mCrashMessage->setText( tr( "A command entered in the Python console caused QGIS to crash." ) );
splitter->setSizes( { 0, splitter->width() } );
break;
}
}

void QgsCrashDialog::showReportWidget()
{
}
Expand Down
4 changes: 4 additions & 0 deletions src/crashhandler/qgscrashdialog.h
Expand Up @@ -22,6 +22,8 @@
#include <QPlainTextEdit>
#include <QPushButton>

#include "qgscrashreport.h"

#include "ui_qgscrashdialog.h"

/**
Expand All @@ -40,6 +42,8 @@ class QgsCrashDialog : public QDialog, private Ui::QgsCrashDialog
void setBugReport( const QString &reportData );
void setReloadArgs( const QString &reloadArgs );

void setPythonFault( const QgsCrashReport::PythonFault &fault );

private slots:
void showReportWidget();
void createBugReport();
Expand Down
49 changes: 48 additions & 1 deletion src/crashhandler/qgscrashreport.cpp
Expand Up @@ -73,7 +73,6 @@ const QString QgsCrashReport::toHtml() const
if ( pythonLog.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
QTextStream inputStream( &pythonLog );
QString line;
while ( !inputStream.atEnd() )
{
pythonStack.append( inputStream.readLine() );
Expand Down Expand Up @@ -260,6 +259,54 @@ QString QgsCrashReport::crashReportFolder()
QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
}

void QgsCrashReport::setPythonCrashLogFilePath( const QString &path )
{
mPythonCrashLogFilePath = path;

QFile pythonLog( mPythonCrashLogFilePath );
if ( pythonLog.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
QTextStream inputStream( &pythonLog );
QString line;
while ( !inputStream.atEnd() )
{
line = inputStream.readLine();

const thread_local QRegularExpression pythonTraceRx( QStringLiteral( "\\s*File\\s+\"(.*)\",\\s+line\\s+(\\d+)" ) );

const QRegularExpressionMatch fileLineMatch = pythonTraceRx.match( line );
if ( fileLineMatch.hasMatch() )
{
const QString pythonFilePath = fileLineMatch.captured( 1 );
if ( pythonFilePath.contains( QLatin1String( "profiles" ), Qt::CaseInsensitive )
&& pythonFilePath.contains( QLatin1String( "processing" ), Qt::CaseInsensitive )
&& pythonFilePath.contains( QLatin1String( "scripts" ), Qt::CaseInsensitive ) )
{
mPythonFault.cause = LikelyPythonFaultCause::ProcessingScript;
const QFileInfo fi( pythonFilePath );
mPythonFault.title = fi.fileName();
mPythonFault.filePath = pythonFilePath;
}
else if ( mPythonFault.cause == LikelyPythonFaultCause::Unknown && pythonFilePath.contains( QLatin1String( "console.py" ), Qt::CaseInsensitive ) )
{
mPythonFault.cause = LikelyPythonFaultCause::ConsoleCommand;
}
else if ( mPythonFault.cause == LikelyPythonFaultCause::Unknown )
{
const thread_local QRegularExpression pluginRx( QStringLiteral( "python[/\\\\]plugins[/\\\\](.*?)[/\\\\]" ) );
const QRegularExpressionMatch pluginNameMatch = pluginRx.match( pythonFilePath );
if ( pluginNameMatch.hasMatch() )
{
mPythonFault.cause = LikelyPythonFaultCause::Plugin;
mPythonFault.title = pluginNameMatch.captured( 1 );
mPythonFault.filePath = pythonFilePath;
}
}
}
}
}
}

QString QgsCrashReport::htmlToMarkdown( const QString &html )
{
// Any changes in this function must be copied to qgsstringutils.cpp too
Expand Down
20 changes: 19 additions & 1 deletion src/crashhandler/qgscrashreport.h
Expand Up @@ -46,6 +46,14 @@ class QgsCrashReport
};
Q_DECLARE_FLAGS( Flags, Flag )

enum class LikelyPythonFaultCause
{
Unknown,
ProcessingScript,
Plugin,
ConsoleCommand
};

/**
* Sets the stack trace for the crash report.
* \param value A string list for each line in the stack trace.
Expand Down Expand Up @@ -91,7 +99,16 @@ class QgsCrashReport
/**
* Sets the \a path to the associated Python crash log.
*/
void setPythonCrashLogFilePath( const QString &path ) { mPythonCrashLogFilePath = path; }
void setPythonCrashLogFilePath( const QString &path );

struct PythonFault
{
LikelyPythonFaultCause cause = LikelyPythonFaultCause::Unknown;
QString title;
QString filePath;
};

PythonFault pythonFault() const { return mPythonFault; }

/**
* convert htmlToMarkdown (copied from QgsStringUtils::htmlToMarkdown)
Expand All @@ -106,6 +123,7 @@ class QgsCrashReport
QStringList mVersionInfo;
QString mPythonCrashLogFilePath;

PythonFault mPythonFault;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsCrashReport::Flags )
Expand Down

0 comments on commit e811a47

Please sign in to comment.