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)
}
1. Why is it logged when using the debugger but outside (starting from the home screen) the logs coming from Logger are not invoking
readabilityHandler
?
This behaviour only makes sense from a historical perspective (-:
When you run a program under Xcode, it connects std{in,out,err}
to a pseudo terminal [1]. This is what allows you to capture the output from print
, respond to readline
requests, and so on.
Prior to Xcode 15, Xcode was not integrated with the system log. So, if folks adopted Logger
[2] they wouldn’t see any output. Needless to say, they weren’t happy about that.
To get around this the system log folks added a hack affordance for Xcode, namely the OS_ACTIVITY_DT_MODE
environment variable. For more background on this, see Your Friend the System Log. This is set by Xcode, which is why you see system log entries reflected to stderr
. It isn’t set when you run the app from the Home screen, which is why you don’t see the behaviour there.
With Xcode 15’s shiny new system log support we no longer need this affordance. I’m not actually sure what its final fate is, that is, whether it still actually works. Maybe one day I’ll look into that, but it’s not actually that relevant because this is feature was only ever intended to be used during development. Relying on it in production would be a mistake.
2. Is there a more Swift-friendly approach to writing logs to a file
There is no supported way to hook Logger
so that it writes to a file. There are other options, although none of them are perfect [3]. I touch on this in Your Friend the System Log. Please read that through and then write back if you have follow-up questions.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] The exact behaviour is configurable in the Options tab of the scheme editor.
[2] Or one its predecessors.
[3] I don’t believe a perfect logging API is possible, because different clients prioritise different features.