【UE4】完全に独立したカスタムクラッシュレポーターを実装する
はじめに
クラッシュレポーターに関する日本語情報はとても少ない
というか英語でも少ないし、UE4.24前後からは仕様が微妙に変化しているらしくggってもわからない部分が多い
なので「かっこいいクラッシュレポーターを作りたい!」と思ったときにとても苦労するので
自分がわかっている範囲で共有
完全に独立したカスタムクラッシュレポーターとは?
標準のクラッシュレポーターはこちら
見てわかる通り、めちゃくちゃ「UE4!!!!!」という印象だし出てほしくない情報とかも出ている
まぁ標準のクラッシュレポーターじたいもEngineのソースを弄れば変更が可能なのでレイアウトを変更したり見た目を変えることも可能ではあるけれど、色々要件がある場合自前でクラッシュレポーターを1から作成してそちらを使用したいというケースが出てくる
しかしそうなるととたんに情報が少なくなるのでそこらへんの情報をまとめる
想定しているゴール
- 完全に独立したカスタムクラッシュレポーターを呼び出すことが出来る
- エラー情報を取得することができる
クラッシュレポーターとは
UE4のエディタやパッケージ化したバイナリがクラッシュした際に出てくるエラー情報などを表示したうえで事前に設定したサーバへエラー内容を送信してくれるクライアント
詳細は公式ドキュメントを参照
開発環境
UE4.26系
Windows10
Visual Studio Community 2017
前準備
Githubから持ってきたEngineでビルドする
EpicgameLancherでDLした通常のUE4ではカスタムのクラッシュレポーターは使用できないので必ず行ってください
- GithubからEngineのソースを手に入れる方法についての詳細は公式ドキュメントへ
- Engineのソースが用意出来たらuprojectファイルを右クリックでSwitch Unreal Engine version
- 用意したEngineを指定してslnファイルを再生成
- VisualStudioでエディタを再ビルドする
プロジェクト設定
クラッシュレポーターをパッケージに含めるためとエラー情報を取得できるようにするために以下の二つをプロジェクト設定からONにする
独自のクラッシュレポーターを実装する
クラッシュレポーターの実装形式は何でもよいのだが、今回は標準的なWPFアプリケーションで実装
※ここのコードそのものは重要ではない
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.IO; namespace CrashRepoter { /// <summary> /// App.xaml の相互作用ロジック /// </summary> public partial class App : Application { private string windowMessage = ""; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); List<string> argList = new List<string>(e.Args); string path = argList.Find(n => n.Contains("UE4CC-") && n.Contains("Crashes")); string logText = null, xmlText = null; byte[] miniDump = null; if (string.IsNullOrEmpty(path)) return; GetErrorInfos(path, out logText, out xmlText, out miniDump); windowMessage = xmlText; } protected override void OnActivated(EventArgs e) { base.OnActivated(e); MainWindow mainWindow = MainWindow as MainWindow; mainWindow.SetDescriptionText(windowMessage); } private void GetErrorInfos(string crashDirPath, out string OutLog, out string OutXml, out byte[] OutMiniDump) { OutLog = ""; OutXml = ""; OutMiniDump = null; DirectoryInfo crashDir = new DirectoryInfo(crashDirPath); if (crashDir.Exists) { crashDir.Refresh(); FileInfo[] fileBuffer = null; fileBuffer = crashDir.GetFiles("*.log"); if (fileBuffer.Length > 0) { FileInfo logFile = fileBuffer.First(); OutLog = File.ReadAllText(logFile.FullName); } fileBuffer = crashDir.GetFiles("*.runtime-xml"); if (fileBuffer.Length > 0) { FileInfo logFile = fileBuffer.First(); OutXml = File.ReadAllText(logFile.FullName); } fileBuffer = crashDir.GetFiles("*.dmp"); if (fileBuffer.Length > 0) { FileInfo dumpFile = fileBuffer.First(); OutMiniDump = File.ReadAllBytes(dumpFile.FullName); } } } } }
重要な部分のコード解説
エラー情報の吐き出し先のPathを取得する
引数に起動時のパス情報などが渡されるので文字列検索で取得可能
List<string> argList = new List<string>(e.Args); string path = argList.Find(n => n.Contains("UE4CC-") && n.Contains("Crashes"));
EventArgs引数が取得できない場合はEnvironmentクラスで取得可能なのでこちらでもOK
string[] args = Environment.GetCommandLineArgs();
備考
独自のクラッシュレポーターを作成するときにあまりネットに情報ないのがUE4側から吐き出されたエラー情報のファイルがどこにあるのかという点
ネットにある資料(参考リンク)では以下のPathにあるとあるのだが現在は仕様が変わったせいなのかここには存在しない
~\AppData\Local\[Game Name]\Saved\Crashes\UE4CC-Windows-#################################
現在は以下のパスに出力される
~\[Packaged folder]\[project name]\Saved\Crashes\UE4CC-Windows-#################################
なお、引数として渡される情報は以下の通りである
第1引数 | 第2引数 | 第3引数 | 第4引数 |
---|---|---|---|
エラーファイルの出力Path | gameのAppName | 今回のCrashGUID | DebugSymbolsのPath |
パッケージされた成果物のクラッシュレポーターをカスタムクラッシュレポーターにする
実行ファイルを置き換えるだけ
UE4のクラッシュレポーターはゲームとは完全に独立していて別プロセスとなっているので置き換えるだけで動作するようにできている
クラッシュレポーターは以下のPathに配置されているのでそのディレクトリのファイルを全て削除してカスタムクラッシュレポーターの成果物へ置き換えよう
※この時カスタムクラッシュレポーターのファイル名は全て「CrashReportClient」にしておこう
~\[Packaged folder]\Engine\Binaries\Win64
置き換えた後のクラッシュレポーターディレクトリ
これで全ての作業が完了
ゲームを起動させてコンソールコマンドなどで意図的にクラッシュさせて作成したクラッシュレポーターが起動することを確認しよう
おまけ
いやー完全独自のカスタムクラッシュレポーターとか要らないから標準のクラッシュレポーターをパパっといじりたいですわ~
という人は以下のbugsplatさま(参考リンク)の記事を見ればどうにかなるので参考にしてほしい