mirror of
https://github.com/cranci1/Sora.git
synced 2026-01-11 20:10:24 +00:00
154 lines
5.1 KiB
Swift
154 lines
5.1 KiB
Swift
//
|
|
// Logging.swift
|
|
// Sora
|
|
//
|
|
// Created by seiike on 16/01/2025.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
class Logger {
|
|
static let shared = Logger()
|
|
|
|
struct LogEntry {
|
|
let message: String
|
|
let type: String
|
|
let timestamp: Date
|
|
}
|
|
|
|
private let queue = DispatchQueue(label: "me.cranci.sora.logger", attributes: .concurrent)
|
|
private var logs: [LogEntry] = []
|
|
private let logFileURL: URL
|
|
private let logFilterViewModel = LogFilterViewModel.shared
|
|
|
|
private let maxFileSize = 1024 * 512
|
|
private let maxLogEntries = 1000
|
|
|
|
private init() {
|
|
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
|
logFileURL = documentDirectory.appendingPathComponent("logs.txt")
|
|
}
|
|
|
|
func log(_ message: String, type: String = "General") {
|
|
guard logFilterViewModel.isFilterEnabled(for: type) else { return }
|
|
|
|
let entry = LogEntry(message: message, type: type, timestamp: Date())
|
|
|
|
queue.async(flags: .barrier) {
|
|
self.logs.append(entry)
|
|
|
|
if self.logs.count > self.maxLogEntries {
|
|
self.logs.removeFirst(self.logs.count - self.maxLogEntries)
|
|
}
|
|
|
|
self.saveLogToFile(entry)
|
|
self.debugLog(entry)
|
|
}
|
|
}
|
|
|
|
func getLogs() -> String {
|
|
var result = ""
|
|
queue.sync {
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "dd-MM HH:mm:ss"
|
|
result = logs.map { "[\(dateFormatter.string(from: $0.timestamp))] [\($0.type)] \($0.message)" }
|
|
.joined(separator: "\n----\n")
|
|
}
|
|
return result
|
|
}
|
|
|
|
func getLogsAsync() async -> String {
|
|
return await withCheckedContinuation { continuation in
|
|
queue.async {
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "dd-MM HH:mm:ss"
|
|
let result = self.logs.map { "[\(dateFormatter.string(from: $0.timestamp))] [\($0.type)] \($0.message)" }
|
|
.joined(separator: "\n----\n")
|
|
continuation.resume(returning: result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func clearLogs() {
|
|
queue.async(flags: .barrier) {
|
|
self.logs.removeAll()
|
|
try? FileManager.default.removeItem(at: self.logFileURL)
|
|
}
|
|
}
|
|
|
|
func clearLogsAsync() async {
|
|
await withCheckedContinuation { continuation in
|
|
queue.async(flags: .barrier) {
|
|
self.logs.removeAll()
|
|
try? FileManager.default.removeItem(at: self.logFileURL)
|
|
continuation.resume()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func saveLogToFile(_ log: LogEntry) {
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "dd-MM HH:mm:ss"
|
|
|
|
let logString = "[\(dateFormatter.string(from: log.timestamp))] [\(log.type)] \(log.message)\n---\n"
|
|
|
|
guard let data = logString.data(using: .utf8) else {
|
|
print("Failed to encode log string to UTF-8")
|
|
return
|
|
}
|
|
|
|
do {
|
|
if FileManager.default.fileExists(atPath: logFileURL.path) {
|
|
let attributes = try FileManager.default.attributesOfItem(atPath: logFileURL.path)
|
|
let fileSize = attributes[.size] as? UInt64 ?? 0
|
|
|
|
if fileSize + UInt64(data.count) > maxFileSize {
|
|
self.truncateLogFile()
|
|
}
|
|
|
|
if let handle = try? FileHandle(forWritingTo: logFileURL) {
|
|
handle.seekToEndOfFile()
|
|
handle.write(data)
|
|
handle.closeFile()
|
|
}
|
|
} else {
|
|
try data.write(to: logFileURL)
|
|
}
|
|
} catch {
|
|
print("Error managing log file: \(error)")
|
|
try? data.write(to: logFileURL)
|
|
}
|
|
}
|
|
|
|
private func truncateLogFile() {
|
|
do {
|
|
guard let content = try? String(contentsOf: logFileURL, encoding: .utf8),
|
|
!content.isEmpty else {
|
|
return
|
|
}
|
|
|
|
let entries = content.components(separatedBy: "\n---\n")
|
|
guard entries.count > 10 else { return }
|
|
|
|
let keepCount = entries.count / 2
|
|
let truncatedEntries = Array(entries.suffix(keepCount))
|
|
let truncatedContent = truncatedEntries.joined(separator: "\n---\n")
|
|
|
|
if let truncatedData = truncatedContent.data(using: .utf8) {
|
|
try truncatedData.write(to: logFileURL)
|
|
}
|
|
} catch {
|
|
print("Error truncating log file: \(error)")
|
|
try? FileManager.default.removeItem(at: logFileURL)
|
|
}
|
|
}
|
|
|
|
private func debugLog(_ entry: LogEntry) {
|
|
#if DEBUG
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateFormat = "dd-MM HH:mm:ss"
|
|
let formattedMessage = "[\(dateFormatter.string(from: entry.timestamp))] [\(entry.type)] \(entry.message)"
|
|
print(formattedMessage)
|
|
#endif
|
|
}
|
|
}
|