OSLogStore on Monterey
So, let’s start with some history:
macOS programs have been able to read log messages since the introduction of
OSLogStore
on macOS 10.15.This API is not available on iOS-based platforms.
In iOS 14 beta we added the OSLog framework to the iOS SDK, along with a new initialiser to
OSLogStore
that allowed iOS apps to read their own log messages.Unfortunately this feature didn’t work properly )-: and so it was removed very late in the iOS 14 beta cycle.
It’s now several months later and the feature has not returned (up to and including iOS 14.5b5).
I have no concrete info to share about when this feature will return; in fact, I can’t even confirm that it will return. What I can say is that the OSLog team are well aware of the demand for this feature from third-party developers.
Gaining access to the local unified logging system requires permission from the system. The caller must be run by an admin account and have the
com.apple.logging.local-store
entitlement.
This is good news / bad news story:
The bad news is that there’s no way for a third-party developer to get the
com.apple.logging.local-store
entitlement.The good news is that it’s not necessary: As long as you’re running as an admin user, you don’t need the entitlement.
The bad news is that this won’t work from within the App Sandox. AFAICT there’s no way for a third-party sandboxed app to access the log store.
As of iOS 15 and macOS Monterey,
OSLogStore
works just as expected. No entitlements or hacks needed. It works in the Simulator, on device, on macOS and macOS Catalyst. Try out the OSLogTest project here.
The local()
log store and .system
scope still don’t work in the sandbox. You’ll just get an error like:
Error Domain=OSLogErrorDomain Code=10 "Connection to logd failed" UserInfo={NSLocalizedDescription=Connection to logd failed, _OSLogErrorInternalCode=15}
From a sandboxed app, you can only use the .currentProcessIdentifier
scope. Not having access to the entire system log does make some sense for privacy reasons, but it really reduces the usefulness of OSLogStore
:
You can’t read log entries from other apps and system processes, which might relate to your app, for example if the two are interoperating.
You can’t read log entries from your app’s own helper processes.
You can’t even read log entries from a previous instance of your own app. So, if you detect that your app crashed the last time it ran, you can’t look up information in the log to try to figure out why. The pid has changed, so it’s already too late.
So, OSLogStore
offers a nicer API than /usr/bin/log
, but it is still very limited. In practice, I find that I still need to implement my own log persistence, which is too bad because in theory os_log
has already solved hard problems like:
Concurrency
Performance
Automatic expiration of older or less important log entries (rolling)
Storage of individual fields (not just a giant blob of plain text)
A portable archive format and tooling to go with it
And, since os_log
doesn’t have a pluggable backend, it needs to be isolated behind another layer in your app if you ever want to be able to access your own logs. Apple even has an open-source project for doing this.
SwiftLog (via Mattt Thompson):
This package only provides the logging API itself and therefore
SwiftLog
is a ‘logging API package’.SwiftLog
(usingLoggingSystem.bootstrap
) can be configured to choose any compatible logging backend implementation. This way packages can adopt the API and the application can choose any compatible logging backend implementation without requiring any changes from any of the libraries.
Previously:
- Dangerous NSLog() Calls in Swift
- iOS 14 Shipping Tomorrow, Xcode 12 GM
- Console, the Vital Tool That Apple Abandoned
- Problems With os_log
Update (2021-12-16): Saagar Jha:
It’s kind of weird that NSLog really hasn’t gotten a replacement at all for print debugging on Apple’s platforms. It just packs in so many of the right choices for this use case that everyone (myself included) finds themselves reaching for it all the time. Even from Swift!
[…]
Nobody is going to pull in a third party library or write a wrapper around something just for a debugging session, so the alternatives are what, print(f) and os_log? I use the former a bunch and the latter occasionally, but they often just aren’t what I need…
os_log is…cool, but cumbersome. You have to import a thing, then set up a logger, then you give it a static string, plus a category or whatever. And after all that work, it doesn’t even show up in Xcode! And in Console it’s redacted or at a low level so you don’t see it…
See also: Making os_log Public on macOS Catalina.