Skip to content

Instantly share code, notes, and snippets.

@robinkunde
Created October 1, 2025 14:33
Show Gist options
  • Select an option

  • Save robinkunde/5e0d037f5b80bc95b75cc8db36d5efda to your computer and use it in GitHub Desktop.

Select an option

Save robinkunde/5e0d037f5b80bc95b75cc8db36d5efda to your computer and use it in GitHub Desktop.
redirect_xcode_logs.swift
#if DEBUG
import Foundation
class DebugLogger {
static let shared: DebugLogger = {
let logger = DebugLogger()
logger.openConsolePipe()
return logger
}()
static private var inputPipe = Pipe()
static private var outputPipe = Pipe()
static private var fileRedirectURL: URL?
private init() { }
func redirectOutputToFile(_ fileURL: URL) {
DebugLogger.fileRedirectURL = fileURL
}
private func openConsolePipe() {
// Route everything that comes in throught the outputPipe back to xcode console
dup2(fileno(stdout), DebugLogger.outputPipe.fileHandleForWriting.fileDescriptor)
// Route printing functions that go to sys pipes (stdout & stderr) into local inputPipe
dup2(DebugLogger.inputPipe.fileHandleForWriting.fileDescriptor, fileno(stdout))
dup2(DebugLogger.inputPipe.fileHandleForWriting.fileDescriptor, fileno(stderr))
// Begin notification listener
let inputReadHandler = DebugLogger.inputPipe.fileHandleForReading
NotificationCenter.default.addObserver(self, selector: #selector(handlePipeNotification(notification:)), name: FileHandle.readCompletionNotification, object: inputReadHandler)
inputReadHandler.readInBackgroundAndNotify()
}
@objc private func handlePipeNotification(notification: Notification) {
// Listen for next input
DebugLogger.inputPipe.fileHandleForReading.readInBackgroundAndNotify()
if let data = notification.userInfo?[NSFileHandleNotificationDataItem] as? Data {
// Write data back to output pipe for xcode to display
DebugLogger.outputPipe.fileHandleForWriting.write(data)
// Write to file if applicable
if let fileURL = DebugLogger.fileRedirectURL {
if !FileManager.default.fileExists(atPath: fileURL.path) {
FileManager.default.createFile(atPath: fileURL.path, contents: nil, attributes: nil)
}
do {
let fileHandle = try FileHandle(forWritingTo: fileURL)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
} catch { /* pass */ }
}
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment