OSLog is a unified logging system for the reading of historical data.

OSLog Documentation

Pinned Posts

Posts under OSLog tag

60 Posts
Sort by:
Post not yet marked as solved
29 Replies
32k Views
I have a Swift 3 Cocoa application that uses Apple's Unified Logging, like this: - import os class MyClass { @available(OSX 10.12, *) static let scribe = OSLog(subsystem: "com.mycompany.myapp", category: "myapp") func SomeFunction(){ if #available(OSX 10.12, *){ os_log("Test Error Message", log: MyClass.scribe, type: .error) } if #available(OSX 10.12, *){ os_log("Test Info Message", log: MyClass.scribe, type: .info) } if #available(OSX 10.12, *){ os_log("Test Debug Message", log: MyClass.scribe, type: .debug) } } }Within the Console application, both Include Info Messages and Include Debug Messages are turned on.When os_log is called, only the error type message is visible in the Console application.Using Terminal, with the command, all message types are visible in the Terminal output: -sudo log stream --level debugI've tried running the Console app as root, via sudo from the command line and the same issue occurs; no debug or info messages can be seen, even though they're set to being turned on under the Action menu.Setting system-wide logging to be debug, has no effect on the Console application output:sudo log config --mode level:debugPlease can someone tell me what I'm missing and how can I view debug and info messages in the Console application?
Posted
by
Post not yet marked as solved
4 Replies
968 Views
In my sandboxed MacOS app I want to access OSLogStore programmatically to fetch logs for multi-component application (app, libraries, deriver) for further analysis. According to the documentation, - https://developer.apple.com/documentation/oslog/oslogstore/3366102-local the app should have com.apple.logging.local-storeentitlement. I have added this entitlement "by hand" to the entitlement file as I I can't find a correspondent entry in the Xcode -> Sign & Capabilities interface. When I run the app, I get Unsatisfied entitlements: com.apple.logging.local-store error and the app doesn't start. If I remove the entitlement, the app can't get access to the logd subsystem. How can I add com.apple.logging.local-store to my app? Should I request this not visible via Xcode configuration UI from apple? Thanks!
Posted
by
Post not yet marked as solved
7 Replies
3k Views
I understand that in iOS 15 and macOS Monterey, I can easily access the log system to get log entries for my app like this: let store = try OSLogStore(scope: .currentProcessIdentifier) I can then query store for the log entries. However, as it says right in the name, the store is only for current process, i.e current run of my app. When I try to get entries, I only get entries from the current run, even if I specify an earlier time like this: guard let positionDate = Calendar.current.date(byAdding: .day, value: -7, to: Date()) else { return } let position = store.position(date: positionDate) let predicate = NSPredicate(format: "subsystem == 'com.exampl.emyAppSubsystem'") let entries = try store.getEntries(with: [], at: position, matching: predicate) for entry in entries { print("Entry: \(entry.date) \(entry.composedMessage)") } Is there any way to access log entries for earlier runs of my app, e.g from days or weeks ago? Either on macOS or iOS?
Posted
by
Post not yet marked as solved
0 Replies
5.2k Views
The unified system log on Apple platforms gets a lot of stick for being ‘too verbose’. I understand that perspective: If you’re used to a traditional Unix-y system log, you might expect to learn something about an issue by manually looking through the log, and the unified system log is way too chatty for that. However, that’s a small price to pay for all its other benefits. This post is my attempt to explain those benefits, broken up into a series of short bullets. Hopefully, by the end, you’ll understand why I’m best friends with the system log, and why you should be too! If you have questions or comments about this, start a new thread and tag it with OSLog so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Your Friend the System Log Apple’s unified system log is very powerful. If you’re writing code for any Apple platform, and especially if you’re working on low-level code, it pays to become friends with the system log! The Benefits of Having a Such Good Friend The public API for logging is fast and full-featured. And it’s particularly nice in Swift. Logging is fast enough to leave log points [1] enabled in your release build, which makes it easier to debug issues that only show up in the field. The system log is used extensively by the OS itself, allowing you to correlate your log entries with the internal state of the system. Log entries persist for a long time, allowing you to investigate an issue that originated well before you noticed it. Log entries are classified by subsystem, category, and type. Each type has a default disposition, which determines whether that log entry is enable and, if it is, whether it persists in the log store. You can customise this, based on the subsystem, category, and type, in four different ways: Install a configuration profile created by Apple (all platforms). Add an OSLogPreferences property to your app’s Info.plist (all platforms). Run the log tool with the config command (macOS only) Create and install a custom configuration profile with the com.apple.system.logging payload (macOS only). When you log a value, you may tag it as private. These values are omitted from the log by default but you can configure the system to include them. For information on how to do that, see Recording Private Data in the System Log. The Console app displays the system log. On the left, select either your local Mac or an attached iOS device. Console can open and work with log snapshots (.logarchive). It also supports surprisingly sophisticated searching. For instructions on how to set up your search, choose Help > Console Help. Console’s search field supports copy and paste. For example, to set up a search for the subsystem com.foo.bar, paste subsystem:com.foo.bar into the field. Console supports saved searches. Again, Console Help has the details. Console supports viewing log entries in a specific timeframe. By default it shows the last 5 minutes. To change this, select an item in the Showing popup menu in the pane divider. If you have a specific time range of interest, select Custom, enter that range, and click Apply. Instruments has os_log and os_signpost instruments that record log entries in your trace. Use this to correlate the output of other instruments with log points in your code. Instruments can also import a log snapshot. Drop a .logarchive file on to Instruments and it’ll import the log into a trace document, then analyse the log with Instruments’ many cool features. The log command-line tool lets you do all of this and more from Terminal. There’s a public API to read back existing log entries, albeit one with significant limitations on iOS (more on that below). Every sysdiagnose log includes a snapshot of the system log, which is ideal for debugging hard-to-reproduce problems. For more details on that, see Using a Sysdiagnose Log to Debug a Hard-to-Reproduce Problem. For general information about sysdiagnose logs, see Bug Reporting > Profiles and Logs. But you don’t have to use sysdiagnose logs. To create a quick snapshot of the system log, run the log tool with the collect subcommand. If you’re investigating recent events, use the --last argument to limit its scope. For example, the following creates a snapshot of log entries from the last 5 minutes: % sudo log collect --last 5m For more information, see: os > Logging OSLog log man page os_log man page (in section 3) os_log man page (in section 5) WWDC 2016 Session 721 Unified Logging and Activity Tracing [1] Well, most log points. If you’re logging thousands of entries per second, the very small overhead for these disabled log points add up. Foster Your Friendship Good friendships take some work on your part, and your friendship with the system log is no exception. Follow these suggestions for getting the most out of the system log. The system log has many friends, and it tries to love them the all equally. Don’t abuse that by logging too much. One key benefit of the system log is that log entries persist for a long time, allowing you to debug issues with their roots in the distant past. But there’s a trade off here: The more you log, the shorter the log window, and the harder it is to debug such problems. Put some thought into your subsystem and category choices. One trick here is to use the same category across multiple subsystems, allowing you to track issues as they cross between subsystems in your product. Or use one subsystem with multiple categories, so you can search on the subsystem to see all your logging and then focus on specific categories when you need to. Don’t use too many unique subsystem and context pairs. As a rough guide: One is fine, ten is OK, 100 is too much. Choose your log types wisely. The documentation for each OSLogType value describes the default behaviour of that value; use that information to guide your choices. Remember that disabled log points have a very low cost. It’s fine to leave chatty logging in your product if it’s disabled by default. No Friend Is Perfect The system log API is hard to wrap. The system log is so efficient because it’s deeply integrated with the compiler. If you wrap the system log API, you undermine that efficiency. For example, a wrapper like this is very inefficient: -*-*-*-*-*- DO NOT DO THIS -*-*-*-*-*- void myLog(const char * format, ...) { va_list ap; va_start(ap, format); char * str = NULL; vasprintf(&str, format, ap); os_log_debug(sLog, "%s", str); free(str); va_end(ap); } -*-*-*-*-*- DO NOT DO THIS -*-*-*-*-*- This is mostly an issue with the C API, because the modern Swift API is nice enough that you rarely need to wrap it. If you do wrap the C API, use a macro and have that pass the arguments through to the underlying os_log_xyz macro. iOS has very limited facilities for reading the system log. Currently, an iOS app can only read entries created by that specific process, using .currentProcessIdentifier scope. This is annoying if, say, the app crashed and you want to know what it was doing before the crash. What you need is a way to get all log entries written by your app (r. 57880434). There are two known bugs with the .currentProcessIdentifier scope. The first is that the .reverse option doesn’t work (r. 87622922). You always get log entries in forward order. The second is that the getEntries(with:at:matching:) method doesn’t honour its position argument (r. 87416514). You always get all available log entries. Xcode 15 beta has a shiny new console interface. For the details, watch WWDC 2023 Session 10226 Debug with structured logging. For some other notes about this change, search the Xcode 15 Beta Release Notes for 109380695. In older versions of Xcode the console pane was not a system log client (r. 32863680). Rather, it just collected and displayed stdout and stderr from your process. This approach had a number of consequences: The system log does not, by default, log to stderr. Xcode enabled this by setting an environment variable, OS_ACTIVITY_DT_MODE. The existence and behaviour of this environment variable is an implementation detail and not something that you should rely on. Xcode sets this environment variable when you run your program from Xcode (Product > Run). It can’t set it when you attach to a running process (Debug > Attach to Process). Xcode’s Console pane does not support the sophisticated filtering you’d expect in a system log client. When I can’t use Xcode 15, I work around the last two by ignoring the console pane and instead running Console and viewing my log entries there. If you don’t see the expected log entries in Console, make sure that you have Action > Include Info Messages and Action > Include Debug Messages enabled. The system log interface is available within the kernel but it has some serious limitations. Here’s the ones that I’m aware of: This is no subsystem or category support )-: There is no support for annotations like {public} and {private}. Adding such annotations causes the log entry to be dropped (r. 40636781). Revision History 2023-10-20 Added some Instruments tidbits. 2023-10-13 Described a second known bug with the .currentProcessIdentifier scope. Added a link to Using a Sysdiagnose Log to Debug a Hard-to-Reproduce Problem. 2023-08-28 Described a known bug with the .reverse option in .currentProcessIdentifier scope. 2023-06-12 Added a call-out to the Xcode 15 Beta Release Notes. 2023-06-06 Updated to reference WWDC 2023 Session 10226. Added some notes about the kernel’s system log support. 2023-03-22 Made some minor editorial changes. 2023-03-13 Reworked the Xcode discussion to mention OS_ACTIVITY_DT_MODE. 2022-10-26 Called out the Showing popup in Console and the --last argument to log collect. 2022-10-06 Added a link WWDC 2016 Session 721 Unified Logging and Activity Tracing. 2022-08-19 Add a link to Recording Private Data in the System Log. 2022-08-11 Added a bunch of hints and tips. 2022-06-23 Added the Foster Your Friendship section. Made other editorial changes. 2022-05-12 First posted.
Posted
by
Post not yet marked as solved
0 Replies
2.2k Views
I’ve discussed all of the following on DevForums before, but scattered across multiple threads. The issue of system log private data recently came up in another context and I decided to collect my thoughts in one place. If you have any questions or comments, start a new thread and tag it with OSLog so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Recording Private Data in the System Log The unified system log on Apple platforms is a Thing of Wonder™. If you’re not convinced, go read Your Friend the System Log. One great feature of the system log is private data: If you tag a value as private, it’s omitted from the log by default. This keep personal information out the log, which is obviously a good thing. In some circumstances it makes sense to record private data. Imagine, for example, that you’re investigating a Gatekeeper problem on macOS and you see a log entry like this: type: info time: 2022-05-12 05:53:35.896830 -0700 process: XprotectService subsystem: com.apple.xprotect category: xprotect message: SecAssessment results: <private> (null) That looks interesting, but the assessment result, the thing that you really want to see, was omitted. Now look at the same log entry with the private data enabled: type: info time: 2022-05-12 05:55:21.673682 -0700 process: XprotectService subsystem: com.apple.xprotect category: xprotect message: SecAssessment results: { "assessment:authority" = { LSDownloadRiskCategoryKey = LSRiskCategoryMayContainUnsafeExecutable; "assessment:authority:flags" = 0; "assessment:authority:source" = "_XProtect"; }; "assessment:remote" = 1; "assessment:verdict" = 1; } (null) That’s much more helpful. There are two ways to enable recording of private data in the system log: Add an OSLogPreferences property in your app’s profile (all platforms). Create and install a custom configuration profile with the SystemLogging (com.apple.system.logging) payload (macOS only). WARNING Do not enable the recording of private data on a system you care about. Log entries are often tagged as private for a good reason. You don’t want them ending up in your system log! This is critically important when installing a configuration profile. Personally, I only do that on a ‘victim’ machine, one that doesn’t have any of my personal info and that I can erase when I’m done (typically a VM). Log Preferences Property Imagine an app with this code: let log = Logger(subsystem: "com.example.apple-samplecode.PrivateValueLogger", category: "app") let client: String = … log.debug("will answer the ultimate question, client: \(client)") let answer: Int = … lots of work … log.debug("did answer the ultimate question, answer: \(answer, privacy: .private)") Note This uses the Logger API in Swift but the same logic applies to all system log APIs. With this code both the client and answer values are considered private data, the first because that’s the default for strings and the second because it’s explicitly called out as private. And if you run the app outside of Xcode you’ll see that this private data is omitted: type: debug time: 16:55:23.994070+0100 process: PrivateValueLogger subsystem: com.example.apple-samplecode.PrivateValueLogger category: app message: will answer the ultimate question, client: <private> type: debug time: 16:55:23.994108+0100 process: PrivateValueLogger subsystem: com.example.apple-samplecode.PrivateValueLogger category: app message: did answer the ultimate question, answer: <private> Note When you use Xcode to run the app, it sets an environment variable, OS_ACTIVITY_DT_MODE, that changes the default handling of log entries. To record this private data, add the following to the app’s Info.plist file: <key>OSLogPreferences</key> <dict> <key>com.example.apple-samplecode.PrivateValueLogger</key> <dict> <key>app</key> <dict> <key>Enable-Private-Data</key> <true/> </dict> </dict> </dict> Now the private data is recorded in the log: … message: will answer the ultimate question, client: The Mice … message: did answer the ultimate question, answer: 42 This might not seem like a big deal — if you’re going to rebuild the app, you could just as easily change the code to log the values as public — but it has some important benefits: You only have to make this change in one place. If your app has lots of log points, this change affects them all. It works for code that you don’t control. If you need to record private data for library code running in your process, including system frameworks, you can do just that. It works on both macOS and iOS. Configuration Profile macOS has an extra trick up its sleeve, namely, the SystemLogging configuration profile payload (com.apple.system.logging). Use this to enable private data without modifying your code. For example, here’s an outline of a configuration profile that enables private data for the code shown earlier: … <dict> <key>PayloadContent</key> <array> <dict> … <key>PayloadType</key> <string>com.apple.system.logging</string> … <key>Subsystems</key> <dict> <key>com.example.apple-samplecode.PrivateValueLogger</key> <dict> <key>app</key> <dict> <key>Enable-Private-Data</key> <true/> </dict> </dict> </dict> </dict> </array> … </dict> </plist> Critically, this applies not just to your app but to all logging on the system. Continuing the Gatekeeper example from earlier, to see the assessment result, create a profile to enable private data for the com.apple.xprotect subsystem and the xprotect category. For detailed information on constructing a configuration profile, see Device Management. To get a head start with that, use Apple Configurator to create profile with a dummy payload and then use a text editor to modify that payload along the lines shown above. Revision History 2023-06-10 Added a warning about the risks of recording private data. 2022-05-12 First posted.
Posted
by
Post not yet marked as solved
9 Replies
2.1k Views
I have os_log statements in my app. With my phone connected to the Mac, when I run the app through XCode, open Console app, those logs are shown. However, when I'm launching the app on its own, those logs don't appear in Console (phone still connected). Am I missing something very basic? Please help.
Posted
by
Post marked as solved
10 Replies
1.9k Views
I wanted to try structured logging with os_log in C++, but I found that it fails to print anything given a format string and a variable: eg. void example(std::string& str) { os_log_info(OS_LOG_DEFAULT, "%s", str.c_str()); os_log_debug(OS_LOG_DEFAULT, "%s", str.c_str()); os_log_error(OS_LOG_DEFAULT, "%s", str.c_str()); } This prints a blank row in the console, but with no text. How is this meant to work with variables? It only works with literals and constants now as far as I can tell. I'm looking forward to getting this working.
Posted
by
Post not yet marked as solved
3 Replies
976 Views
Hi, I'm currently developing Apple Pay In-App Provisioning and have encountered an issue with viewing logs necessary for debugging. I've followed the instructions listed in https://download.developer.apple.com/iOS/iOS_Logs/Wallet_Logging_Instructions.pdf and have installed the relevant wallet profile. After repeating the issue, and opening up the sysdiagnose file on my mac, the logs that i'm interested in is still hidden with private tags. The device I'm using to develop on is an iPhone 11, runnning on iOS 16.5. The version of Xcode is 14.3. I am also using a sandbox account on the device if that is relevant to the issue. Below are screenshots of the logs I'm interested in. Any help in solving this issue will be greatly appreciated.
Posted
by
Post not yet marked as solved
4 Replies
1.1k Views
Hi. I want to use OSLog. It is working as expected inside my controller. I can view all details in the console and can use "jump to source" and it jumps to the source code :) NICE If I call this inside a package in side a static func like this Package Example: import OSLog class A { static func testLog(meesage: String) { Logger(subsystem: "Test", category: "console").info("\(message)") } } I can the message inside the console but "Jump to soure" is not working. Only a ? appears on screen. Did I miss anything ?
Posted
by
Post not yet marked as solved
1 Replies
782 Views
Hi, I'm currently working on exporting logs from a user's phone. Let's say I want to include an option in the settings that allows the user to retrieve all logs recorded via Logger. I've found that it's possible to use OSLogStore to get logs recorded via Logger. It has initializer with the scope of the current process identifier OSLogStore(scope: .currentProcessIdentifier). This method works fine until the app is killed or crashes. How can I retrieve the persistent logs in a manner similar to the log collect command? We need to access logs from when the app was killed or crashed, and we don't have direct access to the user's phone.
Posted
by
Post not yet marked as solved
1 Replies
714 Views
OSLog’s structured logging is nice, but the output length is limited compared with stdio’s. Currently, it looks like if I expect long variable-length print-outs, I’m forced to revert to using stdio. —or is this just an Xcode 15 beta 2 bug (discussed in the release notes) and fixed versions will match what stdio gives me? If not, could there be a way to configure oslog to fall-back to stdio dynamicallty based on whether the printout is too long or not? A custom fallback buffer allocator? Alternatively, what if I could still get the structured logging with the metadata, and use stdio for the rest of the message that doesn’t fit? That would be a nice way to guarantee that you get structured logging info without dropping the entire message.
Posted
by
Post not yet marked as solved
1 Replies
437 Views
I've got a complex app extension and I'd like to be able to combine the logging from the app and the extension into a single file (for extraction/uploading etc.) I experimented adding the following code to both the app and the extension i.e. using the same subsystem for both app and extension logging. let subsystem = "mySubsystem" let logger = Logger(subsystem: subsystem, category: "main") logger.info("Log from within extension") // the version in the app says Log from within app do { let logStore = try OSLogStore(scope: .currentProcessIdentifier) let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600)) let allEntries = try logStore.getEntries(at: oneHourAgo) let filtered = allEntries .compactMap { $0 as? OSLogEntryLog } .filter { $0.subsystem == subsystem } } The filtered content only contains logging from either the app or the extension. I suppose the issue might be the use of .currentProcessIdentifier as the scope, however that's the only scope that is defined. Is what is being attempted here possible? Is there any way to write to and extract a unified log for an app and app extension? If not, how about adding it, surely this would be something useful for people to be able to do
Posted
by
Post not yet marked as solved
1 Replies
1.5k Views
I'm assuming it's possible to stream the device log to a file, any clues? I'm trying to debug an app installation issue I am having with iOS 17, and hunting through the Console log is just super noisy. I want to just attach the log so I can hand it over to my developers on the team, but I don't seem to be seeing a way to save the Console log I am looking at in Xcode. Basically I'm looking for the equivalent of an adb shell logcat +pipe to storage that Is not that hard to do on an Android. By any means possible? I've not even tried using LLDB, will it let me do this, if so any clues where to start?
Posted
by
Post not yet marked as solved
1 Replies
383 Views
Hello Folks, I am simply trying to learn to take client-side logs using Xcode or any easy-to-use tools. Please help. That way I can figure out if the issue is on the client side or not. For the server side, I use Charles proxy and I know how to use that. Any help is appreciated!
Posted
by
Post marked as solved
3 Replies
730 Views
When running the code below, only the first entry gets logged. Structured logging seems not to work when there are emoticons or object descriptions in the message. Is this by design? let logger = Logger(subsystem: "TestSystem", category: "TestCategory") logger.log("👍") // Result = 👍 let someEmoji:String = "👎" logger.log("\(someEmoji)") // Result = empty log line let someObjectDescription:String = String(describing:self) logger.log("\(someObjectDescription)") // Result = empty log line
Posted
by
Post not yet marked as solved
1 Replies
317 Views
I'm experimenting with the (relatively) new Logger API after watching WWDC20 session "Explore logging in Swift", and I don't see a default reduction of the values that was discussed in the talk. When I run this code, let i = A(a: "aaaa", b: 111) logger.error("Password: \(i)") // privacy: .auto logger.error("Password: \(i, privacy: .public)") logger.error("Password: \(i, privacy: .private)") logger.error("Password: \(i, privacy: .private(mask: .none))") logger.error("Password: \(i, privacy: .private(mask: .hash))") I get this output in both Xcode console and Console.app: 2023-08-20 22:55:57.373918+0300 MyApp[75828:757479] [MyCategory] Password: a: aaaa, b: 111 2023-08-20 22:55:57.373988+0300 MyApp[75828:757479] [MyCategory] Password: a: aaaa, b: 111 2023-08-20 22:55:57.374014+0300 MyApp[75828:757479] [MyCategory] Password: a: aaaa, b: 111 2023-08-20 22:55:57.374032+0300 MyApp[75828:757479] [MyCategory] Password: a: aaaa, b: 111 2023-08-20 22:55:57.374055+0300 MyApp[75828:757479] [MyCategory] Password: a: aaaa, b: 111 My assumption is that when running the code from Xcode with debug build configuration the system generously opens up any private values so I can inspect them conveniently. But when I ran my code with the release config, I got the same output. However, I want to test what data will be stored on my users' devices when I write different privacy options Any ideas why this happens?
Posted
by
Post marked as solved
2 Replies
397 Views
Hi, I'm on MacBook Pro M2, macOS 13.3.1. I'm writing a feature that need to run before login. After some research I found PreLoginAgents sample code: https://developer.apple.com/library/archive/samplecode/PreLoginAgents/Introduction/Intro.html Followed README, installed pre-built agent and SSH to Macbook, then run: sudo syslog -c 0 -i syslog -w volia! SSH prints agent log, it is working. But if I build code with XCode, there is no log. I tried following changes with no luck: change LogManager acl log to os_log_info(OS_LOG_DEFAULT, "%s", [str UTF8String]), no log change to syslog(LOG_INFO, "%s", [str UTF8String]), has log! But change min deploy target from 10.9 to 11.0, syslog print no log What is the proper way to print PreLoginAgents log? Thanks!
Posted
by
Post marked as solved
3 Replies
1.1k Views
Hi there! Sorry in advance, this is going to be a long post of Apple developer pains which I want to share with you, and, hopefully, find the answer and help Apple become better. I'm at the very beginning of my new and exciting personal project which (I hope) may one day feed me and be my daily source of inspiration. I'm not a newbie in Apple development nor am I a senior-level developer — just a fellow developa'. Here's the problem I bring to you — why Apple promotes Unified Logging System and recommends using it as the primary way to implement logging in 3rd-party apps? No doubt, OSLog is a great, secure, efficient, and centralized way to gather diagnostics information, and I, starting my new project, am itching to choose exactly this 1st-party logging infrastructure. This decision in theory has a number of benefits: I don't have to depend on 3rd-party logging frameworks which may eventually be discontinued; I have extensive documentation, great WWDC sessions explaining how to use the framework, and stackoverflow answers from the whole Apple dev community in case I experience any troubles; I have this cool Console.app and upcoming Xcode 15 tools with great visualization and filtering of my logs; It's quite a robust and stable infrastructure which I may restfully rely on. But... the thing is there's this big elephant in the room — this API is non-customizable, inconvenient, and hard to use in terms of the app architecture. I can't write my own protocol wrapper around it to abstract my domain logic from implementation details or just simplify the usage at the call site. I can't configure my own format for log messages (this is debatable, since Console.app doesn't provide "***** strings" as Xcode 14 and earlier, but still). And what's most important — I can't conveniently retrieve the logs! I can't implement the functionality where my user just taps the button, and the logs are sent on the background queue to my support email (eskimo's answer). They would have to go through this monstrous procedure of holding volume buttons on the iPhone, connecting their device to the Mac, gathering sysdiagnose, entering some weird Terminal commands (jeez, these nerdy developers...), etc. If it ever succeeds, of course, and something doesn't go wrong, leaving my user angry and dissatisfied with my app. Regarding the protocol wrapper, I can't do something like this: protocol Logging { var logger: Logger { get } func info(_ message: OSLogMessage) } extension Logging { var logger: Logger { return Logger( subsystem: "com.my.bundle.id", category: String(describing: Self.self) ) } func info(_ message: OSLogMessage) { logger.info(message) } } class MyClass: Logging { func someImportantMethod() { // ... self.info("Some useful debug info: \(someVar, privacy: .public)") } } I've been investigating this topic for 2 days, and it's the farthest I want to go in beating my head over how to do two simple things: How to isolate logging framework implementation decision from my main code and write convenience wrappers? How to easily transfer the log files from the user to the developer? And I'm not the only one struggling. Here's just one example among hundreds of other questions that are being asked on dev forums: https://www.hackingwithswift.com/forums/ios/unified-logging-system-retrieve-logs-on-device/838. I've read almost all Apple docs which describe the modern Unified Logging System, I've read through eskimo's thread on Apple Developer Forum about the API, but I still haven't found the answer. Maybe, I've misperceived this framework and it's not the tool I'm searching for? Maybe, it focuses on different aspects of logging, e.g. signposting, rather than logging the current state of the app? What am I missing?
Posted
by
Post not yet marked as solved
2 Replies
433 Views
Note: I have read the Your Friend The System Log post, which was very helpful - thanks! I have a follow-up question. I have added support in our app for reading the log messages via OSLogStore. However, as you mention, the Debug and Info level messages do not show up when we read messages when not connected to a debugger. You mention two ways on iOS to change this configuration: Install a configuration profile created by Apple (all platforms). I assume all of these only work for the "com.apple.*" subsystems, correct? So this won't really work for 3rd-party apps like mine. Is this correct? Add an OSLogPreferences property to your app’s Info.plist (all platforms). Is there any official documentation for the OSLogPreferences Info.plist key? I was not able to find any. Does the value of "OSLogPreferences" follow the same dictionary structure described here? Thanks! Eric
Posted
by