Apple introduced Activity Tracing to support debugging asynchronous code. I have some difficulties using it properly. My example scenario is a small MacOS app just downloading a file:
- (IBAction)actionDownload:(NSButton *)sender {
os_activity_label_useraction("actionDownload");
os_log_t logDemo = os_log_create("ActivityTracingDemo", "demo");
os_log_debug(logDemo, "actionDownload start (1)");
os_activity_t actTop = os_activity_create(
"HTTP Download",
OS_ACTIVITY_NONE,
OS_ACTIVITY_FLAG_DETACHED);
os_activity_apply(actTop, ^{
os_log_debug(logDemo, "actionDownload start");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(2 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
os_log_debug(logDemo,
"actionDownload two second later");
});
NSURL *url = [NSURL URLWithString:
@"https://www.google.de/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"];
// Get the current activity (or create a new one,
// if no current activity exists):
os_activity_t act = os_activity_create(
"HTTP Response",
OS_ACTIVITY_CURRENT,
OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
NSURLSessionDownloadTask *downloadPhotoTask =
[ [NSURLSession sharedSession]
downloadTaskWithURL:url
completionHandler:^(NSURL *location,
NSURLResponse *response,
NSError *error)
{
os_activity_apply(act, ^{
// Now the same activity is active,
// that initiated the download.
os_log_debug(logDemo, "actionDownload received data (restored activity)");
});
os_log_debug(logDemo, "actionDownload received data");
}];
[downloadPhotoTask resume];
});
}
Filtering for my messages in Console.app
I am getting:
Obviously NSURLSession
does not call the completionHandler
with the same activity active that initiated the download. I had to manually apply that activity within the callback. Is there a better way to do this? I thought that activities are designed to trace things across process. In that case it is not even working inside the same process without doing some extra work.
In the activity view of the Console.app
I am getting:
The tree view looks promising, to get a quick overview about what application scenarios are triggered. Initially I thought that it is not
necessary to apply a new activity in an action callback and instead it would be possible to use os_activity_label_useraction
to get the scenario displayed in Console.app
activity view on top level. Obviously that's not the case. I can't find that label in any log.
My solution is to create a new detached activity in actionDownload
. This activity is visible on top level in the Console.app
activity view. What I dislike with this solution are two things:
First, I had to explicitly create a new activity with a new scope. This adds lots of noise to the source code. I have many very short action methods in my project. Also the messages view works without this. There I am just getting what I am interested in by filtering for subsystem, category and activity id.
Second, the connection to the initiating activity gets lost.
Would be great to get some hints about how to properly use Activity Tracing and especially the hierarchy thingy.