Logging is a really powerful way to debug code, especially if it’s asynchronous code that runs in a time sensitive way so stepping through the debugger is a pain.

In Simple custom Combine operators I wrote about how to create an operator that logs to the system Console app in just few lines.

After playing with Combine some more I went ahead and created a micro framework called “CombinePrintout” that adds few convenient methods to Combine allowing you to quickly print information about your subscriptions.

CombinePrintout

To use CombinePrintout in your Xcode project go to “File > Swift Packages > Add Package Dependency…” and enter the package URL:

https://github.com/combineopensource/CombinePrintout

The package allows you to easily print information about your subscriptions and cancellables.

Printing subscription info

Combine’s print() operator is pretty useful but while you’re debugging code sometimes you need to subscribe given publisher for the only purpose of printing what’s being emitted and when the publisher completes.

CombinePrintout adds a new subscriber called printSink(), which is … no surprise here … a sink that only prints all events to the console.

You use it like so:

1
2
Just(["One", "Two"])
  .printSink()

printSink() will subscribe the publisher and log all events like so:

1
2
Sink: output(["One", "Two"]) 
Sink: finished

If you are logging multiple subscriptions (especially if they run concurrently) you might want to use an identifier for each like so:

1
2
Just(["One", "Two"])
  .printSink(id: "Search subscription")

This will print the identifier alongside the rest of the output:

1
2
Sink: output(["One", "Two"]) Search subscription
Sink: finished Search subscription

Here’s an Xcode tip for when you are heavily logging in your code: Use the Xcode Console filter field to filter your app’s log in real time:

Printing cancellable info

Another API in CombinePrintout is printCancellable(). This method wraps a Cancellable and prints its life-cycle events.

This could help you figure the precise time when your subscription’s cancellable is created, cancelled, and released from memory.

You use it like so:

1
2
3
4
Just(["One", "Two"])
  .assign(to: \.model, on: self)
  .printCancellable()
  .store(in: &subscriptions)

Note that printCancellable() is not an operator that you call on your publisher. It instead is a method on Cancellable you get back from a subscriber like assign(to:on:) in the code above.

The result of printCancellable() is also an AnyCancellable so you can go on and store it in an [AnyCancellable] collection or a property somewhere.

The result in the console looks like this:

1
2
3
4
5
6
Cancellable: init 
... 
(self.subscriptions is released from memory)
...
Cancellable: cancel 
Cancellable: deinit 

Just like with printSink() you can add an id parameter to identify the logs in your Console.

And that’s a wrap - these are the two publicly available APIs in CombinePrintout. I hope they will help you along the way!

Where to go from here?

Grab the source or add the package as a dependency from the public repo on GitHub:

https://github.com/combineopensource/CombinePrintout

To learn more about debugging with Combine check out the debugging chapter in Combine: Asynchronous programming with Swift - this is where you can see all updates, discuss in the website forums, and more.