mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 00:25:20 +00:00
Add comprehensive logging system for debugging
- Create LoggingService that writes to Documents/Logs directory - Log to both console and file with timestamps - Replace debug print statements with bitchatLog() - Add log file location display in AppInfoView - Enable opening log file in Finder on macOS - Track room member operations and view state - Persist logs for debugging room member display issues
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// LoggingService.swift
|
||||
// bitchat
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import os
|
||||
|
||||
class LoggingService {
|
||||
static let shared = LoggingService()
|
||||
|
||||
private let logger = Logger(subsystem: "com.bitchat", category: "general")
|
||||
private let fileURL: URL
|
||||
private let dateFormatter: DateFormatter
|
||||
private let queue = DispatchQueue(label: "bitchat.logging", qos: .background)
|
||||
|
||||
private init() {
|
||||
// Set up date formatter
|
||||
dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
|
||||
|
||||
// Get documents directory
|
||||
let documentsPath = FileManager.default.urls(for: .documentDirectory,
|
||||
in: .userDomainMask).first!
|
||||
|
||||
// Create logs directory
|
||||
let logsDirectory = documentsPath.appendingPathComponent("Logs")
|
||||
try? FileManager.default.createDirectory(at: logsDirectory,
|
||||
withIntermediateDirectories: true)
|
||||
|
||||
// Create log file with today's date
|
||||
let dateString = DateFormatter.localizedString(from: Date(),
|
||||
dateStyle: .short,
|
||||
timeStyle: .none)
|
||||
.replacingOccurrences(of: "/", with: "-")
|
||||
fileURL = logsDirectory.appendingPathComponent("bitchat-\(dateString).log")
|
||||
|
||||
// Create file if it doesn't exist
|
||||
if !FileManager.default.fileExists(atPath: fileURL.path) {
|
||||
FileManager.default.createFile(atPath: fileURL.path, contents: nil)
|
||||
}
|
||||
|
||||
log("=== BitChat Started ===")
|
||||
log("Log file: \(fileURL.path)")
|
||||
}
|
||||
|
||||
func log(_ message: String, category: String = "general") {
|
||||
let timestamp = dateFormatter.string(from: Date())
|
||||
let logLine = "[\(timestamp)] [\(category)] \(message)\n"
|
||||
|
||||
// Log to console for debugging
|
||||
print(logLine.trimmingCharacters(in: .newlines))
|
||||
|
||||
// Log to system logger
|
||||
logger.log("\(message, privacy: .public)")
|
||||
|
||||
// Write to file asynchronously
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let data = logLine.data(using: .utf8) {
|
||||
do {
|
||||
let fileHandle = try FileHandle(forWritingTo: self.fileURL)
|
||||
fileHandle.seekToEndOfFile()
|
||||
fileHandle.write(data)
|
||||
fileHandle.closeFile()
|
||||
} catch {
|
||||
print("Failed to write to log file: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getLogFileURL() -> URL {
|
||||
return fileURL
|
||||
}
|
||||
|
||||
func clearLogs() {
|
||||
queue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
try? "".write(to: self.fileURL, atomically: true, encoding: .utf8)
|
||||
self.log("=== Logs Cleared ===")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global logging function for convenience
|
||||
func bitchatLog(_ message: String, category: String = "general") {
|
||||
LoggingService.shared.log(message, category: category)
|
||||
}
|
||||
@@ -59,6 +59,10 @@ class ChatViewModel: ObservableObject {
|
||||
loadJoinedRooms()
|
||||
meshService.delegate = self
|
||||
|
||||
// Log startup info
|
||||
bitchatLog("ChatViewModel initialized", category: "startup")
|
||||
bitchatLog("Nickname: \(nickname)", category: "startup")
|
||||
|
||||
// Start mesh service immediately
|
||||
meshService.startServices()
|
||||
|
||||
@@ -251,7 +255,7 @@ class ChatViewModel: ObservableObject {
|
||||
roomMembers[room] = []
|
||||
}
|
||||
roomMembers[room]?.insert(meshService.myPeerID)
|
||||
print("[DEBUG-ROOM] Added self \(meshService.myPeerID) to room \(room), total members: \(roomMembers[room]?.count ?? 0)")
|
||||
bitchatLog("Added self \(meshService.myPeerID) to room \(room), total members: \(roomMembers[room]?.count ?? 0)", category: "room")
|
||||
} else {
|
||||
// Add to main messages
|
||||
messages.append(message)
|
||||
@@ -677,9 +681,9 @@ extension ChatViewModel: BitchatDelegate {
|
||||
}
|
||||
if let senderPeerID = message.senderPeerID {
|
||||
roomMembers[room]?.insert(senderPeerID)
|
||||
print("[DEBUG-ROOM] Added member \(senderPeerID) to room \(room), total members: \(roomMembers[room]?.count ?? 0)")
|
||||
bitchatLog("Added member \(senderPeerID) to room \(room), total members: \(roomMembers[room]?.count ?? 0)", category: "room")
|
||||
} else {
|
||||
print("[DEBUG-ROOM] No senderPeerID for message in room \(room)")
|
||||
bitchatLog("No senderPeerID for message in room \(room)", category: "room")
|
||||
}
|
||||
|
||||
// Update unread count if not currently viewing this room
|
||||
|
||||
@@ -111,6 +111,31 @@ struct AppInfoView: View {
|
||||
.foregroundColor(textColor)
|
||||
}
|
||||
|
||||
// Debug Info
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
SectionHeader("Debug")
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Log Location:")
|
||||
.font(.system(size: 14, weight: .semibold, design: .monospaced))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
Text(LoggingService.shared.getLogFileURL().path)
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
.foregroundColor(secondaryTextColor)
|
||||
.textSelection(.enabled)
|
||||
|
||||
#if os(macOS)
|
||||
Button("Open in Finder") {
|
||||
NSWorkspace.shared.selectFile(LoggingService.shared.getLogFileURL().path, inFileViewerRootedAtPath: "")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.foregroundColor(.blue)
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Version
|
||||
HStack {
|
||||
Spacer()
|
||||
@@ -208,6 +233,31 @@ struct AppInfoView: View {
|
||||
.foregroundColor(textColor)
|
||||
}
|
||||
|
||||
// Debug Info
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
SectionHeader("Debug")
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Log Location:")
|
||||
.font(.system(size: 14, weight: .semibold, design: .monospaced))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
Text(LoggingService.shared.getLogFileURL().path)
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
.foregroundColor(secondaryTextColor)
|
||||
.textSelection(.enabled)
|
||||
|
||||
#if os(macOS)
|
||||
Button("Open in Finder") {
|
||||
NSWorkspace.shared.selectFile(LoggingService.shared.getLogFileURL().path, inFileViewerRootedAtPath: "")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.foregroundColor(.blue)
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Version
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
@@ -601,9 +601,9 @@ struct ContentView: View {
|
||||
if let currentRoom = viewModel.currentRoom,
|
||||
let roomMemberIDs = viewModel.roomMembers[currentRoom] {
|
||||
// Show only peers who have sent messages to this room (including self)
|
||||
print("[DEBUG-VIEW] Room \(currentRoom) has members: \(roomMemberIDs)")
|
||||
print("[DEBUG-VIEW] Connected peers: \(viewModel.connectedPeers)")
|
||||
print("[DEBUG-VIEW] My peer ID: \(myPeerID)")
|
||||
bitchatLog("Room \(currentRoom) has members: \(roomMemberIDs)", category: "view")
|
||||
bitchatLog("Connected peers: \(viewModel.connectedPeers)", category: "view")
|
||||
bitchatLog("My peer ID: \(myPeerID)", category: "view")
|
||||
|
||||
// Start with room members who are also connected
|
||||
var memberPeers = viewModel.connectedPeers.filter { roomMemberIDs.contains($0) }
|
||||
@@ -613,7 +613,7 @@ struct ContentView: View {
|
||||
memberPeers.append(myPeerID)
|
||||
}
|
||||
|
||||
print("[DEBUG-VIEW] Peers to show in room: \(memberPeers)")
|
||||
bitchatLog("Peers to show in room: \(memberPeers)", category: "view")
|
||||
return memberPeers
|
||||
} else {
|
||||
// Show all connected peers in main chat
|
||||
|
||||
Reference in New Issue
Block a user