Skip to content

Commit c579679

Browse files
Capture c++ stack traces from core dump files on linux (#38600)
* add pystack to workbench and developer environments * Turn on core dumps on linux for the inner workbench process Has to switch from multiprocessing to subprocess in order to do this (needed the preexec option). Through some testing, this should preserve the desired spawn behaviour. A new module 'workbench_process.py' has been created to use with subprocess.run (can't pass it a function) * add module to get the compressed output from pystack on the latest worbench core file * add tests for new run pystack module * add cpp traces to the report sender * base64 encode data to store as a string * show pystack output in the show more details window * add release note * update existing tests * fix pystack test * add support for lz4 compressed core files, such as those on idaaas * only import lz4 if on linux * return Path type as intended * use process id to identify core dump file * move release note to 6.13 * pass missing parameter to errorreporter constructor * only launch with preexec_func when not on windows to avoid crash * add property to user properties default file * Update comment in run_pystack --------- Co-authored-by: thomashampson <thomas.hampson@stfc.ac.uk>
1 parent cc099f1 commit c579679

File tree

19 files changed

+571
-233
lines changed

19 files changed

+571
-233
lines changed

Framework/Kernel/inc/MantidKernel/ErrorReporter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class MANTID_KERNEL_DLL ErrorReporter {
3030
const std::string &textBox);
3131
/// Constructor
3232
ErrorReporter(std::string application, Types::Core::time_duration startTime, std::string exitCode, bool share,
33-
std::string name, std::string email, std::string textBox, std::string stacktrace);
33+
std::string name, std::string email, std::string textBox, std::string stacktrace,
34+
std::string cppTraces);
3435
/// Sends an error report
3536
Kernel::InternetHelper::HTTPStatus sendErrorReport();
3637
/// Generates an error string in json format
@@ -50,6 +51,7 @@ class MANTID_KERNEL_DLL ErrorReporter {
5051
const std::string m_textbox;
5152
std::string m_url;
5253
const std::string m_stacktrace;
54+
const std::string m_cppTraces;
5355
};
5456

5557
} // namespace Kernel

Framework/Kernel/src/ErrorReporter.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,21 @@ Logger g_log("ErrorReporter");
3333
*/
3434
ErrorReporter::ErrorReporter(const std::string &application, const Types::Core::time_duration &upTime,
3535
const std::string &exitCode, const bool share)
36-
: ErrorReporter(application, upTime, exitCode, share, "", "", "", "") {}
36+
: ErrorReporter(application, upTime, exitCode, share, "", "", "", "", "") {}
3737

3838
/** Constructor
3939
*/
4040
ErrorReporter::ErrorReporter(const std::string &application, const Types::Core::time_duration &upTime,
4141
const std::string &exitCode, const bool share, const std::string &name,
4242
const std::string &email, const std::string &textBox)
43-
: ErrorReporter(application, upTime, exitCode, share, name, email, textBox, "") {}
43+
: ErrorReporter(application, upTime, exitCode, share, name, email, textBox, "", "") {}
4444

4545
ErrorReporter::ErrorReporter(std::string application, Types::Core::time_duration upTime, std::string exitCode,
4646
const bool share, std::string name, std::string email, std::string textBox,
47-
std::string traceback)
47+
std::string traceback, std::string cppTraces)
4848
: m_application(std::move(application)), m_exitCode(std::move(exitCode)), m_upTime(std::move(upTime)),
4949
m_share(share), m_name(std::move(name)), m_email(std::move(email)), m_textbox(std::move(textBox)),
50-
m_stacktrace(std::move(traceback)) {
50+
m_stacktrace(std::move(traceback)), m_cppTraces(std::move(cppTraces)) {
5151
auto url = Mantid::Kernel::ConfigService::Instance().getValue<std::string>("errorreports.rooturl");
5252
if (!url.has_value()) {
5353
g_log.debug() << "Failed to load error report url\n";
@@ -113,11 +113,13 @@ std::string ErrorReporter::generateErrorMessage() const {
113113
message["email"] = m_email;
114114
message["name"] = m_name;
115115
message["stacktrace"] = m_stacktrace;
116+
message["cppCompressedTraces"] = m_cppTraces;
116117
} else {
117118
message["email"] = "";
118119
message["name"] = "";
119120
message["textBox"] = m_textbox;
120121
message["stacktrace"] = "";
122+
message["cppCompressedTraces"] = "";
121123
}
122124

123125
return Mantid::JsonHelpers::jsonToString(message);

Framework/Kernel/test/ErrorReporterTest.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ErrorReporterTest : public CxxTest::TestSuite {
6666
const std::string appName = "My testing application name";
6767
const Mantid::Types::Core::time_duration upTime(5, 0, 7, 0);
6868
const std::string stackTrace = "File \" C :\\file\\path\\file.py\", line 194, in broken_function";
69-
TestableErrorReporter reporter(appName, upTime, "0", true, "name", "email", "textBox", stackTrace);
69+
TestableErrorReporter reporter(appName, upTime, "0", true, "name", "email", "textBox", stackTrace, "");
7070
const std::string message = reporter.generateErrorMessage();
7171

7272
::Json::Value root;
@@ -102,7 +102,7 @@ class ErrorReporterTest : public CxxTest::TestSuite {
102102
void test_errorMessageWithShareAndRecoveryFileHash() {
103103
const std::string name = "My testing application name";
104104
const Mantid::Types::Core::time_duration upTime(5, 0, 7, 0);
105-
TestableErrorReporter errorService(name, upTime, "0", true, "name", "email", "textBox", "stacktrace");
105+
TestableErrorReporter errorService(name, upTime, "0", true, "name", "email", "textBox", "stacktrace", "cppTraces");
106106
const std::string message = errorService.generateErrorMessage();
107107

108108
::Json::Value root;
@@ -111,7 +111,7 @@ class ErrorReporterTest : public CxxTest::TestSuite {
111111
const std::vector<std::string> expectedMembers{
112112
"ParaView", "application", "host", "mantidSha1", "mantidVersion", "osArch",
113113
"osName", "osReadable", "osVersion", "uid", "facility", "upTime",
114-
"exitCode", "textBox", "name", "email", "stacktrace"};
114+
"exitCode", "textBox", "name", "email", "stacktrace", "cppCompressedTraces"};
115115
for (auto expectedMember : expectedMembers) {
116116
TSM_ASSERT(expectedMember + " not found",
117117
std::find(members.begin(), members.end(), expectedMember) != members.end());
@@ -124,12 +124,13 @@ class ErrorReporterTest : public CxxTest::TestSuite {
124124
TS_ASSERT_EQUALS(root["email"].asString(), "email");
125125
TS_ASSERT_EQUALS(root["textBox"].asString(), "textBox");
126126
TS_ASSERT_EQUALS(root["stacktrace"].asString(), "stacktrace");
127+
TS_ASSERT_EQUALS(root["cppCompressedTraces"].asString(), "cppTraces");
127128
}
128129

129130
void test_errorMessageWithNoShareAndRecoveryFileHash() {
130131
const std::string name = "My testing application name";
131132
const Mantid::Types::Core::time_duration upTime(5, 0, 7, 0);
132-
TestableErrorReporter errorService(name, upTime, "0", false, "name", "email", "textBox", "stacktrace");
133+
TestableErrorReporter errorService(name, upTime, "0", false, "name", "email", "textBox", "stacktrace", "cppTraces");
133134
const std::string message = errorService.generateErrorMessage();
134135

135136
::Json::Value root;
@@ -138,7 +139,8 @@ class ErrorReporterTest : public CxxTest::TestSuite {
138139
const std::vector<std::string> expectedMembers{
139140
"ParaView", "application", "host", "mantidSha1", "mantidVersion", "osArch",
140141
"osName", "osReadable", "osVersion", "uid", "facility", "upTime",
141-
"exitCode", "textBox", "name", "email", "stacktrace"};
142+
"exitCode", "textBox", "name", "email", "stacktrace", "upTime",
143+
"exitCode", "textBox", "name", "email", "stacktrace", "cppCompressedTraces"};
142144
for (auto expectedMember : expectedMembers) {
143145
TSM_ASSERT(expectedMember + " not found",
144146
std::find(members.begin(), members.end(), expectedMember) != members.end());
@@ -151,5 +153,6 @@ class ErrorReporterTest : public CxxTest::TestSuite {
151153
TS_ASSERT_EQUALS(root["email"].asString(), "");
152154
TS_ASSERT_EQUALS(root["textBox"].asString(), "textBox");
153155
TS_ASSERT_EQUALS(root["stacktrace"].asString(), "");
156+
TS_ASSERT_EQUALS(root["cppCompressedTraces"].asString(), "");
154157
}
155158
};

Framework/Properties/Mantid.properties.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ usagereports.enabled = @ENABLE_USAGE_REPORTS@
5959
errorreports.rooturl = https://errorreports.mantidproject.org
6060
usagereports.rooturl = https://reports.mantidproject.org
6161

62+
# Location of core dump files (linux only feature)
63+
errorreports.core_dumps =
64+
6265
# Where to load Grouping files (that are shipped with Mantid) from
6366
groupingFiles.directory = @MANTID_ROOT@/instrument/Grouping
6467

Framework/PythonInterface/mantid/kernel/src/Exports/ErrorReporter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void export_ErrorReporter() {
1919
std::string>())
2020

2121
.def(init<std::string, Mantid::Types::Core::time_duration, std::string, bool, std::string, std::string,
22-
std::string, std::string>())
22+
std::string, std::string, std::string>())
2323

2424
.def("sendErrorReport", &ErrorReporter::sendErrorReport, arg("self"), "Sends an error report")
2525

Framework/PythonInterface/test/python/mantid/kernel/ConfigServiceTest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ def test_properties_documented(self):
157157
"UpdateInstrumentDefinitions.URL", # shouldn't be changed by users
158158
"docs.html.root", # shouldn't be changed by users
159159
"errorreports.rooturl", # shouldn't be changed by users
160+
"errorreports.core_dumps",
160161
"usagereports.rooturl", # shouldn't be changed by users
161162
"workspace.sendto.SansView.arguments",
162163
"workspace.sendto.SansView.saveusing", # related to SASview in menu

conda/recipes/mantid-developer/meta.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ requirements:
2525
- libboost-python-devel {{ libboost_python_devel }}
2626
- libopenblas {{ libopenblas }} # [osx or linux]
2727
- librdkafka {{ librdkafka }}
28+
- lz4 # [linux]
2829
- matplotlib {{ matplotlib }}
2930
- muparser {{ muparser }}
3031
- ninja {{ ninja }}
@@ -37,6 +38,7 @@ requirements:
3738
- pydantic {{ pydantic }}
3839
- pyqt {{ pyqt }}
3940
- pyqtwebengine
41+
- pystack # [linux]
4042
- python-dateutil {{ python_dateutil }}
4143
- python {{ python }}
4244
- python.app # [osx]

conda/recipes/mantidworkbench/meta.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ requirements:
3939
- versioningit {{ versioningit }}
4040
run:
4141
- ipykernel
42+
- lz4 # [linux]
4243
- psutil {{ psutil }}
4344
- {{ pin_compatible("python", max_pin="x.x") }}
4445
- matplotlib {{ matplotlib }}
4546
- mslice {{ mslice }}
4647
- python.app # [osx]
48+
- pystack # [linux]
4749
- qtconsole {{ qtconsole }}
4850
- {{ pin_compatible("setuptools", max_pin="x.x") }}
4951
{% if environ.get('INCLUDE_MANTIDDOCS', 'True') != 'False' %}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Added property ``errorreports.core_dumps``. Linux users can set this to the directory on their system where core dump files are put after a crash (e.g ``errorreports.core_dumps=/var/lib/apport/coredump``).
2+
Workbench will then be able to use this property to extract useful information from the core dump file created after a crash and give that to the error reporting service.
3+
This will help us to diagnose some problems where previously no stacktrace was available after a crash. On Linux, core dumps are now always turned on for the workbench process.

0 commit comments

Comments
 (0)