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

OSLog Documentation

Pinned Posts

Posts under OSLog tag

61 Posts
Sort by:
Post not yet marked as solved
0 Replies
344 Views
Love the new console. but every time I open a new tab, it clear the console filter. I have some info level log that is from Bluetooth and other. I want to collect those logs but I don't want those in the Console. How can I keep the filter as copied to new window tab, like the search panel.
Posted
by yuyubox.
Last updated
.
Post not yet marked as solved
0 Replies
407 Views
Our application (which happens to run in an admin account, thus there's no problem authenticating) collects logs calling /usr/bin/log through NSTask. Usually this works all right, but sometimes all we get is the header Timestamp Thread Type Activity PID TTL and nothing else. The tool finishes with a zero result code, we get nothing on stderr and just the header above on stdout, with a proper EOF (as determined by a zero-length availableData read from an NSFileHandle through the stdout pipe). At the same moment, if the /usr/bin/log tool is run manually in a Terminal window with precisely the same arguments in the same user account the application runs in, we get the logs all right. Any idea what might be the culprit and how to fix the problem? Thanks!
Posted
by OC_s.
Last updated
.
Post marked as solved
1 Replies
410 Views
I am trying to wrap os_log for logging in my iOS app like so: import Foundation import OSLog enum LogCategory: String, CaseIterable { case viewCycle case tracking case api } struct Log { private static let logs = { return LogCategory.allCases .reduce(into: [LogCategory: OSLog]()) { dict, category in dict[category] = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "BIMB", category: category.rawValue) } }() static func debug(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .debug, args) } static func info(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .info, args) } static func notice(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .default, args) } static func warning(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .default, args) } static func error(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .error, args) } static func critical(category: LogCategory, message: StaticString, _ args: CVarArg...) { logImpl(category: category, message: message, type: .fault, args) } private static func logImpl(category: LogCategory, message: StaticString, type: OSLogType, _ args: CVarArg...) { guard let log = logs[category] else { return } os_log(message, log: log, type: type, args) } } The problem is if I did this: Log.debug(category: .tracking, message: "Device ID: %s.", UIDevice.current.identifierForVendor?.uuidString ?? "unknown") it always crashed with this error: 2023-12-13 12:33:35.173798+0700 bimb-authenticate-ios[62740:928633] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Swift.__SwiftDeferredNSArray UTF8String]: unrecognized selector sent to instance 0x600000dcbbc0' But if I just do it with os_log like this: os_log("Device ID: %s.", log: OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "tracking"), type: .debug, UIDevice.current.identifierForVendor?.uuidString ?? "unknown") it worked fine. Also if I changed %@ in my wrapper instead, it didn't crash, but the idfv is shown inside a pair of brackets like this: Device ID: ( "C0F906C8-CD73-44F6-86A1-A587248680D3" ).` But with os_log it is shown normally like this: Device ID: C0F906C8-CD73-44F6-86A1-A587248680D3. Can you tell me what's wrong here? And how do I fix this? Thanks. NOTE: This is using os_log since the minimum version is iOS 11. I don't know why people advising me with using Logger instead.
Posted Last updated
.
Post not yet marked as solved
1 Replies
499 Views
For awhile I've wrapped OSLog in my own macros to include the line number and source file the logging statement originates from in debug mode because OSLog didn't include that info in console output (until recently). Now I noticed the source code file and line number of the logging statement isn't being shown (I have all the metadata switches turned on in Xcode's console "Metadata Options" popover). Then I realized it is being shown, only on mouse hover over the logging statement in very tiny text. The text is barely readable (on mouse hover). Why would viewing the line number require me to move the mouse cursor over a logging statement? It doesn't look pretty at all (hiding information behind mouse hover) and even if it did look pretty, this is the console for programmers and we don't care about such nonsense.
Posted Last updated
.
Post not yet marked as solved
6 Replies
1.2k Views
I'm finding that in Xcode 15, NSLog statements (from Objective-C, in this case) will sometimes appear in Xcode's Console and sometimes will not. This is making it difficult to debug using our existing logging, which for our REST API requests and responses has been working well for about ten years and is a tough thing to lose. Is there any way I can restore reliable handling of NSLog in Xcode 15's Console without having to rewrite all (over 200) of our uses of NSLog to use OSLog? Note: I am aware that Xcode 15's Console sometimes takes more than 30 seconds to start tracking app output, but it appears that in some cases the content of individual NSLog statements never will appear. (If this 30 second delay is news to anyone, it may be related to a spam of identical warnings that are okay which occur on launch of our app. I have suspected that Xcode 15 just gets a bit flustered with identical messages and gives up for a bit.) Thank you!
Posted
by FL340.
Last updated
.
Post not yet marked as solved
3 Replies
419 Views
I have created an iOS .ipa file to run some tests, and all the test cases have os_log implemented for tracing. However, there is an issue; my tests take over 20 seconds to run, and the screen starts to dim. Consequently, the execution stops. Once I reactivate the screen, the tests resume. I added [UIApplication.sharedApplication setIdleTimerDisabled:YES]; to the code, but it doesn't resolve the problem. I've used os_log to trace all the test case results. I wonder if it's possible to display all the os_log messages from runTest on the app main screen as well. int main(int argc, char** argv) { //Separate thread to runTest, os_log implemented there std::thread thread_obj(runTests, argc, argv); int applicationReturn; @autoreleasepool { [UIApplication.sharedApplication setIdleTimerDisabled:YES]; applicationReturn = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } thread_obj.join(); [UIApplication.sharedApplication setIdleTimerDisabled:NO]; return applicationReturn; }
Posted
by ken123.
Last updated
.
Post marked as solved
4 Replies
592 Views
Lately, I've switched from NSLog to the new os_log. My problem is, whatever I try, I can't see the private values in my 13.6 (22G120). My test line is trivial os_log(OS_LOG_DEFAULT,"private shown: %@", [NSString stringWithFormat:@"OK"]); and it prints (both in Xcode and in Console) private shown: <private> I did install in Settings the appropriate profile (as found here, copied down, changed just my company info) — in vain, it did not help, not even after restarting my computer. For the record, the profile is shown below. Can anybody see what am I doing wrong and why it does not work? Thanks! <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>ConsentText</key> <dict> <key>default</key> <string>This will enable showing private strings and data in Unified Logs.</string> </dict> <key>PayloadContent</key> <array> <dict> <key>PayloadDisplayName</key> <string>ManagedClient logging</string> <key>PayloadEnabled</key> <true/> <key>PayloadIdentifier</key> <string>com.apple.system.logging.89AE58D8-0A4A-448B-8AE0-761DEE2D007F</string> <key>PayloadType</key> <string>com.apple.system.logging</string> <key>PayloadUUID</key> <string>89AE58D8-0A4A-448B-8AE0-761DEE2D007F</string> <key>PayloadVersion</key> <integer>1</integer> <key>System</key> <dict> <key>Enable-Private-Data</key> <true/> </dict> </dict> </array> <key>PayloadDescription</key> <string>Allows showing private log messages.</string> <key>PayloadDisplayName</key> <string>Allow Private Logs</string> <key>PayloadIdentifier</key> <string>cz.ocs.enable.private.logs</string> <key>PayloadOrganization</key> <string>OCSoftware</string> <key>PayloadRemovalDisallowed</key> <false/> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>529DF49A-6CB3-4DE9-A29F-4C41EC88BFDD</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>
Posted
by OC_s.
Last updated
.
Post marked as solved
2 Replies
447 Views
When exporting OSLog entries from OSLogStore, composedMessage doesn't seem to respect the given privacy marker. This feels like a bug to me, but it maybe a case of me holding it wrong. Here's an example: import UIKit import OSLog class ViewController: UIViewController { let logger = Logger(subsystem: "com.example.project", category: "ViewController") override func viewDidLoad() { super.viewDidLoad() logger.info("Top secret number \(42, privacy: .private)") do { let store = try OSLogStore(scope: .currentProcessIdentifier) let postion = store.position(timeIntervalSinceLatestBoot: 1) let logs = try store.getEntries(at: postion) .compactMap { $0 as? OSLogEntryLog } .filter { $0.subsystem == "com.example.project" } .map { $0.composedMessage } // Prints: // Logger: ["Top secret number 42"] print("Logger: \(logs)") } catch { print(error) } } } Is there a more appropriate way to format the text ready for sharing?
Posted Last updated
.
Post not yet marked as solved
3 Replies
440 Views
I use a macro to do logging: #define LOG(fmt, ...) NSLog((fmt), ##VA_ARGS); which means I can write code like: LOG(@"radius=%.1f", fRadius) Up until Xcode 15 the %.1f would be respected and display fRadius to one decimal place. But since Xcode 15 it seems to ignore that and just display all decimal places regardless. Anyone know why, and how to fix that?
Posted Last updated
.
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 Jaanus.
Last updated
.
Post not yet marked as solved
1 Replies
462 Views
Environment Context: iOS 17.0 Simulator Xcode 15.0 In the above environment, I'm noticing in Instruments that the OS subsystem com.apple.VectorKit is emitting os_signpost events at a rate of ~2.8 events/ms. This large amount of data logging seems to be triggering warnings of: 'Data stream: 1 log/signpost messages lost due to high rates' ...when trying to capture other system logging data. (In the attached screenshot, notice the warning sign icons right outside the selected time series.) This is preventing me from being able to successfully log my own signpost data and profile my application. As well, this subsystem's data is unnecessary for my purposes and distracting. I have tried to disable logging for this subsystem in the Simulator by running the following from the macOS host: % xcrun simctl spawn booted log config --subsystem com.apple.VectorKit --mode level:off ...and confirmed it with: % xcrun simctl spawn booted log config --subsystem com.apple.VectorKit --status Mode for 'com.apple.VectorKit' OFF PERSIST_OFF ...however, when running Instruments after the above output, this data does not actually get disabled. How can I disable this subsystem's logging? Feedback Assistant report: FB13292000
Posted
by joshavant.
Last updated
.
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 eskimo.
Last updated
.
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 Last updated
.
Post not yet marked as solved
3 Replies
705 Views
minimum is to create an os_log once in the parent, then, after fork, use an existing os_log instance or create a new one. Here's my reproduction sample. It looks like an OS bug, So what is the workaround till its solved and releases. #include <os/log.h> #include <stdio.h> #include <errno.h> #define USE_SWIFT_LOGGER 0 // set to 1 to use Logger() instead of os_log() #define USE_SHARED_LOG 0 // set to 1 to use a shared os_log instance instead of allocating one for each os_log() call #if USE_SWIFT_LOGGER // log messages using Swift's Logger class instead of calling os_log_... directly #include "forktest-Swift.h" #define LOG(msg) log_using_logger([NSString stringWithUTF8String:msg]) const char * logMethod = "Swift's Logger"; #elif USE_SHARED_LOG // use a shared os_log instance for all log messages static os_log_t log = os_log_create("com.ivanti.forktest", "foo"); #define LOG(msg) os_log_debug(log, msg) const char * logMethod = "shared log"; #else // create a new os_log instance for each log message #define LOG(msg) os_log_debug(os_log_create("com.ivanti.forktest", "foo"), msg) const char * logMethod = "new log instance for each message"; #endif static void forkTest() { int pid = fork(); if (pid < 0) { fprintf(stderr, "fork failed: %s\n", strerror(errno)); exit(1); } else if (pid == 0) { printf("in child process...\n"); LOG("in child process..."); printf("child process done\n"); } else { printf("child process pid: %d\n", pid); } } int main(int arc, const char ** argv) { printf("Log method: %s\n", logMethod); LOG("entering main..."); forkTest(); LOG("leaving main..."); return 0; }
Posted
by viveknuna.
Last updated
.
Post not yet marked as solved
0 Replies
954 Views
I regularly talk to developers debugging hard-to-reproduce problems. I have some general advice on that topic. I’ve posted this to DevForums before, and also sent similar info to folks who’ve opened a DTS incident, but I figured I should write it down properly. If you have questions or comments, put them in a new thread here on DevForums. Tag it with Debugging so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Using a Sysdiagnose Log to Debug a Hard-to-Reproduce Problem Some problems are hard to reproduce in your office. These usually fall into one of two categories: Environment specific — This is where some of your users can easily reproduce the problem, but you can’t reproduce it in your environment. Intermittent — In this case the problem could affect any user, but it’s hard to predict when a given user will see the problem. A key tool in debugging such problems is the sysdiagnose log. This post explains how to make this technology work for you. IMPORTANT A sysdiagnose log might contain private information. If you ask a user to send you a log, make sure they understand the privacy impact of that. If you want to see how Apple handles this, run the sysdiagnose command on a fresh Mac and read through it’s initial prompt. Sysdiagnose Logs All Apple platforms can generate sysdiagnose logs. For instructions on how to do this, see our Bug Reporting > Profiles and Logs page. The resulting log is a .tar.gz file. Unpacking that reveals a bunch of files. The most critical of these is system_logs.logarchive, which is a snapshot of the system log. For more information about the system log, including links to the documentation, see Your Friend the System Log. This log snapshot includes many thousands of log entries (I just took a log snapshot on my Mac and it had 22.8 million log entries!). That can be rather daunting. To avoid chasing your tail, it pays to do some preparation. Preparation The goal here is to create a set of instructions that you can give to your user to capture an actionable sysdiagnose log. That takes some preparation. To help orient yourself in the log, add log points to your code to highlight the problem. For example, if you’re trying to track down a keychain problem where SecItemCopyMatching intermittently fails with errSecMissingEntitlement ( -34018 ), add a log point like this: import os.log let log = Logger(subsystem: "com.example.waffle-varnish", category: "keychain") func … { let err = SecItemCopyMatching(…) log.log("SecItemCopyMatching failed, err: \(err)") } When you look through a log, find this specific failure by searching for SecItemCopyMatching failed, err: -34018. You might also add log points at the start and end of an operation, which helps establish a time range of interest. Log points like this have a very low overhead and it’s fine to leave them enabled in your released product. However, in some cases you might want to make more extensive changes, creating a debug build specifically to help investigate your problem. Think about how you’re going to get that debug build to the affected users. You might, for example, set up a special TestFlight group for folks who’ve encountered this issue. Go to Bug Reporting > Profiles and Logs and look for debug profiles that might help your investigation. For example, if you’re investigating a Network Extension issue, the VPN (Network Extension) debug profile will enable useful debug logging. Now craft your instructions for your user. Include things like: Your take on the privacy impact on this Instructions on how to get the necessary build of your product If there’s a debug profile, instructions on how to install that Instructions on how to trigger the sysdiagnose log And on how to send it to you IMPORTANT Make sure to stress how important it is that the user triggers the sysdiagnose immediately after seeing the problem. Finally, test your steps. Do an initial test in your office, to make sure that the log captures the info you need. Then do an end-to-end test with someone who’s about as technically savvy as your users, to make sure that your instructions make sense to Real People™. Prompting for a Sysdiagnose Log In some cases it might not be obvious to the user when to trigger a sysdiagnose log. Imagine you’re hunting the above-mentioned errSecMissingEntitlement error and it only crops up when your product is performing some task in the background. The user doesn’t see that failure, they’re not even running your app!, so they don’t know that action is required. A good option here is to add code to actively monitor for the failure and post a local notification requesting that the user trigger a sysdiagnose log. Continuing the above example, you might write code like this: func … { let err = SecItemCopyMatching(…) log.log("SecItemCopyMatching failed, err: \(err)") if err == errSecMissingEntitlement { … post a local notification … } } Obviously this is quite intrusive so, depending on the market for your product, you might not want to deploy this to all users. Perhaps you can restrict it to your internal testers, or your external beta testers, or a particularly savvy set of customers. Looking at the System Log Once you have your sysdiagnose log, unpack it and open the system log snapshot (system_logs.logarchive) in Console. The hardest part is knowing where to start. That’s why adding your own log entries, as discussed in Preparation, is so important. A good general process is: Search for log entries from your subsystem. An easy way to initiate that search is to paste the text subsystem:SSS, where SSS is your subsystem, into the Search field. Continuing the above example, find that log entry by pasting in subsystem:com.example.waffle-varnish. Identify the log entry that indicates the problem and select it. Then remove your search and work backwards through the log looking for system log entries related to your issue. The relevant log entries might not be within the time range shown by Console. Customise that by selecting values from the Showing popup in the pane divider. Once you have a rough idea of the timeframe involved, select Custom from that popup to focus on that range. If the log is showing stuff that’s not relevant to your problem, Console has some great facilities for filtering those out. For the details, choose Help > Console Help. Talk to Apple A key benefit of this approach is that, if your investigation suggests that this is a system bug, you can file a bug report and attach this sysdiagnose log to it. The setup described above is exactly the sort of info needed to analyse the bug. Likewise, if you decide to seek formal code-level support by opening a DTS tech support incident, your friendly neighbourhood DTS engineer will find that sysdiagnose log very handy.
Posted
by eskimo.
Last updated
.
Post marked as solved
8 Replies
866 Views
Currently I have a setup which duplicates the stderr STDERR_FILENO pipe into a separate one. Then by setting up a readabilityHandler (on the new Pipe) I can capture the logged data and either store it inside a File, adjust/modify the data etc. Since iOS 17 this is not possible anymore (previous versions worked iOS 16)? I cannot find any documentation on why or what changed on the os_log side. private func setupPipes() { inputPipe.fileHandleForReading.readabilityHandler = { [weak self] handler in guard let strongSelf = self else { return } let data = handler.availableData strongSelf.queue.async(flags: .barrier) { guard let fileHandle = try? FileHandle(forWritingTo: strongSelf.filePath) else { return } fileHandle.seekToEndOfFile() fileHandle.write(data) try? fileHandle.close() } strongSelf.outputPipe.fileHandleForWriting.write(data) } dup2(STDERR_FILENO, outputPipe.fileHandleForWriting.fileDescriptor) dup2(inputPipe.fileHandleForWriting.fileDescriptor, STDERR_FILENO) }
Posted
by ggeo.
Last updated
.
Post not yet marked as solved
5 Replies
773 Views
I need to log to OSLog and into a file in parallel (due to OSLogStore not being able to provide old logs (FB13191608)). In Objective-C I can accomplish this with a macro using __FILE__ and __LINE__ in the macro implementation which still reference the position in the original code. I tried to create a Swift macro to make this work from Swift. However, log() takes the file and line number of the macro definition file instead of the position in the calling code. So when I click on the metadata link, I'm taken to the macro instead of the calling location. Is there any solution to that? #file and #line are correctly set in the macro but there’s no way to specify file and line number to the log() function (FB13204310).
Posted
by ortwin.
Last updated
.
Post not yet marked as solved
5 Replies
1.2k Views
This is the opposite of https://developer.apple.com/forums/thread/726354 really, and I've read both of the Recording Private Data in the System Log and Your Friend, the System Log threads, but I still can't solve my problem. The structured log always seems to redact private values to If I set OS_ACTIVITY_DT_MODE=1 in my environment (it's not set anymore by Xcode, at least not for my projects) then the logs are unredacted as I would expect, but structured logging is turned off. Is there a way to have the unredacted strings in the log when the app is running under Xcode and still get the nice structured log output? I don't want the unredacted logs when the app runs normally, but I'd like them under Xcode. At the moment, I'm having to explicitly make everything public, which defeats the whole purpose of the system.
Posted
by iains5.
Last updated
.
Post not yet marked as solved
4 Replies
6.0k Views
Is it possible to reduce the verbosity of logs from os_log when debugging an application? Specifically, can I filter to specific subsystems and / or exclude DEBUG logs using configuration?
Posted Last updated
.
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 Last updated
.