
This video is only available to subscribers. Start a subscription today to get access to this and 470 other videos.
Activity Tracing in Swift
This episode is part of a series: Unified Logging and Activity Tracing.
Special thanks to Zach Waldowski, who originally created the Activity
wrapper we use in this episode. Also thanks to Greg Heo, who helped me understand how dlsym
works with RTLD_DEFAULT
.
Episode Links
- Activity.swift - the os_activity wrapper that makes the framework accessible in Swift
Using the Activity wrapper
let activity = Activity("Complex Work")
activity.apply {
os_log("Starting some work...", log: log, type: .info)
DispatchQueue.global(qos: .background).async {
os_log("Work started...", log: self.log, type: .info)
self.doStuff()
}
}
Entering and leaving activities
let scope = waterActivity.enter()
defer {
scope.leave()
}
Implementing os_activity directly using C-interop
First, we load the symbol dynamically, since it is not exposed to Swift...
// see activity.h and dlfcn.h
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
let sym = dlsym(RTLD_DEFAULT, "_os_activity_current")
let OS_ACTIVITY_CURRENT = unsafeBitCast(sym, to: os_activity_t.self)
Then we get a handle to our dynamic shared object, which we need to make mutable:
let dso = UnsafeMutableRawPointer(mutating: #dsohandle)
For our description, we need to translate this into the pointer type that the method expects. This involves some acrobatics.
let desc: StaticString = "My Custom Activity"
desc.withUTF8Buffer { buffer in
if let address = buffer.baseAddress {
let descriptionBuffer = UnsafeRawPointer(address).assumingMemoryBound(to: Int8.self)
// ...
}
}
Finally we can create our activity and apply a block to it.
let activity = _os_activity_create(dso, descriptionBuffer, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT)
os_activity_apply(activity, {
os_log("Logging from my custom activity", log: self.log, type: .info)
})