fix(apple): ensure log file exists before writing to it (#9597)

Similar to the issue for the gui clients, the log file handle needs to
be able to be rolled over after logs are cleared.

related: #6850
This commit is contained in:
Jamil
2025-06-20 10:03:59 -07:00
committed by GitHub
parent fc3a9d17b9
commit 5537b8cfe7
7 changed files with 58 additions and 11 deletions

View File

@@ -5,8 +5,8 @@
//
import FirezoneKit
import SwiftUI
import Sentry
import SwiftUI
@main
struct FirezoneApp: App {

View File

@@ -136,9 +136,11 @@ private final class LogWriter {
// All log writes happen in the workQueue
private let workQueue: DispatchQueue
private let logger: Logger
private let handle: FileHandle
private var handle: FileHandle
private let dateFormatter: ISO8601DateFormatter
private let jsonEncoder: JSONEncoder
private let folderURL: URL // Add this to store folder URL
private var currentLogFileURL: URL // Add this to track current file
init?(folderURL: URL?, logger: Logger) {
let fileManager = FileManager.default
@@ -159,11 +161,15 @@ private final class LogWriter {
return nil
}
self.folderURL = folderURL // Store folder URL
let logFileURL =
folderURL
.appendingPathComponent(dateFormatter.string(from: Date()))
.appendingPathExtension("jsonl")
self.currentLogFileURL = logFileURL // Store current file URL
// Create log file
guard fileManager.createFile(atPath: logFileURL.path, contents: Data()),
let handle = try? FileHandle(forWritingTo: logFileURL),
@@ -185,6 +191,37 @@ private final class LogWriter {
}
}
// Returns a valid file handle, recreating file if necessary
private func ensureFileExists() -> FileHandle? {
let fileManager = FileManager.default
// Check if current file still exists
if fileManager.fileExists(atPath: currentLogFileURL.path) {
return handle
}
// File was deleted, need to recreate
try? handle.close()
// Ensure directory exists
guard SharedAccess.ensureDirectoryExists(at: folderURL.path) else {
logger.error("Could not recreate log directory")
return nil
}
// Create new log file
guard fileManager.createFile(atPath: currentLogFileURL.path, contents: Data()),
let newHandle = try? FileHandle(forWritingTo: currentLogFileURL),
(try? newHandle.seekToEnd()) != nil
else {
logger.error("Could not recreate log file: \(self.currentLogFileURL.path)")
return nil
}
self.handle = newHandle
return newHandle
}
func write(severity: Severity, message: String) {
let logEntry = LogEntry(
time: dateFormatter.string(from: Date()),
@@ -200,7 +237,12 @@ private final class LogWriter {
jsonData.append(Data("\n".utf8))
workQueue.async { [weak self] in
self?.handle.write(jsonData)
guard let self = self else { return }
// Get valid handle, recreating file if necessary
if let handle = self.ensureFileExists() {
handle.write(jsonData)
}
}
}
}

View File

@@ -143,10 +143,10 @@ public class Configuration: ObservableObject {
// so this feature only enabled for macOS 13 and higher given the tiny Firezone installbase for macOS 12.
func updateAppService() async throws {
if #available(macOS 13.0, *) {
// Getting the status initially appears to be blocking sometimes
SentrySDK.pauseAppHangTracking()
defer { SentrySDK.resumeAppHangTracking() }
let status = SMAppService.mainApp.status
// Getting the status initially appears to be blocking sometimes
SentrySDK.pauseAppHangTracking()
defer { SentrySDK.resumeAppHangTracking() }
let status = SMAppService.mainApp.status
if !startOnLogin, status == .enabled {
try await SMAppService.mainApp.unregister()

View File

@@ -5,8 +5,8 @@
//
import Foundation
import UserNotifications
import Sentry
import UserNotifications
#if os(macOS)
import AppKit

View File

@@ -6,8 +6,8 @@
//
import Combine
import SwiftUI
import Sentry
import SwiftUI
#if os(macOS)
import SystemExtensions

View File

@@ -11,8 +11,8 @@ import Combine
import Foundation
import NetworkExtension
import OSLog
import SwiftUI
import Sentry
import SwiftUI
#if os(macOS)
@MainActor

View File

@@ -24,7 +24,12 @@ export default function Apple() {
return (
<Entries downloadLinks={downloadLinks} title="macOS / iOS">
{/* When you cut a release, remove any solved issues from the "known issues" lists over in `client-apps`. This must not be done when the issue's PR merges. */}
<Unreleased></Unreleased>
<Unreleased>
<ChangeItem pull="9597">
Fixes an issue where certain log files would not be recreated after
logs were cleared.
</ChangeItem>
</Unreleased>
<Entry version="1.5.3" date={new Date("2025-06-19")}>
<ChangeItem pull="9564">
Fixes an issue where connections would fail to establish if both