Skip to content

Commit 1a9e419

Browse files
committed
feat(core): Crash Reporter
1 parent fef6ce0 commit 1a9e419

File tree

9 files changed

+147
-9
lines changed

9 files changed

+147
-9
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
working-directory: swiftly
5353
shell: bash
5454
run: |
55-
sudo apt install -y libreadline-dev
55+
sudo apt install -y libreadline-dev libboost-all-dev
5656
bash ./setup.sh
5757
5858
- name: Prepare Build - Windows

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@
101101
"complex": "cpp",
102102
"scoped_allocator": "cpp",
103103
"typeindex": "cpp",
104-
"valarray": "cpp"
104+
"valarray": "cpp",
105+
"*.ipp": "cpp"
105106
},
106107
"C_Cpp.default.compilerPath": "C:\\msys64\\mingw64\\bin\\g++.exe",
107108
"C_Cpp.formatting": "clangFormat"

AMBuilder

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ for sdk_target in MMSPlugin.sdk_targets:
6868
binary.compiler.defines += ['HAVE_STRUCT_TIMESPEC']
6969

7070
if binary.compiler.target.platform == 'linux':
71-
binary.compiler.postlink += ['-lrt', '-lssl', '-lcrypto', '-fexceptions', '-lidn2', '-lpsl', '-lbrotlidec', '-lz']
72-
binary.compiler.defines += ["LUA_USE_LINUX", "LUA_USE_READLINE"]
71+
binary.compiler.postlink += ['-lrt', '-lssl', '-lcrypto', '-fexceptions', '-lidn2', '-lpsl', '-lbrotlidec', '-lz', '-lbacktrace']
72+
binary.compiler.defines += ["LUA_USE_LINUX", "LUA_USE_READLINE", "BOOST_STACKTRACE_USE_BACKTRACE"]
7373
elif binary.compiler.target.platform == 'windows':
7474
binary.compiler.postlink += [
7575
os.path.join('psapi.lib'),

src/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class SwiftlyPlugin : public ISmmPlugin, public IMetamodListener
5151
void OnLevelShutdown();
5252
void NextFrame(std::function<void()> fn);
5353

54+
std::string GetMap();
55+
5456
public:
5557
void Hook_StartupServer(const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *);
5658
void Hook_GameFrame(bool simulating, bool bFirstTick, bool bLastTick);

src/dumps/CrashDump.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include "CrashDump.h"
2+
3+
#ifdef _WIN32
4+
bool BeginCrashListener() { return true; }
5+
#else
6+
7+
#include <boost/stacktrace.hpp>
8+
#include <boost/exception/all.hpp>
9+
#include <rapidjson/document.h>
10+
#include <rapidjson/writer.h>
11+
#include <rapidjson/stringbuffer.h>
12+
13+
#include <random>
14+
15+
#include <tier0/icommandline.h>
16+
17+
#include "../files/Files.h"
18+
#include "../http/HTTPManager.h"
19+
#include "../common.h"
20+
21+
std::string get_uuid()
22+
{
23+
static std::random_device dev;
24+
static std::mt19937 rng(dev());
25+
26+
std::uniform_int_distribution<int> dist(0, 15);
27+
28+
const char *v = "0123456789abcdef";
29+
const bool dash[] = {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0};
30+
31+
std::string res;
32+
for (int i = 0; i < 16; i++)
33+
{
34+
if (dash[i])
35+
res += "-";
36+
res += v[dist(rng)];
37+
res += v[dist(rng)];
38+
}
39+
return res;
40+
}
41+
42+
std::string startup_cmd = "None";
43+
44+
void signal_handler(int signumber)
45+
{
46+
try
47+
{
48+
auto boostStackTrace = boost::stacktrace::stacktrace();
49+
50+
std::string stacktrace = boost::to_string(boost::stacktrace::stacktrace());
51+
std::string coredumpdata = stacktrace;
52+
std::vector<std::string> splitted_dump = explode(coredumpdata, "\n");
53+
PRINTF("Crash Reporter", "A crash has occured and a dump has been created:\n");
54+
for (int i = 0; i < splitted_dump.size() - 1; i++)
55+
PRINTF("Crash Reporter", "%s\n", splitted_dump[i].c_str());
56+
57+
std::string file_path = string_format("addons/swiftly/dumps/crash.%s.log", get_uuid().c_str());
58+
if (Files::ExistsPath(file_path))
59+
Files::Delete(file_path);
60+
61+
Files::Append(file_path, string_format("================================\nCommand: %s\nMap: %s\n================================\n\n%s", startup_cmd.c_str(), g_Plugin.GetMap().c_str(), coredumpdata.c_str()), false);
62+
PRINTF("Crash Reporter", "A dump log file has been created at: %s\n", file_path.c_str());
63+
PRINTF("Crash Reporter", "A crash report has been sent to Swiftly Crash Reporter Server.\n");
64+
65+
rapidjson::Document document(rapidjson::kObjectType);
66+
67+
document.AddMember(rapidjson::Value().SetString("coredumpdata", document.GetAllocator()), rapidjson::Value().SetString(coredumpdata.c_str(), document.GetAllocator()), document.GetAllocator());
68+
document.AddMember(rapidjson::Value().SetString("startup_cmd", document.GetAllocator()), rapidjson::Value().SetString(startup_cmd.c_str(), document.GetAllocator()), document.GetAllocator());
69+
document.AddMember(rapidjson::Value().SetString("map", document.GetAllocator()), rapidjson::Value().SetString(g_Plugin.GetMap().c_str(), document.GetAllocator()), document.GetAllocator());
70+
71+
rapidjson::StringBuffer buffer;
72+
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
73+
document.Accept(writer);
74+
75+
std::string json = std::string(buffer.GetString());
76+
77+
uint64_t requestid = g_httpManager->CreateRequest("https://crashreporter.swiftlycs2.net");
78+
HTTPRequest *req = g_httpManager->FetchRequest(requestid);
79+
req->SetBody(json);
80+
req->SetContentType(ContentType::APPLICATION_JSON);
81+
req->Post("/");
82+
g_httpManager->DeleteRequest(requestid);
83+
}
84+
catch (const std::runtime_error &e)
85+
{
86+
PRINTF("Crash Reporter", "Error crash handling: %s\n", e.what());
87+
}
88+
89+
exit(EXIT_FAILURE);
90+
}
91+
92+
bool BeginCrashListener()
93+
{
94+
if (!Files::ExistsPath("addons/swiftly/dumps"))
95+
{
96+
if (!Files::CreateDirectory("addons/swiftly/dumps"))
97+
{
98+
PRINTF("Crash Listener", "Couldn't create dumps folder.\n");
99+
return false;
100+
}
101+
}
102+
103+
startup_cmd = CommandLine()->GetCmdLine();
104+
105+
::signal(SIGSEGV, &signal_handler);
106+
return true;
107+
}
108+
109+
#endif

src/dumps/CrashDump.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _crashdump_h
2+
#define _crashdump_h
3+
4+
bool BeginCrashListener();
5+
6+
#endif

src/entrypoint.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "entities/EntityManager.h"
2828
#include "precacher/Precacher.h"
2929
#include "menus/Menus.h"
30+
#include "dumps/CrashDump.h"
3031

3132
#define LOAD_COMPONENT(TYPE, VARIABLE_NAME) \
3233
{ \
@@ -135,7 +136,10 @@ bool SwiftlyPlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen,
135136
if (g_Config->LoadConfiguration())
136137
PRINT("Configurations", "The configurations has been succesfully loaded.\n");
137138
else
139+
{
138140
PRINT("Configurations", "Failed to load configurations. The plugin will not work.\n");
141+
return false;
142+
}
139143

140144
g_SMAPI->AddListener(this, this);
141145

@@ -182,6 +186,9 @@ bool SwiftlyPlugin::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen,
182186
if (g_Config->FetchValue<bool>("core.console_filtering"))
183187
g_conFilter->Toggle();
184188

189+
if (!BeginCrashListener())
190+
return false;
191+
185192
PRINT("Components", "Loading components...\n");
186193

187194
LOAD_COMPONENT(BasicComponent, basic_component);
@@ -289,7 +296,12 @@ void SwiftlyPlugin::Hook_GameServerSteamAPIActivated()
289296
RETURN_META(MRES_IGNORED);
290297
}
291298

292-
std::string map;
299+
std::string map = "None";
300+
301+
std::string SwiftlyPlugin::GetMap()
302+
{
303+
return map;
304+
}
293305

294306
void SwiftlyPlugin::OnLevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
295307
{

src/files/Files.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void Files::Delete(std::string path)
7878
std::filesystem::remove(path);
7979
}
8080

81-
void Files::Append(std::string path, std::string content)
81+
void Files::Append(std::string path, std::string content, bool hasdate)
8282
{
8383
ChangePath();
8484
std::filesystem::create_directories(Files::getBase(path));
@@ -91,12 +91,13 @@ void Files::Append(std::string path, std::string content)
9191
#pragma GCC diagnostic push
9292
#pragma GCC diagnostic ignored "-Wformat-truncation"
9393
#endif
94-
snprintf(date, sizeof(date), "[%02d/%02d/%04d - %02d:%02d:%02d] ", ltm->tm_mday, ltm->tm_mon + 1, ltm->tm_year + 1900, ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
94+
if (hasdate)
95+
snprintf(date, sizeof(date), "[%02d/%02d/%04d - %02d:%02d:%02d] ", ltm->tm_mday, ltm->tm_mon + 1, ltm->tm_year + 1900, ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
9596
#if GCC_COMPILER
9697
#pragma GCC diagnostic pop
9798
#endif
9899
std::ofstream File(path, std::ios_base::app);
99-
File << date << content << std::endl;
100+
File << (hasdate ? date : "") << content << std::endl;
100101
File.close();
101102
}
102103

@@ -112,6 +113,12 @@ bool Files::IsDirectory(std::string path)
112113
return std::filesystem::is_directory(path);
113114
}
114115

116+
bool Files::CreateDirectory(std::string path)
117+
{
118+
ChangePath();
119+
return std::filesystem::create_directory(path);
120+
}
121+
115122
std::vector<std::string> Files::FetchFileNames(std::string path)
116123
{
117124
ChangePath();

src/files/Files.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
namespace Files
1111
{
1212
std::string Read(std::string path);
13-
void Append(std::string path, std::string content);
13+
void Append(std::string path, std::string content, bool hasdate = true);
1414
void Delete(std::string path);
1515
std::string getBase(std::string filePath);
1616
bool ExistsPath(std::string path);
1717
bool IsDirectory(std::string path);
1818
std::vector<std::string> FetchFileNames(std::string path);
1919
std::vector<std::string> FetchDirectories(std::string path);
20+
bool CreateDirectory(std::string path);
2021
};
2122

2223
#endif

0 commit comments

Comments
 (0)