Debugging Combine with OSLog

Joe Williams
3 min readSep 23, 2021

Since heavily adopting Combine in some of our work, we’ve found debugging much harder than typical closure-based asynchronous code. Pyramid of Hell was, well, hell. On the flip side, we found reading those stack traces much easier. In Combine, it’s fairly well detailed that stack traces are super long or way too short, making it super difficult to reason about:

These little hiccups make selling a framework to your colleagues a little more difficult. So, I embarked on learning how to create a custom operator. My aim was to build an operator that could log file, function, line and Output. That has led to log — a very small OSLog-based operator.

It’s a small extension on Publisher which performs amap over the existing operator, logs out some useful information such as the file, line, function and the Self.Output of your current publisher. For network requests, this is the (data: Data, response: URLResponse). I’ve found that particularly useful for seeing what the URLResponse status code is, error, etc.

How do you use it?

Frustratingly, you do have to tack it onto your publisher streams at the point at which you wish to log. For my use case, that’s not too bad. We have a generic get<T: Decodable> method through which all our GET request go. As such, all our network requests get logged at a low cost:

Now, we can see precisely which network call failed, where, and why. Secondly, because it’s using OSLog, we’re able to pull that information off test devices and inspect failures that are happening in beta! When a device is connected, we can see the stream of logs too:

As you can see, it pulls out the get(request:)and we can view the output below. I’ve redacted a few bits for security reasons.



Joe Williams

iOS Engineer @ Sky Betting & Gaming | Indie Dev @ Expodition Podcast App