Skip to content

Commit da8b054

Browse files
authored
CBL-8057: Better stack trace logging and crash handling (#2490)
It's almost impossible to have a release build that properly prints out stack traces at runtime with frame names and such. This adds the relative address of the frame to the stack trace log so that it can be looked up after the fact, and also adds a new crash log that prints a stack trace to a special file in the event of a crash. * No more need to explicitly enable fatal exception handling It is on by default, and the API that used to turn it on was removed * Fix tests to account for the presence of one more file in the logging folder * As a side effect of updating Fleece this also fixes CBL-8363
1 parent ed06469 commit da8b054

4 files changed

Lines changed: 30 additions & 12 deletions

File tree

C/c4Log.cc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,7 @@ void c4log_warnOnErrors(bool warn) noexcept { error::sWarnOnError = warn; }
329329
bool c4log_getWarnOnErrors() noexcept { return error::sWarnOnError; }
330330

331331
void c4log_enableFatalExceptionBacktrace() C4API {
332-
fleece::Backtrace::installTerminateHandler([](const string& backtrace) {
333-
c4log(kC4DefaultLog, kC4LogError,
334-
"FATAL ERROR (backtrace follows)\n"
335-
"********************\n"
336-
"%s\n"
337-
"******************** NOW TERMINATING",
338-
backtrace.c_str());
339-
});
332+
c4log(kC4DefaultLog, kC4LogWarning, "c4log_enableFatalExceptionBacktrace is a no-op now");
340333
}
341334

342335
#pragma mark - WRITING LOG MESSAGES:

LiteCore/Logging/LogFiles.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
//
1212

1313
#include "LogFiles.hh"
14+
15+
#include "Backtrace.hh"
1416
#include "c4ExceptionUtils.hh"
1517
#include "Error.hh"
1618
#include "FilePath.hh"
@@ -159,6 +161,10 @@ namespace litecore {
159161
// Initialize LogFile objects before opening them:
160162
for ( int i = 0; i < kNumLogLevels; i++ ) _files[i] = make_unique<LogFile>(LogLevel(i), _options);
161163
for ( int i = 0; i < kNumLogLevels; i++ ) _files[i]->open();
164+
165+
// The expectation here is that you will only create one active LogFiles at once
166+
auto crash_path = options.directory + FilePath::kSeparator + "cbl_crash.log";
167+
BacktraceSignalHandler::setLogPath(crash_path.c_str());
162168
}
163169

164170
LogFiles::~LogFiles() { close(); }

LiteCore/tests/LogEncoderTest.cc

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
#include <fstream>
2727
#include <thread>
2828

29+
#ifndef _MSC_VER
30+
# include <signal.h>
31+
# include <unistd.h>
32+
#endif
33+
2934
using namespace std;
3035

3136
// These formats are used in the decoded log files. They are UTC times.
@@ -290,9 +295,9 @@ TEST_CASE_METHOD(LogFileTest, "Logging rollover", "[Log]") {
290295
});
291296

292297
// infoFiles.size(), log files at the Info level
293-
// 4 additional log files, 1 for each level besides Info.
298+
// 5 additional log files, 1 for each level besides Info plus the crash log.
294299
// 2 arbitrary files, "intheway" and "acbd", in particular
295-
REQUIRE(totalCount == infoFiles.size() + 6);
300+
REQUIRE(totalCount == infoFiles.size() + 7);
296301
// The rollover logic will cut a new file as its size reaches maxSize as specified in
297302
// the LogFiles::Options. However, we check the size by checking the number of bytes already
298303
// flushed to the fstream. Therefore, the number of files that have actually been cut
@@ -519,7 +524,7 @@ TEST_CASE_METHOD(LogFileTest, "c4log writeToBinary", "[Log]") {
519524
CHECK(binaryFilePath == path);
520525
int currFileCount = fileCount;
521526
fileCount = getFileCount(logDir);
522-
CHECK(fileCount - currFileCount == 5); // There are 5 valid levels.
527+
CHECK(fileCount - currFileCount == 6); // There are 5 valid levels, and a crash log.
523528

524529
// That is, no logs will be observed.
525530
CHECK(checkDomainEffectiveLevels(kC4LogNone));
@@ -638,3 +643,17 @@ TEST_CASE("LogEncoder Bad C-string", "[Log]") {
638643
" Obj=/Tweedledum#1/rattle#2/ and I'm another rattle\\n");
639644
CHECK(regex_match(result, expected));
640645
}
646+
647+
#ifndef _MSC_VER
648+
649+
TEST_CASE_METHOD(LogFileTest, "Crash Log", "[.LogManual]") {
650+
tmpLogDir.mkdir();
651+
LogFiles::Options fileOptions{tmpLogDir.canonicalPath(), "Hello", 1024, 1, false};
652+
createLogger(fileOptions, LogLevel::Info);
653+
WARN("This test will crash the process, so you will need to manually inspect "
654+
<< tmpLogDir.canonicalPath() << "/cbl_crash.log to see if things are working");
655+
c4log_enableFatalExceptionBacktrace();
656+
657+
raise(SIGABRT);
658+
}
659+
#endif

0 commit comments

Comments
 (0)