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

OSLog Documentation

Pinned Posts

Posts under OSLog tag

27 Posts
Sort by:
Post not yet marked as solved
3 Replies
596 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
0 Replies
218 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! Friends with Benefits 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 in your app’s profile (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. The Console app displays the log, both on the local Mac and on attached iOS devices. It also opens log snapshots (.logarchive). It also supports surprisingly sophisticated filtering. 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 information about sysdiagnose logs, see the info on 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. For more information, see: os > Logging OSLog log man page os_log man page (in section 3) os_log man page (in section 5) [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. 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). Xcode’s console pane has no system log integration (r. 32863680). I generally work around this by ignoring the console pane and instead running Console and viewing my log entries there. Revision History 2022-06-23 Added the Foster Your Friendship section. Made other editorial changes. 2022-05-12 First posted.
Posted
by eskimo.
Last updated
.
Post marked as solved
2 Replies
159 Views
Platform: macOS 12.4, MacBook Pro 2.3GHz Quad-Core i5, 16GB RAM I'm trying to read an OSLog concurrently because it is big and I don't need any of the data in order. Because the return from .getEntries is a sequence, the most efficient approach seems to be to iterate through. Iteration through the sequence from start to finish can take a long time so I thought I can split it up into days and concurrently process each day. I'm using a task group to do this and it works as long as the number of tasks is less than 8. When it works, I do get the result faster but not a lot faster. I guess there is a lot of overhead but actually it seems to be that my log file is dominated by the processing on 1 of the days. Ideally I want more concurrent tasks to break up the day into smaller blocks. But as soon as I try to create 8 or more tasks, I get a lockup with the following error posted to the console. enable_updates_common timed out waiting for updates to reenable Here are my tests. First - a pure iterative approach. No tasks. completion of this routine on my i5 quad core takes 229s    func scanLogarchiveIterative(url: URL) async {     do {       let timer = Date()               let logStore = try OSLogStore(url: url)       let last5days = logStore.position(timeIntervalSinceEnd: -3600*24*5)       let filteredEntries = try logStore.getEntries(at: last5days)               var processedEntries: [String] = []               for entry in filteredEntries {         processedEntries.append(entry.composedMessage)       }               print("Completed iterative scan in: ", timer.timeIntervalSinceNow)     } catch {             }   } Next is a concurrent approach using a TaskGroup which creates 5 child tasks. Completion takes 181s. Faster but the last day dominates so not a huge benefit as the most time is taken by a single task processing the last day.   func scanLogarchiveConcurrent(url: URL) async {     do {       let timer = Date()               var processedEntries: [String] = []               try await withThrowingTaskGroup(of: [String].self) { group in         let timestep = 3600*24         for logSectionStartPosition in stride(from: 0, to: -3600*24*5, by: -1*timestep) {           group.addTask {             let logStore = try OSLogStore(url: url)             let filteredEntries = try logStore.getEntries(at: logStore.position(timeIntervalSinceEnd: TimeInterval(logSectionStartPosition)))             var processedEntriesConcurrent: [String] = []             let endDate = logStore.position(timeIntervalSinceEnd: TimeInterval(logSectionStartPosition + timestep)).value(forKey: "date") as? Date             for entry in filteredEntries {               if entry.date > (endDate ?? Date()) {                 break               }               processedEntriesConcurrent.append(entry.composedMessage)             }             return processedEntriesConcurrent           }         }                   for try await processedEntriesConcurrent in group {           print("received task completion")           processedEntries.append(contentsOf: processedEntriesConcurrent)         }       }               print("Completed concurrent scan in: ", timer.timeIntervalSinceNow)             } catch {             }   } If I split this further to concurrently process half days, then the app locks up. The console periodically prints enable_updates_common timed out waiting for updates to reenable If I pause the debugger, it seems like there is a wait on a semaphore which must be internal to the concurrent framework?    func scanLogarchiveConcurrentManyTasks(url: URL) async {     do {       let timer = Date()               var processedEntries: [String] = []               try await withThrowingTaskGroup(of: [String].self) { group in         let timestep = 3600*12         for logSectionStartPosition in stride(from: 0, to: -3600*24*5, by: -1*timestep) {           group.addTask {             let logStore = try OSLogStore(url: url)             let filteredEntries = try logStore.getEntries(at: logStore.position(timeIntervalSinceEnd: TimeInterval(logSectionStartPosition)))             var processedEntriesConcurrent: [String] = []             let endDate = logStore.position(timeIntervalSinceEnd: TimeInterval(logSectionStartPosition + timestep)).value(forKey: "date") as? Date             for entry in filteredEntries {               if entry.date > (endDate ?? Date()) {                 break               }               processedEntriesConcurrent.append(entry.composedMessage)             }             return processedEntriesConcurrent           }         }                   for try await processedEntriesConcurrent in group {           print("received task completion")           processedEntries.append(contentsOf: processedEntriesConcurrent)         }       }               print("Completed concurrent scan in: ", timer.timeIntervalSinceNow)             } catch {             }   } I read that it may be possible to get more insight into concurrency issue by setting the following environment: LIBDISPATCH_COOPERATIVE_POOL_STRICT 1 This stops the lockup but it is because each task is run sequentially so there is no benefit from concurrency anymore. I cannot see where to go next apart from accept the linear processing time. It also feels like doing any concurrency (even if under 8 tasks) is risky as there is no documentation to suggest that is a limit. Could it be that concurrently processing the sequence from OSLog .getEntries is not suitable for concurrent access and shouldn't be done? Again, I don't see any documentation to suggest this is the case. Finally, the processing of each entry is so light that there is little benefit to offloading just the processing to other tasks. The time taken seems to be purely dominated by iterating the sequence. In reality I do use a predicate in .getEntries which helps a bit but its not enough and concurrency would still be valuable if I could process 1 hour blocks concurrently.
Posted
by tumbler.
Last updated
.
Post not yet marked as solved
3 Replies
194 Views
We created Driver sample by Xcode template and following macro was added into code: #define Log(fmt, ...) os_log(OS_LOG_DEFAULT, "Driver - " fmt "\n", ##__VA_ARGS__) We used this macro in init and start. For example: bool ForcePlateDriver::init() { Log("init()"); But our logs are not displayed in Console app. Did we miss something? Is anything else is required to have logs for Driver? Our environment: MacOS Monterey - 12.4 (21F79) Xcode - Version 13.4 (13F17a)
Posted
by myurik2.
Last updated
.
Post marked as solved
2 Replies
182 Views
I'm debugging a USB DriverKit driver, and noticed the os_log messages during the kernel verification checks do not have a subsystem (not my driver's logging): { "traceID" : 44303244788367364, "eventMessage" : "DK: G600Driver-0x1002dd073: family entitlements check failed", "eventType" : "logEvent", "source" : null, "formatString" : "DK: %s-0x%qx: family entitlements check failed\n", "activityIdentifier" : 0, "subsystem" : "", "category" : "", "threadID" : 2655768, "senderImageUUID" : "198748B0-2858-345A-957A-45C9ACB4C2F2", "backtrace" : { "frames" : [ { "imageOffset" : 9007231, "imageUUID" : "198748B0-2858-345A-957A-45C9ACB4C2F2" } ] }, "bootUUID" : "", "processImagePath" : "\/kernel", "timestamp" : "2022-06-14 01:57:51.171906-0700", "senderImagePath" : "\/kernel", "machTimestamp" : 281599031530198, "messageType" : "Default", "processImageUUID" : "198748B0-2858-345A-957A-45C9ACB4C2F2", "processID" : 0, "senderProgramCounter" : 9007231, "parentActivityIdentifier" : 0, "timezoneName" : "" } Is there a recommended way (other than substring matching on the driver name) to create a predicate for filtering the log to messages relevant to my driver? Thanks.
Posted
by nealsid.
Last updated
.
Post marked as solved
3 Replies
265 Views
I am trying to use the Logger api instead of CocoaLumberjack. In the WWDC 2020 video it states that log messages will display in the Xcode debug console as well as the device logs. However, I cannot see any of these messages in Xcode. Does anyone have any insight on this?
Posted
by G_Frank.
Last updated
.
Post not yet marked as solved
19 Replies
1.5k Views
Hi there, Recently we have been seeing thread_policy_set(1) returned 46 flooding our log output. We tracked down that the flood of this is coming from a separate library whom we've contacted. They mentioned that this is a Apple internal message that comes up in the library's deadlock detector. The proposed solution was to use OS_ACTIVITY_MODE env var to hide the logs as suggested from the post on StackOverflow.. I tried all suggestions from that StackOverflow post, which were able to hide other system logs generated from Apple but it specifically did not hide the thread_policy_set(1) returned 46 What I am hoping to understand is: Why does this message come up? I see that the documentation for this on Apple's docs is very limited. Is this message's visibility controllable via a separate variable in project settings outside of modifying settings for all logs? As a last resort, how can I disable only this log message? Thank you!
Posted Last updated
.
Post not yet marked as solved
1 Replies
137 Views
UAL (Unified Access Logging) system saves every log into files. But when does those files expire? It cannot grow forever.
Posted
by dabresua.
Last updated
.
Post not yet marked as solved
0 Replies
127 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). 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.
Posted
by eskimo.
Last updated
.
Post not yet marked as solved
5 Replies
383 Views
I'm debugging very rarely occuring problem in my NetworkExtension. For this I rely on logs being saved by OSLog: import os.log ... os_log("[TAG] %{public}s", log: OSLog.default, type: type, String(describing: msg)) After I download logs from the phone using log collect on my mac, I can see, that only logs made while phone was unlocked are persisted. If I filter logs for my process, I can see that something is going on, as a lot of other logs from my process are saved (like the ones with categories tcp, connection, boringssl, etc.), but not my custom logs made with os_log. My logs appear only around the time I unlock the phone. Is it expected behaviour? Can I make it log all the time without exceptions?
Posted Last updated
.
Post not yet marked as solved
1 Replies
334 Views
I'm trying to collect logs on my mac from my app running on iPhone, but I always get an error. I use log collect as such: % sudo log collect --device --output log.logarchive --last 1m Archive successfully written to log.logarchive % sudo log show --archive log.logarchive/ log: Could not open log archive: The log archive is corrupt or incomplete and cannot be read so log show always claims the logs create by log collect are corrupt. I'm on maces monterey and iOS 15.3, and solution / tip? thanks
Posted
by gshaviv.
Last updated
.
Post not yet marked as solved
1 Replies
337 Views
Does anyone here have experience with LogRocket in an iOS app, specifically the screen recording capabilities? I'm working on a project in which LogRocket has come up as a "desired" addition. They are really interested in the screen recording capability. According to LogRocket, they have an agreement with Apple whereby apps don't have to notify users about screen recording if they accept a "general" analytics question. This doesn't feel right to me, particularly given Apple's privacy focus. If you're using LogRocket, how do you handle this?
Posted
by dnedrow.
Last updated
.
Post not yet marked as solved
1 Replies
273 Views
I was delighted to see that OSLogStore finally works on iOS 15+, so that I could enable our users to share the logs with us within our app, without having to roll our own custom logging. However, from what I can see, this functionality is still essentially crippled. Is there any way to fetch logs across app restarts? (ie app crashes, then the user re-opens and we want to upload those logs). As far as I can see .currentProcessIdentifier will only enable us to access logs from the current process. If not - what is everyone doing to make this actually useful? are we still stuck with using third party logging mechanisms / rolling our own? Many thanks
Posted Last updated
.
Post not yet marked as solved
2 Replies
338 Views
Hi, I need to retrieve the app logs in a file to be sent via API only when needed. I write the logs and recover them but only of the current instance! If the app crashes or is closed, the old logs are deleted while I have to recover them at the next start. I write log with Logger and recover them with OSLogStore. here a sample snippet to write func testLog(_ message: String){    let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "myAppLog")    logger.error("Sample error msg")   } and the snippet to load  func getLogEntries() throws -> [OSLogEntryLog] {     let logStore = try OSLogStore(scope: .currentProcessIdentifier)     let oneDayAgo = logStore.position(date: Date().addingTimeInterval(-3600*24))     let allEntries = try logStore.getEntries(at: oneDayAgo)     return allEntries       .compactMap { $0 as? OSLogEntryLog }       .filter { $0.subsystem == Logger.subsystem }   } any clue?
Posted
by Dr.Luiji.
Last updated
.
Post not yet marked as solved
2 Replies
346 Views
The very little and outdated 'documentation' shared by Apple about CoreAudio and CoreMIDI server plugins suggested to use syslog for logging. At least since Bug Sur syslog doesn't end up anywhere. (So, while you seem to think its OK to not document your APIs you could at least remove not working APIs then! Not to do so causes unnecessary and frustrating bug hunting?) Should we replace syslog by unified logging? For debugging purpose only our plugins write to our own log files. Where can I find suitable locations? Where is this documented? Thanks, hagen.
Posted
by hagen.
Last updated
.
Post not yet marked as solved
2 Replies
308 Views
XCode version 13.2.1 I enabled os_log messages using the following code:    let myLog = OSLog(subsystem: "testing", category: "exploring")   override func viewDidLoad() {     os_log("LOGGING TEST BLAH BLAH", log: myLog)     print("Starting ViewDidLoad")     super.viewDidLoad()     os_log("LOGGING TEST BLAH BLAH", log: myLog)' ... However, I do not see anything on the XCode console - just the print ("Starting ViewDidLoad"). Is there a setting in XCode to echo messages from the logger that needs to be turned on? I understand that Logger is the preferred method now instead of os_log, but both should echo the log messages on XCode debug console from what I can tell.. Thanks!
Posted Last updated
.
Post not yet marked as solved
2 Replies
496 Views
Hi I have watched this video https://developer.apple.com/wwdc20/10168 and tried to implement Logger in my application. Then I've tried to generate .logarchive file from my iPhone device using this command (as it was mentioned in the video): sudo log collect --device --start '2021-09-07 10:00:00' --output logTest.logarchive where the result was: Archive successfully written to logTest.logarchive However, when I double-click over this file it opens the Console.app but then it stays infinitely loading the .logarchive. Some notes: The file size is about 150Mb, so I believe is not related with this. Am I doing something wrong? Can you please help me? Thanks in advance
Posted
by davidbel.
Last updated
.
Post not yet marked as solved
1 Replies
336 Views
Would someone explain something about this content I got from this URL to Apple documentation? Logging ”You view log messages using the Console app, log command-line tool, or Xcode debug console. You can also access log messages programmatically using the OSLogframework.” I’m not sure what Console app runs on. Is that an app on macOS? I’m not really sure what to ask really. I’m looking for a way to get debug data from people using my app who download it from the App Store, so they won’t be using TestFlight. I did a search on Google but didn’t find what I needed to know. I’m trying to connect to the App Store on my iPhone, but it’s not able to connect. That seems to happen often for some reason. I wonder if this is talking about the Console app that I’m wondering about? https://help.dayoneapp.com/en/articles/470117-using-ios-console
Posted Last updated
.
Post not yet marked as solved
0 Replies
278 Views
I'm developing a Mac OS application. I can see the following error message when I run the application. "You do not have permission to open the application" If the SIP is disable, the crash report is stored in "users\username\Library\Logs\DiagnosticReports". But if the SIP is enable, I cannot see the log in same folder. Do you know where the log is stored? Mac OS 11.2.2
Posted
by ShoC.
Last updated
.