Skip to content

Commit 595c010

Browse files
committed
use a log file for daemon
1 parent 4689f22 commit 595c010

File tree

6 files changed

+39
-159
lines changed

6 files changed

+39
-159
lines changed

Coder-Desktop/Coder-Desktop/Preview Content/PreviewFileSync.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import VPNLib
22

33
@MainActor
44
final class PreviewFileSync: FileSyncDaemon {
5+
var logFile: URL = .init(filePath: "~/log.txt")!
6+
57
var sessionState: [VPNLib.FileSyncSession] = []
68

79
var state: DaemonState = .running
810

9-
var recentLogs: [String] = []
10-
1111
init() {}
1212

1313
func refreshSessions() async {}

Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
8686
dontRetry = true
8787
}
8888
} message: {
89-
// You can't have styled text in alert messages
9089
Text("""
91-
File sync daemon failed: \(fileSync.state.description)\n\n\(fileSync.recentLogs.joined(separator: "\n"))
92-
""")
90+
File sync daemon failed. The daemon log file at\n\(fileSync.logFile.path)\nhas been opened.
91+
""").onAppear {
92+
// Open the log file in the default editor
93+
NSWorkspace.shared.open(fileSync.logFile)
94+
}
9395
}.task {
9496
// When the Window is visible, poll for session updates every
9597
// two seconds.

Coder-Desktop/Coder-DesktopTests/Util.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ class MockVPNService: VPNService, ObservableObject {
2929

3030
@MainActor
3131
class MockFileSyncDaemon: FileSyncDaemon {
32+
var logFile: URL = .init(filePath: "~/log.txt")
33+
3234
var sessionState: [VPNLib.FileSyncSession] = []
3335

3436
func refreshSessions() async {}
3537

36-
var recentLogs: [String] = []
37-
3838
func deleteSessions(ids _: [String]) async throws(VPNLib.DaemonError) {}
3939

4040
var state: VPNLib.DaemonState = .running

Coder-Desktop/VPNLib/FileSync/FileSyncDaemon.swift

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010
public protocol FileSyncDaemon: ObservableObject {
1111
var state: DaemonState { get }
1212
var sessionState: [FileSyncSession] { get }
13-
var recentLogs: [String] { get }
13+
var logFile: URL { get }
1414
func tryStart() async
1515
func stop() async
1616
func refreshSessions() async
@@ -39,15 +39,13 @@ public class MutagenDaemon: FileSyncDaemon {
3939

4040
@Published public var sessionState: [FileSyncSession] = []
4141

42-
// We store the last N log lines to show in the UI if the daemon crashes
43-
private var logBuffer: RingBuffer<String>
44-
public var recentLogs: [String] { logBuffer.elements }
45-
4642
private var mutagenProcess: Subprocess?
4743
private let mutagenPath: URL!
4844
private let mutagenDataDirectory: URL
4945
private let mutagenDaemonSocket: URL
5046

47+
public let logFile: URL
48+
5149
// Managing sync sessions could take a while, especially with prompting
5250
let sessionMgmtReqTimeout: TimeAmount = .seconds(15)
5351

@@ -64,13 +62,12 @@ public class MutagenDaemon: FileSyncDaemon {
6462
mutagenDataDirectory: URL = FileManager.default.urls(
6563
for: .applicationSupportDirectory,
6664
in: .userDomainMask
67-
).first!.appending(path: "Coder Desktop").appending(path: "Mutagen"),
68-
logBufferCapacity: Int = 10)
65+
).first!.appending(path: "Coder Desktop").appending(path: "Mutagen"))
6966
{
70-
logBuffer = .init(capacity: logBufferCapacity)
7167
self.mutagenPath = mutagenPath
7268
self.mutagenDataDirectory = mutagenDataDirectory
7369
mutagenDaemonSocket = mutagenDataDirectory.appending(path: "daemon").appending(path: "daemon.sock")
70+
logFile = mutagenDataDirectory.appending(path: "daemon.log")
7471
// It shouldn't be fatal if the app was built without Mutagen embedded,
7572
// but file sync will be unavailable.
7673
if mutagenPath == nil {
@@ -113,34 +110,23 @@ public class MutagenDaemon: FileSyncDaemon {
113110

114111
// Creating the same process twice from Swift will crash the MainActor,
115112
// so we need to wait for an earlier process to die
116-
if let waitForExit {
117-
await waitForExit()
118-
// We *need* to be sure the process is dead or the app ends up in an
119-
// unrecoverable state
120-
try? await Task.sleep(for: .seconds(1))
121-
}
113+
await waitForExit?()
122114

123115
await transition.wait()
124116
defer { transition.signal() }
125117
logger.info("starting mutagen daemon")
126118

127119
mutagenProcess = createMutagenProcess()
128-
// swiftlint:disable:next large_tuple
129-
let (standardOutput, standardError, waitForExit): (Pipe.AsyncBytes, Pipe.AsyncBytes, @Sendable () async -> Void)
120+
let (standardError, waitForExit): (Pipe.AsyncBytes, @Sendable () async -> Void)
130121
do {
131-
(standardOutput, standardError, waitForExit) = try mutagenProcess!.run()
122+
(_, standardError, waitForExit) = try mutagenProcess!.run()
132123
} catch {
133124
throw .daemonStartFailure(error)
134125
}
135126
self.waitForExit = waitForExit
136127

137128
Task {
138-
await streamHandler(io: standardOutput)
139-
logger.info("standard output stream closed")
140-
}
141-
142-
Task {
143-
await streamHandler(io: standardError)
129+
await handleDaemonLogs(io: standardError)
144130
logger.info("standard error stream closed")
145131
}
146132

@@ -283,11 +269,30 @@ public class MutagenDaemon: FileSyncDaemon {
283269
}
284270
}
285271

286-
private func streamHandler(io: Pipe.AsyncBytes) async {
272+
private func handleDaemonLogs(io: Pipe.AsyncBytes) async {
273+
if !FileManager.default.fileExists(atPath: logFile.path) {
274+
guard FileManager.default.createFile(atPath: logFile.path, contents: nil) else {
275+
logger.error("Failed to create log file")
276+
return
277+
}
278+
}
279+
280+
guard let fileHandle = try? FileHandle(forWritingTo: logFile) else {
281+
logger.error("Failed to open log file for writing")
282+
return
283+
}
284+
287285
for await line in io.lines {
288286
logger.info("\(line, privacy: .public)")
289-
logBuffer.append(line)
287+
288+
do {
289+
try fileHandle.write(contentsOf: Data("\(line)\n".utf8))
290+
} catch {
291+
logger.error("Failed to write to daemon log file: \(error)")
292+
}
290293
}
294+
295+
try? fileHandle.close()
291296
}
292297
}
293298

Coder-Desktop/VPNLib/Util.swift

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,39 +29,3 @@ public func makeNSError(suffix: String, code: Int = -1, desc: String) -> NSError
2929
userInfo: [NSLocalizedDescriptionKey: desc]
3030
)
3131
}
32-
33-
// Insertion-only RingBuffer for buffering the last `capacity` elements,
34-
// and retrieving them in insertion order.
35-
public struct RingBuffer<T> {
36-
private var buffer: [T?]
37-
private var start = 0
38-
private var size = 0
39-
40-
public init(capacity: Int) {
41-
buffer = Array(repeating: nil, count: capacity)
42-
}
43-
44-
public mutating func append(_ element: T) {
45-
let writeIndex = (start + size) % buffer.count
46-
buffer[writeIndex] = element
47-
48-
if size < buffer.count {
49-
size += 1
50-
} else {
51-
start = (start + 1) % buffer.count
52-
}
53-
}
54-
55-
public var elements: [T] {
56-
var result = [T]()
57-
result.reserveCapacity(size)
58-
for i in 0 ..< size {
59-
let index = (start + i) % buffer.count
60-
if let element = buffer[index] {
61-
result.append(element)
62-
}
63-
}
64-
65-
return result
66-
}
67-
}

Coder-Desktop/VPNLibTests/UtilTests.swift

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy