Add CheckCaches mode to emit a log/save/screenshot on detected issue
This commit is contained in:
@@ -938,7 +938,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||||
InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0);
|
InvalidateWindowClassesData(WC_DEPARTURES_BOARD, 0);
|
||||||
|
|
||||||
CheckCaches(true, nullptr);
|
CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2688,7 +2688,7 @@ DEF_CONSOLE_CMD(ConCheckCaches)
|
|||||||
if (broadcast) {
|
if (broadcast) {
|
||||||
DoCommandP(0, 0, 0, CMD_DESYNC_CHECK);
|
DoCommandP(0, 0, 0, CMD_DESYNC_CHECK);
|
||||||
} else {
|
} else {
|
||||||
CheckCaches(true, nullptr);
|
CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
111
src/crashlog.cpp
111
src/crashlog.cpp
@@ -535,6 +535,62 @@ char *CrashLog::FillDesyncCrashLog(char *buffer, const char *last, const DesyncE
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the crash log buffer with all data of an inconsistency event.
|
||||||
|
* @param buffer The begin where to write at.
|
||||||
|
* @param last The last position in the buffer to write to.
|
||||||
|
* @return the position of the \c '\0' character after the buffer.
|
||||||
|
*/
|
||||||
|
char *CrashLog::FillInconsistencyLog(char *buffer, const char *last, const InconsistencyExtraInfo &info) const
|
||||||
|
{
|
||||||
|
time_t cur_time = time(nullptr);
|
||||||
|
buffer += seprintf(buffer, last, "*** OpenTTD Inconsistency Report ***\n\n");
|
||||||
|
|
||||||
|
buffer += seprintf(buffer, last, "Inconsistency at: %s", asctime(gmtime(&cur_time)));
|
||||||
|
|
||||||
|
#ifdef USE_SCOPE_INFO
|
||||||
|
buffer += WriteScopeLog(buffer, last);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i, %i) (DL: %u)\n", _cur_date_ymd.year, _cur_date_ymd.month + 1, _cur_date_ymd.day, _date_fract, _tick_skip_counter, _settings_game.economy.day_length_factor);
|
||||||
|
if (_game_load_time != 0) {
|
||||||
|
buffer += seprintf(buffer, last, "Game loaded at: %i-%02i-%02i (%i, %i), %s",
|
||||||
|
_game_load_cur_date_ymd.year, _game_load_cur_date_ymd.month + 1, _game_load_cur_date_ymd.day, _game_load_date_fract, _game_load_tick_skip_counter, asctime(gmtime(&_game_load_time)));
|
||||||
|
}
|
||||||
|
if (_networking && !_network_server) {
|
||||||
|
extern Date _last_sync_date;
|
||||||
|
extern DateFract _last_sync_date_fract;
|
||||||
|
extern uint8 _last_sync_tick_skip_counter;
|
||||||
|
|
||||||
|
YearMonthDay ymd;
|
||||||
|
ConvertDateToYMD(_last_sync_date, &ymd);
|
||||||
|
buffer += seprintf(buffer, last, "Last sync at: %i-%02i-%02i (%i, %i)",
|
||||||
|
ymd.year, ymd.month + 1, ymd.day, _last_sync_date_fract, _last_sync_tick_skip_counter);
|
||||||
|
}
|
||||||
|
buffer += seprintf(buffer, last, "\n");
|
||||||
|
|
||||||
|
buffer = this->LogOpenTTDVersion(buffer, last);
|
||||||
|
buffer = this->LogOSVersion(buffer, last);
|
||||||
|
buffer = this->LogCompiler(buffer, last);
|
||||||
|
buffer = this->LogOSVersionDetail(buffer, last);
|
||||||
|
buffer = this->LogConfiguration(buffer, last);
|
||||||
|
buffer = this->LogLibraries(buffer, last);
|
||||||
|
buffer = this->LogGamelog(buffer, last);
|
||||||
|
buffer = this->LogRecentNews(buffer, last);
|
||||||
|
buffer = this->LogCommandLog(buffer, last);
|
||||||
|
buffer = DumpDesyncMsgLog(buffer, last);
|
||||||
|
|
||||||
|
if (!info.check_caches_result.empty()) {
|
||||||
|
buffer += seprintf(buffer, last, "CheckCaches:\n");
|
||||||
|
for (const std::string &str : info.check_caches_result) {
|
||||||
|
buffer += seprintf(buffer, last, " %s\n", str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += seprintf(buffer, last, "*** End of OpenTTD Inconsistency Report ***\n");
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the version info log buffer.
|
* Fill the version info log buffer.
|
||||||
* @param buffer The begin where to write at.
|
* @param buffer The begin where to write at.
|
||||||
@@ -758,6 +814,61 @@ bool CrashLog::MakeDesyncCrashLog(const std::string *log_in, std::string *log_ou
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes an inconsistency log, writes it to a file and then subsequently tries
|
||||||
|
* to make a crash savegame. It uses DEBUG to write
|
||||||
|
* information like paths to the console.
|
||||||
|
* @return true when everything is made successfully.
|
||||||
|
*/
|
||||||
|
bool CrashLog::MakeInconsistencyLog(const InconsistencyExtraInfo &info) const
|
||||||
|
{
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
char buffer[65536 * 2];
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
char name_buffer[64];
|
||||||
|
char *name_buffer_date = name_buffer + seprintf(name_buffer, lastof(name_buffer), "inconsistency-");
|
||||||
|
time_t cur_time = time(nullptr);
|
||||||
|
strftime(name_buffer_date, lastof(name_buffer) - name_buffer_date, "%Y%m%dT%H%M%SZ", gmtime(&cur_time));
|
||||||
|
|
||||||
|
printf("Inconsistency encountered, generating diagnostics log...\n");
|
||||||
|
this->FillInconsistencyLog(buffer, lastof(buffer), info);
|
||||||
|
|
||||||
|
bool bret = this->WriteCrashLog(buffer, filename, lastof(filename), name_buffer);
|
||||||
|
if (bret) {
|
||||||
|
printf("Inconsistency log written to %s. Please add this file to any bug reports.\n\n", filename);
|
||||||
|
} else {
|
||||||
|
printf("Writing inconsistency log failed.\n\n");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_savegame_DBGL_data = buffer;
|
||||||
|
_save_DBGC_data = true;
|
||||||
|
bret = this->WriteSavegame(filename, lastof(filename), name_buffer);
|
||||||
|
if (bret) {
|
||||||
|
printf("info savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
printf("Writing inconsistency savegame failed. Please attach the last (auto)save to any bug reports.\n\n");
|
||||||
|
}
|
||||||
|
_savegame_DBGL_data = nullptr;
|
||||||
|
_save_DBGC_data = false;
|
||||||
|
|
||||||
|
if (!(_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == nullptr)) {
|
||||||
|
SetScreenshotAuxiliaryText("Inconsistency Log", buffer);
|
||||||
|
bret = this->WriteScreenshot(filename, lastof(filename), name_buffer);
|
||||||
|
if (bret) {
|
||||||
|
printf("Inconsistency screenshot written to %s. Please add this file to any bug reports.\n\n", filename);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
printf("Writing inconsistency screenshot failed.\n\n");
|
||||||
|
}
|
||||||
|
ClearScreenshotAuxiliaryText();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a version info log, writes it to a file. It uses DEBUG to write
|
* Makes a version info log, writes it to a file. It uses DEBUG to write
|
||||||
* information like paths to the console.
|
* information like paths to the console.
|
||||||
|
@@ -27,6 +27,10 @@ struct DesyncExtraInfo {
|
|||||||
};
|
};
|
||||||
DECLARE_ENUM_AS_BIT_SET(DesyncExtraInfo::Flags)
|
DECLARE_ENUM_AS_BIT_SET(DesyncExtraInfo::Flags)
|
||||||
|
|
||||||
|
struct InconsistencyExtraInfo {
|
||||||
|
std::vector<std::string> check_caches_result;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for creating crash logs.
|
* Helper class for creating crash logs.
|
||||||
*/
|
*/
|
||||||
@@ -130,6 +134,7 @@ public:
|
|||||||
|
|
||||||
char *FillCrashLog(char *buffer, const char *last) const;
|
char *FillCrashLog(char *buffer, const char *last) const;
|
||||||
char *FillDesyncCrashLog(char *buffer, const char *last, const DesyncExtraInfo &info) const;
|
char *FillDesyncCrashLog(char *buffer, const char *last, const DesyncExtraInfo &info) const;
|
||||||
|
char *FillInconsistencyLog(char *buffer, const char *last, const InconsistencyExtraInfo &info) const;
|
||||||
char *FillVersionInfoLog(char *buffer, const char *last) const;
|
char *FillVersionInfoLog(char *buffer, const char *last) const;
|
||||||
bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name = "crash", FILE **crashlog_file = nullptr) const;
|
bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name = "crash", FILE **crashlog_file = nullptr) const;
|
||||||
|
|
||||||
@@ -148,6 +153,7 @@ public:
|
|||||||
|
|
||||||
bool MakeCrashLog();
|
bool MakeCrashLog();
|
||||||
bool MakeDesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info) const;
|
bool MakeDesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info) const;
|
||||||
|
bool MakeInconsistencyLog(const InconsistencyExtraInfo &info) const;
|
||||||
bool MakeVersionInfoLog() const;
|
bool MakeVersionInfoLog() const;
|
||||||
bool MakeCrashSavegameAndScreenshot() const;
|
bool MakeCrashSavegameAndScreenshot() const;
|
||||||
|
|
||||||
@@ -165,6 +171,7 @@ public:
|
|||||||
static void InitThread();
|
static void InitThread();
|
||||||
|
|
||||||
static void DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info);
|
static void DesyncCrashLog(const std::string *log_in, std::string *log_out, const DesyncExtraInfo &info);
|
||||||
|
static void InconsistencyLog(const InconsistencyExtraInfo &info);
|
||||||
static void VersionInfoLog();
|
static void VersionInfoLog();
|
||||||
|
|
||||||
static void SetErrorMessage(const char *message);
|
static void SetErrorMessage(const char *message);
|
||||||
|
@@ -16,7 +16,8 @@ enum CheckCachesFlags : uint32 {
|
|||||||
CHECK_CACHE_NONE = 0,
|
CHECK_CACHE_NONE = 0,
|
||||||
CHECK_CACHE_GENERAL = 1 << 0,
|
CHECK_CACHE_GENERAL = 1 << 0,
|
||||||
CHECK_CACHE_INFRA_TOTALS = 1 << 1,
|
CHECK_CACHE_INFRA_TOTALS = 1 << 1,
|
||||||
CHECK_CACHE_ALL = UINT32_MAX,
|
CHECK_CACHE_ALL = UINT16_MAX,
|
||||||
|
CHECK_CACHE_EMIT_LOG = 1 << 16,
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_AS_BIT_SET(CheckCachesFlags)
|
DECLARE_ENUM_AS_BIT_SET(CheckCachesFlags)
|
||||||
|
|
||||||
|
@@ -2288,7 +2288,7 @@ static void DoAcquireCompany(Company *c)
|
|||||||
|
|
||||||
delete c;
|
delete c;
|
||||||
|
|
||||||
CheckCaches(true, nullptr);
|
CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int GetAmountOwnedBy(const Company *c, Owner owner);
|
extern int GetAmountOwnedBy(const Company *c, Owner owner);
|
||||||
|
@@ -1373,6 +1373,13 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log, CheckC
|
|||||||
if (desync_level == 1 && _scaled_date_ticks % 500 != 0) return;
|
if (desync_level == 1 && _scaled_date_ticks % 500 != 0) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> saved_messages;
|
||||||
|
if (flags & CHECK_CACHE_EMIT_LOG) {
|
||||||
|
log = [&saved_messages](const char *str) {
|
||||||
|
saved_messages.emplace_back(str);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
char cclog_buffer[1024];
|
char cclog_buffer[1024];
|
||||||
#define CCLOG(...) { \
|
#define CCLOG(...) { \
|
||||||
seprintf(cclog_buffer, lastof(cclog_buffer), __VA_ARGS__); \
|
seprintf(cclog_buffer, lastof(cclog_buffer), __VA_ARGS__); \
|
||||||
@@ -1763,6 +1770,15 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log, CheckC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & CHECK_CACHE_EMIT_LOG) && !saved_messages.empty()) {
|
||||||
|
InconsistencyExtraInfo info;
|
||||||
|
info.check_caches_result = std::move(saved_messages);
|
||||||
|
CrashLog::InconsistencyLog(info);
|
||||||
|
for (std::string &str : info.check_caches_result) {
|
||||||
|
LogDesyncMsg(std::move(str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef CCLOGV
|
#undef CCLOGV
|
||||||
#undef CCLOG
|
#undef CCLOG
|
||||||
}
|
}
|
||||||
@@ -1779,7 +1795,7 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log, CheckC
|
|||||||
CommandCost CmdDesyncCheck(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
CommandCost CmdDesyncCheck(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||||
{
|
{
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
CheckCaches(true, nullptr);
|
CheckCaches(true, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommandCost();
|
return CommandCost();
|
||||||
@@ -1836,7 +1852,7 @@ void StateGameLoop()
|
|||||||
SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
|
SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckCaches(false, nullptr);
|
CheckCaches(false, nullptr, CHECK_CACHE_ALL | CHECK_CACHE_EMIT_LOG);
|
||||||
|
|
||||||
/* All these actions has to be done from OWNER_NONE
|
/* All these actions has to be done from OWNER_NONE
|
||||||
* for multiplayer compatibility */
|
* for multiplayer compatibility */
|
||||||
|
@@ -492,6 +492,13 @@ void CDECL HandleCrash(int signum, siginfo_t *si, void *context)
|
|||||||
log.MakeDesyncCrashLog(log_in, log_out, info);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info)
|
||||||
|
{
|
||||||
|
CrashLogOSX log(CrashLogOSX::DesyncTag{});
|
||||||
|
log.MakeInconsistencyLog(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* static */ void CrashLog::VersionInfoLog()
|
/* static */ void CrashLog::VersionInfoLog()
|
||||||
{
|
{
|
||||||
CrashLogOSX log(CrashLogOSX::DesyncTag{});
|
CrashLogOSX log(CrashLogOSX::DesyncTag{});
|
||||||
|
@@ -628,6 +628,12 @@ static void CDECL HandleCrash(int signum)
|
|||||||
log.MakeDesyncCrashLog(log_in, log_out, info);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info)
|
||||||
|
{
|
||||||
|
CrashLogUnix log(CrashLogUnix::DesyncTag{});
|
||||||
|
log.MakeInconsistencyLog(info);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::VersionInfoLog()
|
/* static */ void CrashLog::VersionInfoLog()
|
||||||
{
|
{
|
||||||
CrashLogUnix log(CrashLogUnix::DesyncTag{});
|
CrashLogUnix log(CrashLogUnix::DesyncTag{});
|
||||||
|
@@ -758,6 +758,12 @@ static void CDECL CustomAbort(int signal)
|
|||||||
log.MakeDesyncCrashLog(log_in, log_out, info);
|
log.MakeDesyncCrashLog(log_in, log_out, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void CrashLog::InconsistencyLog(const InconsistencyExtraInfo &info)
|
||||||
|
{
|
||||||
|
CrashLogWindows log(nullptr);
|
||||||
|
log.MakeInconsistencyLog(info);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::VersionInfoLog()
|
/* static */ void CrashLog::VersionInfoLog()
|
||||||
{
|
{
|
||||||
CrashLogWindows log(nullptr);
|
CrashLogWindows log(nullptr);
|
||||||
|
Reference in New Issue
Block a user