Hi all,
I'm working on a non-interactive macOS application (a service or daemon), and I'm trying to understand the best practices around logging and error reporting, particularly in failure scenarios.
If a daemon or service fails in macOS, where is it expected to log errors, and how can users or developers discover what went wrong?
Specifically, I have a few questions:
What is the recommended location or system for logging errors from a non-interactive macOS application?
Should we use os_log, standard error output, or write directly to files somewhere?
How can a user or developer access these logs to diagnose issues—should logs be visible via the Console app?
Is there a standard approach to making failure information easily accessible for debugging and support, especially for daemons running under launchd?
Any guidance or best practices would be appreciated.
OSLog
RSS for tagOSLog is a unified logging system for the reading of historical data.
Posts under OSLog tag
33 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I folks,
I have an application that is already available in production and I would like to store some logs to the app, so that on real device I will see outputs for better tracing.
iOS13 would be fine, but I can migrate it into e.g. iOS 14.
The next question is where to find logs on real devices, so that users can send me for tracing.
Thanks
Petr
I've got an iOS app with lots of extensions, some of them complex and doing a lot of stuff.
After a bug I'd like to be able to use OSLogStore to get a holistic picture of logging for the app and its extensions and send that to a debugging server to retrospectively view logs for the app and its extensions.
The constructor is OSLogStore.init(scope: OSLogStore.Scope), however scope only has one value .currentProcessIdentifier.
Implying if that is called from within the app it can only get access to logging for its process only. I tried it out to confirm this is the case - if I log something in an extension (using Logger), then run the app with code like this:
let logStore = try! OSLogStore(scope: .currentProcessIdentifier)
let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
let allEntries = try! logStore.getEntries(at: oneHourAgo)
for entry in allEntries {
look at the content of the entry
Then none of the entries are from the extension.
Is there anyway from within the app I can access logging made within an extension?
I have installed the following configuration profile:
<?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>PayloadContent</key>
<array>
<dict>
<key>PayloadDisplayName</key>
<string>Enable Private Data Logging for Unified Logging</string>
<key>PayloadEnabled</key>
<true/>
<key>PayloadIdentifier</key>
<string>com.apple.system.logging.2BFB8109-8829-4020-AEB7-BA21761AE50C</string>
<key>PayloadType</key>
<string>com.apple.system.logging</string>
<key>PayloadUUID</key>
<string>2BFB8109-8829-4020-AEB7-BA21761AE50C</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>System</key>
<dict>
<key>Enable-Private-Data</key>
<true/>
</dict>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>Enable Private Logging Data</string>
<key>PayloadIdentifier</key>
<string>Kentzo-Macbook.D000DF5D-AE7A-4D22-B1DC-8F9CD71A2DD2</string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>1CF75441-D3C2-4E5B-B36A-394C397E8529</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>ConsentText</key>
<dict>
<key>default</key>
<string>Warning: Installing this profile will enable private data logging for all of unified logging.</string>
</dict>
</dict>
</plist>
But both Console.app and log show values like <mask.hash: 'Z9xIxlLTn0KlWPUjmpOSkg=='> for the com.apple.mDNSResponder subsystem.
What do I need to do to reveal this information?
The app stops on the breakpoint when "All Runtime Issues" is added. If I disable the breakpoint, the app runs normally. Is there a new project setting to avoid this breakpoint from being set. It does not appear to be a valid error. I am running Xcode 16.2. I edited the "Type" field in the breakpoint box. This occurs with the "System Frameworks" option only.
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 "naked 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?
import SwiftUI
import OsLog
let logger = Logger(subsystem: "Test", category: "Test")
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.task {
logger.info("Hallo")
}
}
}
#Preview {
ContentView()
}
27 | .padding()
28 | .task {
29 | logger.info(__designTimeString("#6734_2", fallback: "Hallo"))
| `- error: argument must be a string interpolation
30 | }
31 | }
Should OsLog be compatible with __designTimeString?
Background
I have a SwiftUI app that uses OSLog and the new Logger framework. In my SwiftUI views, I would like to use something like Self._logChanges() to help debug issues.
After some trial and error, I can see the messages appear in the System console log for the app I am debugging using the com.apple.SwiftUI subsystem.
Problem
I'd like to see those same messages directly in Xcode's console window so I can filter them as needed. How do I do that?
Thanks! -Patrick
Hi,
Our team is facing an issue where the os log message is not fully printed in the Xcode console. Even when using Debug → Attach to Process by PID or Name, the logs appear truncated (Both simulator and physical device).
We noticed that the Xcode 15.0 release notes we saw that there is some truncation made for debug lines in console. We also tried checking the logs using Console.app, but the truncation remains.
If limitation is there how much maximum lines it can print ?
Could anyone please provide guidance on how we can view the complete logs? Any suggestions or workarounds would be highly appreciated.
I'd like to give control to the app developer that uses my library to select which level of logs they'd like to see from my lib (e.g. do they want to see all debug messages or just errors).
I know there are filtering controls that Xcode gives us, but I'm wondering if there is a way to pull this off with code. Ideally the user callsite would look like MyLib(logLevel: .info).
And then I would pass that info level somehow to OSLog. Today, I create my logger like this:
let myLogger = Logger(
subsystem: Bundle.main.bundleIdentifier ?? "UnknownApp",
category: "MyLibrary"
)
As far as I can tell, there is nothing I can then pass to my myLogger instance to configure the threshold level. I'm imagining an interface like:
myLogger.logLevel(.warning)
// Later...
myLogger.debug("You won't see this")
myLogger.error("But you will see this")
Does OSLog and friends give us any ability to do this out of the box, or are we building little wrappers around OSLog to accomplish this?
Thank you,
Lou
I was using os_log in my code and in header of oslog, it has been mentioned that there is physical cap of 1024 bytes per log line for dynamic content. So I was looking for a work around but before that I am not able see the truncation when I tried creating this issue.
let baseString = String(repeating: "a", count: 1020)
let criticalMarker = "LAST_5_BYTES"
let testString = baseString + criticalMarker // 1020 + 12 = 1032 bytes
os_log("LONG_STRING: %@", testString)
I used this as a sample code to check the truncation but in Xcode debugger it logs all the 1020 bytes and the last 12 bytes as well. I even checked the console and there also it was logging all the bytes.
Can anyone help me with this as to what I am missing here?
Hello,
I am a student studying accessibility.
I aim to analyze the smartphone usage patterns of visually impaired individuals.
Therefore, I would like to log the VoiceOver usage records of visually impaired iPhone users.
Is there a way to output VoiceOver logs, similar to the AccessibilityService API on Android?
Thank you in advance for your responses.
Is it just me or does running SwiftUI apps using Xcode 16 give so many warnings and errors in the console that it's impossible to debug everything? Even the simplest gestures such as a long press generate a warning. I'm starting to ignore them, which feels negligent. Any insights/tips?