Extracting app logs from an .xcresult

Chris Mash
3 min readApr 25, 2024

If you’re a dev and you run tests in CI then you’ve probably run into the scenario (many times) where the tests are fine on your machine but on CI they fail.

And many times you just can’t tell what’s going wrong from the UI test results or the test runner’s logs, you can just tell that something is going wrong under the hood in the app and if you could see the logs of the app the answer would likely be apparent.

But where are those logs? They’re not available on CI, you just see the test runner’s logs, something like this:

2024-04-25 18:50:44.436099+0100 TestAppUITests-Runner[21640:5238984] [Default] Running tests...
t = nans Interface orientation changed to Portrait
Test Suite 'TestAppUITests' started at 2024-04-25 18:50:53.439.
Test Case '-[TestAppUITests.TestAppUITests testExample]' started.
t = 0.00s Start Test at 2024-04-25 18:50:53.441
t = 1.07s Set Up
t = 1.16s Open com.chrismash.TestApp
t = 1.16s Launch com.chrismash.TestApp
t = 5.69s Setting up automation session
t = 10.12s Wait for com.chrismash.TestApp to idle
t = 13.30s Waiting 5.0s for "Hello, world!" StaticText to exist
t = 14.33s Checking `Expect predicate `exists == 1` for object "Hello, world!" StaticText`
t = 14.34s Checking existence of `"Hello, world!" StaticText`
t = 14.71s Tear Down
Test Case '-[TestAppUITests.TestAppUITests testExample]' passed (15.088 seconds).
Test Suite 'TestAppUITests' passed at 2024-04-25 18:51:08.529.
Executed 1 test, with 0 failures (0 unexpected) in 15.088 (15.090) seconds

I’d been plagued by this for years and hadn’t found a solution to it. I think fastlane might have options to get at the app logs, but that wasn’t a great option for some of the projects I was working on.

Then I stumbled on an answer on StackOverflow that had appeared only a couple of months ago, pointing out that you can use the xcresulttool that ships with Xcode to extract the logs from an xcresult file!

The process outlined is a bit tedious to do repeatedly but, as henrique pointed out, it’s totally scriptable and I love nothing more than scripting tedious tasks, so I had to give it a go.

I’ve shared the resulting script here: https://github.com/ChrisMash/XCResultExtractor. It’ll output something a little like this:

Standard output and standard error from com.chrismash.TestApp with process ID 21774 beginning at 2024-04-25 17:50:58 +0000

App initialised
ContentView initialised
2024-04-25 18:51:03.553575+0100 TestApp[21774:5241363] [Default] Received request to exchange capabilities, remote interface capabilities are: <XCTCapabilities: 0x600000004840>: {
"query runtime issue reporting" = 1;
"query runtime issue reporting/automation type mismatch" = 1;
}
2024-04-25 18:51:03.561337+0100 TestApp[21774:5241363] [Default] Received request to notify when the main run loop is idle
2024-04-25 18:51:03.561388+0100 TestApp[21774:5241363] [Default] Idle notifier finished setting up run loop observer
2024-04-25 18:51:03.561542+0100 TestApp[21774:5241363] [Default] Received request to notify when animations are idle
2024-04-25 18:51:03.561583+0100 TestApp[21774:5241363] [Default] Sending animations idle reply with error: (null)
ContentView: @self changed.

There’s “noise” in there from the interaction between the test runner and the app (requests for view hierarchies etc.), but it’s definitely better than nothing. You can see the three logs that the test app (included in the repo) outputs:

App initialised
ContentView initialised
ContentView: @self changed.

It’s already helped me out a ton already so I’m looking forward to the future chances to make use of it, rather than dreading them!

--

--

Chris Mash

iOS developer since 2012, previously console games developer at Sony and Activision. Twitter: @CJMash