Jonas Björkert 1 tahun lalu
induk
melakukan
73a865d5a4

+ 7 - 6
LoopFollow/Controllers/Nightscout/BGData.swift

@@ -18,13 +18,13 @@ extension MainViewController {
         dexShare?.fetchData(count) { (err, result) -> () in
             
             if let error = err {
-                LogManager.shared.log(category: .dexcom, message: "Error fetching Dexcom data: \(error.localizedDescription)")
+                LogManager.shared.log(category: .dexcom, message: "Error fetching Dexcom data: \(error.localizedDescription)", limitIdentifier: "Error fetching Dexcom data")
                 self.webLoadNSBGData()
                 return
             }
             
             guard let data = result else {
-                LogManager.shared.log(category: .dexcom, message: "Received nil data from Dexcom")
+                LogManager.shared.log(category: .dexcom, message: "Received nil data from Dexcom", limitIdentifier: "Received nil data from Dexcom")
                 self.webLoadNSBGData()
                 return
             }
@@ -33,7 +33,7 @@ extension MainViewController {
             let latestDate = data[0].date
             let now = dateTimeUtils.getNowTimeIntervalUTC()
             if (latestDate + 330) < now && IsNightscoutEnabled() {
-                LogManager.shared.log(category: .dexcom, message: "Dexcom data is old, loading from NS instead")
+                LogManager.shared.log(category: .dexcom, message: "Dexcom data is old, loading from NS instead", limitIdentifier: "Dexcom data is old, loading from NS instead")
                 self.webLoadNSBGData()
                 return
             }
@@ -104,7 +104,7 @@ extension MainViewController {
                     self.ProcessDexBGData(data: nsData2, sourceName: sourceName)
                 }
             case .failure(let error):
-                LogManager.shared.log(category: .nightscout, message: "Failed to fetch data: \(error)")
+                LogManager.shared.log(category: .nightscout, message: "Failed to fetch bg data: \(error)", limitIdentifier: "Failed to fetch bg data")
                 DispatchQueue.main.async {
                     TaskScheduler.shared.rescheduleTask(
                         id: .fetchBG,
@@ -123,8 +123,9 @@ extension MainViewController {
     // Dexcom BG Data Response processor
     func ProcessDexBGData(data: [ShareGlucoseData], sourceName: String){
         let graphHours = 24 * UserDefaultsRepository.downloadDays.value
-        
-        if data.count == 0 {
+
+        guard !data.isEmpty else {
+            LogManager.shared.log(category: .nightscout, message: "No bg data received. Skipping processing.", limitIdentifier: "No bg data received. Skipping processing.")
             return
         }
         let latestDate = data[0].date

+ 2 - 3
LoopFollow/Controllers/Nightscout/DeviceStatus.swift

@@ -30,12 +30,11 @@ extension MainViewController {
     }
 
     private func handleDeviceStatusError() {
-        LogManager.shared.log(category: .deviceStatus, message: "Device status fetch failed!")
+        LogManager.shared.log(category: .deviceStatus, message: "Device status fetch failed!", limitIdentifier: "Device status fetch failed!")
         DispatchQueue.main.async {
             TaskScheduler.shared.rescheduleTask(id: .deviceStatus, to: Date().addingTimeInterval(10))
+            self.evaluateNotLooping()
         }
-
-        evaluateNotLooping()
     }
     
     func evaluateNotLooping() {

+ 29 - 8
LoopFollow/Log/LogManager.swift

@@ -15,6 +15,9 @@ class LogManager {
     private let logDirectory: URL
     private let dateFormatter: DateFormatter
     private let consoleQueue = DispatchQueue(label: "com.loopfollow.log.console", qos: .background)
+    
+    private let rateLimitQueue = DispatchQueue(label: "com.loopfollow.log.ratelimit")
+    private var lastLoggedTimestamps: [String: Date] = [:]
 
     enum Category: String, CaseIterable {
         case bluetooth = "Bluetooth"
@@ -30,26 +33,46 @@ class LogManager {
     }
 
     init() {
-        // Create log directory in the app's Documents folder
         let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
         logDirectory = documentsDirectory.appendingPathComponent("Logs")
-
-        // Ensure the directory exists
         if !fileManager.fileExists(atPath: logDirectory.path) {
             try? fileManager.createDirectory(at: logDirectory, withIntermediateDirectories: true, attributes: nil)
         }
-
         dateFormatter = DateFormatter()
         dateFormatter.dateFormat = "yyyy-MM-dd"
     }
-
-    func log(category: Category, message: String, isDebug: Bool = false) {
+    
+    /// Logs a message with an optional rate limit.
+    ///
+    /// - Parameters:
+    ///   - category: The log category.
+    ///   - message: The message to log.
+    ///   - isDebug: Indicates if this is a debug log.
+    ///   - limitIdentifier: Optional key to rate-limit similar log messages.
+    ///   - limitInterval: Time interval (in seconds) to wait before logging the same type again.
+    func log(category: Category, message: String, isDebug: Bool = false, limitIdentifier: String? = nil, limitInterval: TimeInterval = 300) {
         let timestamp = DateFormatter.localizedString(from: Date(), dateStyle: .none, timeStyle: .medium)
         let logMessage = "[\(timestamp)] [\(category.rawValue)] \(message)"
 
         consoleQueue.async {
             print(logMessage)
         }
+        
+        if let key = limitIdentifier, !Storage.shared.debugLogLevel.value {
+            let shouldLog: Bool = rateLimitQueue.sync {
+                if let lastLogged = lastLoggedTimestamps[key] {
+                    let interval = Date().timeIntervalSince(lastLogged)
+                    if interval < limitInterval {
+                        return false
+                    }
+                }
+                lastLoggedTimestamps[key] = Date()
+                return true
+            }
+            if !shouldLog {
+                return
+            }
+        }
 
         if !isDebug || Storage.shared.debugLogLevel.value {
             let logFileURL = self.currentLogFileURL
@@ -60,7 +83,6 @@ class LogManager {
     func cleanupOldLogs() {
         let today = dateFormatter.string(from: Date())
         let yesterday = dateFormatter.string(from: Calendar.current.date(byAdding: .day, value: -1, to: Date())!)
-
         do {
             let logFiles = try fileManager.contentsOfDirectory(at: logDirectory, includingPropertiesForKeys: nil)
             for logFile in logFiles {
@@ -93,7 +115,6 @@ class LogManager {
         if !fileManager.fileExists(atPath: fileURL.path) {
             fileManager.createFile(atPath: fileURL.path, contents: nil, attributes: nil)
         }
-
         if let fileHandle = try? FileHandle(forWritingTo: fileURL) {
             defer { fileHandle.closeFile() }
             fileHandle.seekToEndOfFile()