Skip to content

Commit 7903c4f

Browse files
authored
feat: auto-update DataRouterUrl (#68)
* chore: update copyright date * refactor: tease BugSplatSymbols out of BugSplatSettings * refactor: rename BugSplatSettings to BugSplatCrashReportClient * refactor: rename BugSplatSettingsCustomization to BugSplatEditorSettingsCustomization * feat: auto-update DataRouterUrl * fix: upload ios and android symbols * fix: garbage collector warning * fix: bUploadDebugSymbols in setup-upload-symbols-ios.sh * chore: update README.md * chore: update README
1 parent 876754f commit 7903c4f

27 files changed

+497
-405
lines changed

BugSplat.uplugin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
],
3636
"PostBuildSteps": {
3737
"Win64": [
38-
"call \"$(PluginDir)\\Source\\Scripts\\upload-symbols-win64.bat\" $(TargetPlatform) $(ProjectDir)"
38+
"call \"$(PluginDir)\\Source\\Scripts\\upload-symbols-win64.bat\" $(TargetPlatform) $(ProjectDir) $(TargetName)"
3939
],
4040
"Mac": [
4141
"sh $(PluginDir)/Source/Scripts/setup-upload-symbols-ios.sh $(TargetPlatform) $(TargetName) $(ProjectDir) $(PluginDir)"

README.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ You may choose to add BugSplat through the Unreal Marketplace or add the plugin
3232

3333
### Install Manually
3434

35-
1. Navigate to your project folder, which contains your `[ProjectName].uproject` file.
36-
2. If it does not already exist, create a `Plugins` folder.
35+
1. Navigate to your project folder containing your `[ProjectName].uproject` file.
36+
2. Create a `Plugins` folder if it does not already exist.
3737
3. Create a `BugSplat` folder in the `Plugins` folder and copy the contents of this repo into the `BugSplat` folder.
3838
4. In the Unreal Editor, ensure you can access the BugSplat plugin via `Edit > Project Settings` and scroll to the `BugSplat` section under `Plugins`.
3939

@@ -45,40 +45,38 @@ To get started, generate a Client ID and Client Secret via the [Integrations](ht
4545

4646
Next, open the BugSplat plugin menu in the Unreal Editor via `Edit > Project Settings`. Scroll to the `BugSplat` section of `Project Settings` and add values for `Database`, `Application`, `Version`, `Client ID`, and `Client Secret`:
4747

48-
<img width="1259" alt="BugSplat Unreal Plugin Settings" src="https://github.com/BugSplat-Git/bugsplat-unreal/assets/2646053/9997a602-4c1f-4b62-becf-5df264c9d70c">
48+
<img width="1126" alt="BugSplat Unreal Plugin Settings" src="https://github.com/BugSplat-Git/bugsplat-unreal/assets/2646053/c386a288-31e7-475d-adb8-9bef0506272b">
4949

50-
Be sure to also update your project settings to enable `Include Crash Reporter` and `Include Debug Files in Shipping Builds`:
50+
### Windows, macOS, and Linux
5151

52-
<img width="1126" alt="BugSplat Unreal Project Settings" src="https://github.com/BugSplat-Git/bugsplat-unreal/assets/2646053/55680b90-58fb-4afe-9169-a953f756f4d5">
53-
54-
### Desktop
55-
56-
For Desktop, the BugSplat plugin has the ability to modify the [DefaultEngine.ini](https://docs.unrealengine.com/5.0/en-US/configuration-files-in-unreal-engine/) file for both a packaged build or the global engine so that crashes are posted to BugSplat. Additionally, the BugSplat plugin can add a [PostBuildStep](https://docs.unrealengine.com/5.0/en-US/unreal-engine-build-tool-target-reference/) that will upload Windows [symbol files](https://docs.bugsplat.com/introduction/development/working-with-symbol-files) to BugSplat after each build.
57-
58-
BugSplat recommends configuring the crash reporting independently for each packaged build. To configure crash reporting in a packaged build select `Update Game INI`. When prompted, navigate to the root directory of your packaged build that contains the folder `Windows` or `WindowsNoEditor`. Note that you will need to **repeat this step and update the version information every time you create a packaged version of your game**. For production scenarios consider automating this step with a script on your build machine.
59-
60-
![Packaged Directory File Browser](https://github.com/BugSplat-Git/bugsplat-unreal/assets/2646053/4cd8e3c6-26b5-4341-a17b-3d5a18b078a0)
52+
BugSplat leverages Unreal's `CrashReportClient` to provide crash reporting for Windows, macOS, and Linux games. Be sure to update your project settings and enable `Include Crash Reporter` and `Include Debug Files in Shipping Builds`:
6153

62-
Alternatively, BugSplat can be configured to collect crash reports in the editor and all games built with the current engine. To configure BugSplat for the current engine, select `Update Global INI`. Note that updating the global `DefaultEngine.ini` file **will affect all projects using the same engine build**.
54+
<img width="1126" alt="BugSplat Unreal Project Settings" src="https://github.com/BugSplat-Git/bugsplat-unreal/assets/2646053/55680b90-58fb-4afe-9169-a953f756f4d5">
6355

64-
In order to get function names and line numbers in crash reports you'll need to upload your game's `.exe`, `.dll`, and `.pdb` files. To upload symbol files to BugSplat, select the `Add Symbol Uploads` button. The `Add Symbol Uploads` button will generate a bash script which uploads your project's [symbol files](https://docs.bugsplat.com/introduction/development/working-with-symbol-files) to BugSplat. A script to execute [SendPdbs.exe](https://docs.bugsplat.com/education/faq/using-sendpdbs-to-automatically-upload-symbol-files) will be added to the `PostBuildSteps` field in `BugSplat.uplugin` and will run automatically when your game is built.
56+
To configure `CrashReportClient` to post to BugSplat, the `DataRouterUrl` value needs to be added to `DefaultEngine.ini`. The `bugsplat-unreal` plugin automatically updates the value for `DataRouterUrl` when the `Update Engine DefaultEngine.ini` option is enabled. Please note the `DataRouterUrl` value is global and is shared across all packaged builds created by the affected engine. To override the `DataRouterUrl` value a package build uses, you may optionally use the `Update Packaged Game INI` button under the `Tools` section.
6557

66-
### Mobile
58+
In order to get function names and line numbers in crash reports, you'll need to upload your game's `.exe`, `.dll`, and `.pdb` files. To upload debug symbols for reach build, ensure that the `Enable Automatic Symbol Uploads` option is selected. When selected, a script to execute [symbol-upload](https://github.com/BugSplat-Git/symbol-upload) will be added to the `PostBuildSteps` field in `BugSplat.uplugin`. The symbol upload script will run automatically when your game is built.
6759

68-
Select the `Add symbol uploads` and `Add crash reporting` checkboxes in the `Mobile` section of the plugin dialog. Once enabled, the BugSplat plugin will configure crash reporting and symbol uploads automatically on mobile platforms.
60+
### iOS and Android
6961

70-
Before attempting to use the BugSplat plugin to capture crashes on Mobile please ensure you've completed the [iOS](https://docs.unrealengine.com/5.0/en-US/setting-up-an-unreal-engine-project-for-ios/) and [Android](https://docs.unrealengine.com/5.0/en-US/android-support-for-unreal-engine/) quickstart guides.
62+
Before attempting to use the BugSplat plugin to capture crashes on Mobile, please ensure you've completed the [iOS](https://docs.unrealengine.com/5.0/en-US/setting-up-an-unreal-engine-project-for-ios/) and [Android](https://docs.unrealengine.com/5.0/en-US/android-support-for-unreal-engine/) quickstart guides.
7163

72-
In order to get function names and line numbers in your iOS crash reports, please make the following changes in the `iOS` section of `Project Settings`
64+
In order to get function names and line numbers in your iOS crash reports, please make the following changes in the `iOS` section of `Project Settings`.
7365

7466
| Option | Value |
7567
|--------|-------|
7668
| Generate dSYMs for code debugging and profiling| true |
77-
| Generate dSYMs as a bundle for third party crash tools | true |
69+
| Generate dSYMs as a bundle for third-party crash tools | true |
7870
| Support bitcode in shipping | false |
7971

72+
To enable crash reporting, ensure the `Enable iOS Crash Reporting` and `Enable Android Crash Reporting` options are selected.
73+
8074
Note that sometimes iOS applications won't crash while the USB cable is connected. If this happens, disconnect the USB cable and re-run the application to trigger a crash.
8175

76+
### Xbox and PlayStation
77+
78+
BugSplat can provide instructions for implementing Unreal crash reporting on Xbox and PlayStation. Please email us at [[email protected]](mailto:[email protected]) for more info.
79+
8280
## 🏃 Usage
8381

8482
Once you've installed the plugin, add the following C++ snippet to your game to generate a sample crash.
@@ -91,9 +89,9 @@ Run your application and submit a crash report.
9189
9290
On Desktops, submit a crash report via the Unreal CrashReportClient dialog that appears at crash time. We have developed a handy guide on how you can customize the Unreal CrashReportClient dialog that is available [here](https://www.bugsplat.com/blog/game-dev/customizing-unreal-engine-crash-dialog/).
9391
94-
On iOS, after a crash occurs, restart the game and tap the `Send Report` option when prompted.
92+
On iOS, after a crash occurs, restart the game and tap the `Send Report` option when prompted. On Android, crashes are submitted automatically at crash time.
9593
96-
Once you've submitted a crash report navigate to the [Crashes](https://app.bugsplat.com/v2/crashes) page. On the Crashes page, click the link in the ID column.
94+
Once you've submitted a crash report, navigate to the [Crashes](https://app.bugsplat.com/v2/crashes) page. On the Crashes page, click the link in the ID column.
9795
9896
If everything is configured correctly, you should see something that resembles the following:
9997

Source/BugSplat/BugSplat.Build.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 BugSplat. All Rights Reserved.
1+
// Copyright 2023 BugSplat. All Rights Reserved.
22

33
using UnrealBuildTool;
44

Source/BugSplat/Private/BugSplat.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// Copyright 2022 BugSplat. All Rights Reserved.
1+
// Copyright 2023 BugSplat. All Rights Reserved.
22

33
#include "BugSplat.h"
4-
#include "BugSplatSettings.h"
5-
#include "BugSplatSettingsCustomization.h"
4+
#include "BugSplatCrashReportClient.h"
5+
#include "BugSplatEditorSettingsCustomization.h"
66
#include "LevelEditor.h"
77
#include "Widgets/Docking/SDockTab.h"
88
#include "Widgets/Layout/SBox.h"
@@ -12,6 +12,8 @@
1212
#include <Runtime/Projects/Public/PluginDescriptor.h>
1313
#include <EngineSharedPCH.h>
1414
#include <Editor/MainFrame/Public/Interfaces/IMainFrameModule.h>
15+
#include <BugSplatEditorSettings.h>
16+
#include "BugSplatRuntime.h"
1517

1618
static const FName BugSplatTabName("BugSplat");
1719

@@ -33,14 +35,15 @@ void FBugSplatModule::StartupModule()
3335
auto& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
3436
PropertyModule.RegisterCustomClassLayout(
3537
"BugSplatEditorSettings",
36-
FOnGetDetailCustomizationInstance::CreateStatic(&FBugSplatSettingsCustomization::MakeInstance));
38+
FOnGetDetailCustomizationInstance::CreateStatic(&FBugSplatEditorSettingsCustomization::MakeInstance));
3739

3840
PropertyModule.NotifyCustomizationModuleChanged();
3941
}
4042

4143
void FBugSplatModule::ShutdownModule()
4244
{
43-
delete BugSplatSettings;
45+
delete BugSplatCrashReportClient;
46+
delete BugSplatSymbols;
4447

4548
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
4649
{
@@ -54,21 +57,15 @@ FBugSplatModule& FBugSplatModule::Get()
5457
return FModuleManager::LoadModuleChecked<FBugSplatModule>("BugSplat");
5558
}
5659

57-
FReply FBugSplatModule::OnUpdateGlobalIni()
60+
void FBugSplatModule::OnUpdateBugSplatSettings()
5861
{
59-
BugSplatSettings->UpdateGlobalIni();
60-
return FReply::Handled();
62+
BugSplatCrashReportClient->UpdateEngineSettings();
63+
BugSplatSymbols->UpdateSymbolUploadsSettings();
6164
}
6265

6366
FReply FBugSplatModule::OnUpdateLocalIni()
6467
{
65-
BugSplatSettings->UpdateLocalIni();
66-
return FReply::Handled();
67-
}
68-
69-
FReply FBugSplatModule::OnUpdateWindowsSymbolUploadScript()
70-
{
71-
BugSplatSettings->WriteSymbolUploadScript();
68+
BugSplatCrashReportClient->UpdatePackagedBuildSettings();
7269
return FReply::Handled();
7370
}
7471

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Copyright 2023 BugSplat. All Rights Reserved.
2+
3+
#include "BugSplatCrashReportClient.h"
4+
#include <Developer/DesktopPlatform/Public/DesktopPlatformModule.h>
5+
#include <Modules/BuildVersion.h>
6+
#include <Runtime/Core/Public/Misc/EngineVersionComparison.h>
7+
8+
#include "BugSplatEditorSettings.h"
9+
#include "BugSplatRuntime.h"
10+
11+
FBugSplatCrashReportClient::FBugSplatCrashReportClient()
12+
{
13+
14+
}
15+
16+
FString FBugSplatCrashReportClient::CreateBugSplatEndpointUrl(FString Database, FString App, FString Version)
17+
{
18+
FStringFormatOrderedArguments args;
19+
20+
FString Space = " ";
21+
FString EncodedSpace = "%20";
22+
args.Add(Database);
23+
args.Add(App.Replace(*Space, *EncodedSpace));
24+
args.Add(Version.Replace(*Space, *EncodedSpace));
25+
26+
return *FString::Format(*BUGSPLAT_ENDPOINT_URL_FORMAT, args);
27+
}
28+
29+
void FBugSplatCrashReportClient::UpdateCrashReportClientIni(FString Database, FString App, FString Version, FString DefaultEngineIniFilePath)
30+
{
31+
if (!FPaths::FileExists(DefaultEngineIniFilePath))
32+
{
33+
FMessageDialog::Debugf(FText::FromString("Could not find DefaultEngine.ini!"));
34+
return;
35+
}
36+
37+
FConfigCacheIni ini(EConfigCacheType::DiskBacked);
38+
39+
ini.LoadFile(DefaultEngineIniFilePath);
40+
41+
FString SectionTag = FString(TEXT("CrashReportClient"));
42+
43+
FString DataRouterUrlConfigTag = FString(TEXT("DataRouterUrl"));
44+
FString DataRouterUrlValue = CreateBugSplatEndpointUrl(Database, App, Version);
45+
46+
FString CrashReportClientVersionConfigTag = FString(TEXT("CrashReportClientVersion"));
47+
FString CrashReportClientVersionValue = FString(TEXT("1.0"));
48+
49+
ini.SetString(*SectionTag, *DataRouterUrlConfigTag, *DataRouterUrlValue, DefaultEngineIniFilePath);
50+
ini.SetString(*SectionTag, *CrashReportClientVersionConfigTag, *CrashReportClientVersionValue, DefaultEngineIniFilePath);
51+
}
52+
53+
void FBugSplatCrashReportClient::UpdateEngineSettings()
54+
{
55+
UBugSplatEditorSettings* RuntimeSettings = FBugSplatRuntimeModule::Get().GetSettings();
56+
57+
if (!RuntimeSettings->HasValidCrashReporterSettings())
58+
{
59+
return;
60+
}
61+
62+
if (!RuntimeSettings->bUpdateEngineDataRouterUrl)
63+
{
64+
return;
65+
}
66+
67+
UpdateCrashReportClientIni(
68+
RuntimeSettings->BugSplatDatabase,
69+
RuntimeSettings->BugSplatApp,
70+
RuntimeSettings->BugSplatVersion,
71+
*GLOBAL_CRASH_REPORT_CLIENT_CONFIG_PATH
72+
);
73+
}
74+
75+
void FBugSplatCrashReportClient::UpdatePackagedBuildSettings()
76+
{
77+
FString PackagedBuildFolderPath;
78+
79+
if (!FDesktopPlatformModule::Get()->OpenDirectoryDialog(
80+
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
81+
FString("Packaged Directory"),
82+
FPaths::GetProjectFilePath(),
83+
PackagedBuildFolderPath))
84+
{
85+
return;
86+
}
87+
88+
UBugSplatEditorSettings* RuntimeSettings = FBugSplatRuntimeModule::Get().GetSettings();
89+
90+
if (!RuntimeSettings->HasValidCrashReporterSettings())
91+
{
92+
FMessageDialog::Debugf(FText::FromString("Invalid settings, update plugin fields and try again."));
93+
return;
94+
}
95+
96+
FString Platforms[] = {
97+
TEXT("Windows"),
98+
TEXT("Linux"),
99+
TEXT("Mac")
100+
};
101+
bool FoundAnyValidFolders = false;
102+
103+
for (auto &Platform : Platforms)
104+
{
105+
FString PlatformTarget = GetPackagedBuildPlatformTarget(Platform);
106+
FString PlatformTargetPath = *FPaths::Combine(PackagedBuildFolderPath, PlatformTarget);
107+
108+
if (!FPaths::DirectoryExists(PlatformTargetPath))
109+
{
110+
continue;
111+
}
112+
113+
FoundAnyValidFolders = true;
114+
FString DefaultEngineIniRelativePath = GetPackagedBuildDefaultEngineIniRelativePath();
115+
FString DefaultEngineIniFolderPath = *FPaths::Combine(PackagedBuildFolderPath, *PlatformTarget, *DefaultEngineIniRelativePath);
116+
FString DefaultEngineIniFilePath = *FPaths::Combine(*DefaultEngineIniFolderPath, *INI_FILE_NAME);
117+
118+
if (!FPaths::DirectoryExists(DefaultEngineIniFolderPath))
119+
{
120+
IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
121+
PlatformFile.CreateDirectoryTree(*DefaultEngineIniFolderPath);
122+
123+
if (!FPaths::DirectoryExists(DefaultEngineIniFolderPath))
124+
{
125+
FMessageDialog::Debugf(FText::FromString("Failed to create " + DefaultEngineIniFolderPath));
126+
return;
127+
}
128+
129+
CreateEmptyTextFile(DefaultEngineIniFilePath);
130+
131+
if (!FPaths::FileExists(DefaultEngineIniFilePath))
132+
{
133+
FMessageDialog::Debugf(FText::FromString("Failed to create " + DefaultEngineIniFilePath));
134+
return;
135+
}
136+
}
137+
138+
UpdateCrashReportClientIni(
139+
RuntimeSettings->BugSplatDatabase,
140+
RuntimeSettings->BugSplatApp,
141+
RuntimeSettings->BugSplatVersion,
142+
DefaultEngineIniFilePath
143+
);
144+
}
145+
146+
if (!FoundAnyValidFolders)
147+
{
148+
FMessageDialog::Debugf(FText::FromString("Could not find any packaged build directories to update. Please specify the root directory of a valid packaged build."));
149+
return;
150+
}
151+
152+
FMessageDialog::Debugf(FText::FromString("Packaged build settings updated successfully!"));
153+
}
154+
155+
void FBugSplatCrashReportClient::CreateEmptyTextFile(FString FullPath)
156+
{
157+
FString Empty = FString("");
158+
FFileHelper::SaveStringToFile(Empty, *FullPath);
159+
}
160+
161+
FString FBugSplatCrashReportClient::GetPackagedBuildPlatformTarget(FString Platform)
162+
{
163+
return ENGINE_MAJOR_VERSION >= 5 ? Platform : Platform + TEXT("NoEditor");
164+
}
165+
166+
FString FBugSplatCrashReportClient::GetPackagedBuildDefaultEngineIniRelativePath()
167+
{
168+
if (ENGINE_MAJOR_VERSION == 5)
169+
{
170+
return PACKAGED_BUILD_CONFIG_PATH_5;
171+
}
172+
else if (ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 26)
173+
{
174+
return PACKAGED_BUILD_CONFIG_PATH_4_26_TO_5;
175+
}
176+
177+
return PACKAGED_BUILD_CONFIG_PATH_4_25_AND_OLDER;
178+
}

0 commit comments

Comments
 (0)