Building the Sentry Unreal Engine SDK with GitHub Actions
Ensuring a seamless player experience is critical for game developers, and yet unanticipated crashes and performance issues continue to harm games’ reputations and disrupt player engagement. To address this developers need proactive error monitoring across multiple platforms. Luckily, Sentry offers a robust SDK designed specifically for Unreal Engine to help developers debug and maintain performance effectively.
Building an SDK for Unreal Engine wasn’t straightforward though. While designing it, we considered Unreal's unique application structure and the challenges game developers face. But to make Sentry truly effective we had to figure out how to integrate seamlessly with the engine both in editor mode during development and in retail games on various platforms during production.
And that’s exactly what this post is about: the challenges and opportunities of building a game developer-first debugging solution. So whether you’re:
considering building an SDK for Unreal Engine, or
you’re looking for a way to integrate a native third-party library into your custom engine’s plugin, or
perhaps your project could benefit from automating repetitive tasks to streamline its development workflow, or
you’re just curious how we build the platform that supports you building the next big game
this blog post delivers useful insights through the lens of building our crash reporting solution for Unreal Engine. And it’ll include how we build and test support for Unreal Engine on:
Android
iOS
macOS x64 and arm64
Linux x64 and arm64
Windows x64
NOTE: This blog post described the full capabilities of Sentry's Unreal Engine SDK, but to be able to leverage them you should install the SDK from the GitHub Releases page. The version available in the Epic Games Fab (formerly marketplace) has some limitations. To learn more, visit our docs.
Designing the Sentry’s Unreal Engine SDK architecture to make monitoring easy across all platforms
In a nutshell, the SDK for Unreal Engine is just another abstraction level built on top of several other Sentry native SDKs - making it a cross-platform solution for capturing in-game crashes. We leverage the similar interfaces of our SDKs to provide developers with a unified C++/Blueprints API, allowing you to focus solely on Unreal plugin configuration without dealing with low-level platform-specific implementation details.
The Sentry Unreal SDK also includes Sentry CLI - a standalone tool that automatically uploads debug information files upon game build completion. These debug files contain the core data, including original function names, line numbers, file paths, stack traces, call frame info (CFI), and other relevant metadata. Sentry uses debug files to find relevant data to give you actionable insights so that you can debug issues
Since our Unreal SDK is built specifically for Unreal, when you add the SDK, you will be able to make calls to the API and benefit from the automatic instrumentation of the editor itself. The Sentry plugin within Unreal provides an editor menu so that you can configure Sentry; for example, you can quickly build post-processing hooks for uploading debug symbols and easily add listeners for the Unreal Engine logging system to enhance the data Sentry uses to contextualize issues and get you detailed stack traces for easy debugging.
Sentry relies on GitHub Actions to ensure SDK reliability
While Git and GitHub aren’t necessarily the industry standard for game development, we would be remiss to not leverage the large ecosystem of tools and cloud services to build game dev support (e.g. monitoring). In particular, Sentry SDKs (including our Unreal Engine SDK) rely on GitHub Actions to automate common CI/CD tasks such as building, testing and making releases to reduce the manual effort required for its development and maintenance.
GitHub Actions utilize declarative workflows defined in YAML files that have to be placed within the repository's .github/workflows
directory. Each workflow consists of triggers that specify when it should run and jobs that outline the tasks to be executed. Of course, our Unreal SDK has a few workflows that are unique to building support for a game engine:
Handling the additional dependencies on platform-specific Sentry SDKs
Our Unreal SDK heavily relies on other Sentry SDKs to effectively monitor your game across all target platforms. But being a Fair Source startup that is always iterating quickly, it is critical to keep these dependencies up to date. This allows game developers to take full advantage of the functionality Sentry has to offer, including new features, the most recent fixes, and even performance improvements that are made at the native layer.
Some of these dependencies are integrated into our Unreal Engine SDK as separate Git submodules managed within the main repository; this makes it easy to control and update their version. To ensure they are kept up to date, we have a GitHub Actions workflow called update-dependencies.yml
:
update-dependencies.yml
Click to Copyname: update-dependencies on: schedule: - cron: '0 3 * * *' push: branches: - main jobs: native: uses: getsentry/github-workflows/.github/workflows/updater.yml@v2 with: path: modules/sentry-native name: Native SDK secrets: api-token: ${{ secrets.CI_DEPLOY_KEY }} # same for sentry-java and sentry-cocoa cli: uses: getsentry/github-workflows/.github/workflows/updater.yml@v2 with: path: plugin-dev/sentry-cli.properties name: CLI secrets: api-token: ${{ secrets.CI_DEPLOY_KEY }}
This workflow runs daily and on every merge to the main branch, ensuring that our Unreal SDK is kept up to date with updated dependencies and there are no changelog conflicts.
Workflow Tip: Use updater.yml
for dependencies
For our update-depenencies.yml
workflow, you might have noticed that we’re calling updater.yml
. This is a custom action that checks if the specified dependency is up to date by comparing release tags in the submodule and a matching base repo. If there’s a newer version available it will create a pull request that bumps the submodule to the latest tag and updates the changelog accordingly.
In addition to keeping our Unreal SDK aligned with the latest Sentry native SDKs changes, we also need to track updates to sentry-cli
. However, for the Unreal plugin we're only using its pre-built executable, so there is no reason to add yet another submodule to the SDK's repo. We can just track the version in a fairly simple file called sentry-cli.properties
:
sentry-cli.properties
Click to Copyversion=2.38.2 repo=https://github.com/getsentry/sentry-cli
Through the updater custom action we can specify how we’d like to handle dependency checks. So for the sentry-cli
dependency, updater
will consume the version info from the properties file (plugin-dev/sentry-cli.properties
) and make a comparison against the repo’s latest published tag. Then, the version from the properties file is consumed by a script that downloads the required Sentry CLI binaries from its repo’s release page.
Preparing and validating Unreal Engine package content
Once all of the dependencies are up to date we have to process them in a way so that these can be consumed by our Unreal SDK. Some dependencies, like our Native or Android SDKs, require a bit more work as they need to be built in a CI environment to ensure their compatibility with the engine. Others, such as Sentry CLI and the Apple/Cocoa SDK and the Apple/Cocoa SDK, are way simpler to integrate since a simple download of the necessary binaries is sufficient.
This brings us to the continuous integration GitHub Action: ci.yml
, which is a key part of the entire Unreal SDK CI pipeline. At the beginning we have a set of jobs (one per each platform supported by the plugin) that are responsible for actual dependencies preparation.
ci.yml
Click to Copyjobs: android-sdk: uses: ./.github/workflows/sdk-build.yml with: target: Android runsOn: ubuntu-latest ios-sdk: uses: ./.github/workflows/sdk-download.yml with: target: IOS runsOn: ubuntu-latest macos-sdk: uses: ./.github/workflows/sdk-download.yml with: target: Mac runsOn: ubuntu-latest linux-sdk: uses: ./.github/workflows/sdk-build.yml with: target: Linux runsOn: ubuntu-20.04 linux-arm64-sdk: uses: ./.github/workflows/sdk-build.yml with: target: LinuxArm64 runsOn: ubuntu-latest-4-cores-arm64 container: arm64v8/ubuntu:20.04 windows-crashpad-sdk: uses: ./.github/workflows/sdk-build.yml with: target: Win64-Crashpad runsOn: windows-2019 windows-breakpad-sdk: uses: ./.github/workflows/sdk-build.yml with: target: Win64-Breakpad runsOn: windows-2019
The low-level details of this process are hidden behind the
sdk-download.yml
and sdk-build.yml
workflows (e.g. environment setup, pulling certain submodules, building libraries and storing the resulting artifacts to the GitHub cache for further usage).
Once all of the SDK dependencies are downloaded and built, the plugin’s source code needs to be packaged along with all of the artifacts generated previously for every supported engine version. This package is the final deliverable that users will download from the GitHub release page or while installing the plugin via the Epic Games launcher.
ci.yml
Click to Copybuild: needs: [android-sdk, ios-sdk, macos-sdk, linux-sdk, linux-arm64-sdk, windows-crashpad-sdk, windows-breakpad-sdk] name: Package runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Download CLI shell: pwsh run: ./scripts/download-cli.ps1 - uses: actions/download-artifact@v4 with: name: Android-sdk path: plugin-dev/Source/ThirdParty/Android # ...Download other dependencies... - name: Prepare Sentry packages for release shell: pwsh run: ./scripts/packaging/pack.ps1 - name: Upload release artifacts uses: actions/upload-artifact@v4 with: name: ${{ github.sha }} if-no-files-found: error path: | sentry-unreal-*.zip
Lastly, we verify the plugin package for completeness by comparing it against a pre-defined snapshot to identify any missing or new files. Any discrepancies will cause the CI pipeline to fail, making sure game developers are only ever using a working and complete version of the plugin.
There are times when this check will fail expectedly, for example after new scripts or assets are intentionally introduced to the plugin. In cases like this, there’s always an option to accept the new snapshot file content by running the test-contents.ps1
script locally with “accept” as an argument and committing its changes to your branch.
ci.yml
Click to Copypackage-validation: needs: [build] name: Check snapshot runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Download packages uses: actions/download-artifact@v4 with: name: ${{ github.sha }} - name: Verify package content against snapshot shell: pwsh run: ./scripts/packaging/test-contents.ps1
In the end the successful CI graph should look something like this:
Unreal Engine containers: build, test and run
Alright, getting to this point means that the Unreal SDK is properly packaged for use in Unreal Engine. But before it’s used we have to ensure that it can be compiled without errors and run tests.
Unreal Engine Docker containers become a great help with this task as they provide us with the reproducible environment that has all the necessary tools, libraries and most importantly the engine itself to build the Sentry SDK against.
The Sentry Unreal SDK is currently supported for all engine versions starting from 4.27 to 5.5 which is the most recent one at the time this is written. While Epic Games requires that Unreal Engine Marketplace publishers maintain only the three latest engine versions for their SDKs, we aim to provide broader support to accommodate the longer lifecycles of many games. You’ll be able to find those releases in our GitHub Releases page.
Note, that we use a matrix strategy to create multiple job runs for testing within a single job declaration based on the engine version variable.
ci.yml
Click to Copytest: name: Test UE ${{ matrix.unreal }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: unreal: ['4.27', '5.0', '5.1', '5.2', '5.3', '5.4', '5.5']
There are a few important things to keep in mind when working with Unreal Containers in GitHub Actions:
Since the default GitHub runners have limited storage you should free up disk space before pulling any of the Unreal Container images. These images can be up to 40 GB in size for even the “slim” version.
To avoid dealing with permission issues when sharing volumes between the GitHub runner and the Unreal Container, don’t use the root user. Instead, start the container with the user ID of the parent GitHub Action and
chown
engine’s paths to the container.Unreal Engine 5.4 and newer require you to enable ipv6 for the container so it starts up properly
Once the container is up and running triggering the actual SDK build and tests is pretty straightforward as it all comes to invoking a couple of UAT (Unreal Automation Tool) and Editor’s commands:
ci.yml
Click to Copy- name: Run tests id: run-tests run: | docker exec -w /workspace/checkout/${{ matrix.app }} unreal /home/ue4/UnrealEngine/Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \ -project=/workspace/checkout/${{ matrix.app }}/SentryPlayground.uproject \ -archivedirectory=/workspace/checkout/${{ matrix.app }}/Builds \ -platform=Linux \ -nop4 \ -cook \ -build \ -stage \ -prereqss \ -package \ -archive docker exec -w /workspace/checkout/${{ matrix.app }} unreal bash -c " cp -r '/home/ue4/Library/Logs/Unreal Engine/LocalBuildLogs' Saved/Logs " docker exec -w /workspace/checkout/${{ matrix.app }} unreal /home/ue4/UnrealEngine/Engine/Binaries/Linux/${{ matrix.unreal == '4.27' && 'UE4Editor' || 'UnrealEditor' }} \ /workspace/checkout/${{ matrix.app }}/SentryPlayground.uproject \ -ReportExportPath=/workspace/checkout/${{ matrix.app }}/Saved/Automation \ -ExecCmds="Automation RunTests Sentry;quit" \ -TestExit="Automation Test Queue Empty" \ -Unattended \ -NoPause \ -NoSplash \ -NullRHI
For our SDK, we wrap things up by collecting some build logs and automation testing reports that can be used later for more in-depth analysis if any issues arise during this stage.
TL;DR: the Sentry Unreal SDK is available for game devs today
And that’s pretty much it! You now know how we designed, built, and packaged our Unreal Engine SDK for game developers and can benefit from some of the gotcha’s we encountered along the way. Give it a try, we've got docs on installing the plugin and getting started.
We encourage you to explore our GitHub Actions workflow files on your own and share stories about your Unreal Engine tasks automation experience with us in Discord.
What is next for game developers wanting to debug efficiently?
While our current Unreal SDK deployment process covers a reasonable amount of Sentry’s Unreal Engine SDK automation, there are some additional functionality that we are looking to add in the near term:
Smoke Tests: We have good confidence from our Unit Tests, but additional automated integration tests will ensure that the crash monitoring of Unreal Engine games with the Sentry plugin integrated works reliably in various environments. Learn more on this GitHub issue. This is similar to what we did for Unity where a full game is built with the newly built package, and we test its symbol upload and the crash handling functions.
Expanding into other platforms: This new way of packaging Sentry SDKs has also given us insights into how we might expand this workflow to all supported platforms; including game consoles. Although here we’ll to need self-host our own build agents using devkits.
But that will be a whole new story worth a separate blog post so don’t be AFK for too long, you won’t want to miss updates on how game developers can ship and debug more confidently with Sentry.