Просмотр исходного кода

Merge pull request #381 from loopandlearn/alarm-log

Add alarm log and some cleanup
Marion Barker 1 год назад
Родитель
Сommit
f0acfdd0e1

+ 2 - 16
LoopFollow/Controllers/Alarms.swift

@@ -5,20 +5,12 @@
 //  Created by Jon Fawcett on 6/16/20.
 //  Copyright © 2020 Jon Fawcett. All rights reserved.
 //
-//
-//
-//
-//
-//
-
 
 import Foundation
 import AVFoundation
 import CallKit
 
 extension MainViewController {
-    
-    
     func checkAlarms(bgs: [ShareGlucoseData]) {
         // Don't check or fire alarms within 1 minute of prior alarm
         if checkAlarmTimer.isValid {  return }
@@ -56,7 +48,6 @@ extension MainViewController {
         
         
         let currentBGTime = bgs[bgs.count - 1].date
-        var alarmTriggered = false
         var numLoops = 0
         var playSound = true
         checkQuietHours()
@@ -401,7 +392,6 @@ extension MainViewController {
                     // Get the latest bolus over the small bolus exclusion
                     // Start with 0.0 bolus assuming there isn't one to cause a trigger and only add one if found
                     var lastBolus = 0.0
-                    var lastBolusTime = 0.0
                     var i = 1
                     // check the boluses in reverse order setting it only if the time is after the carb time minus prebolus time.
                     // This will make the loop stop at the most recent bolus that is over the minimum value or continue through all boluses
@@ -409,7 +399,6 @@ extension MainViewController {
                         // Set the bolus if it's after the carb time minus prebolus time
                         if (bolusData[bolusData.count - i].date >= lastCarbTime - Double(UserDefaultsRepository.alertMissedBolusPrebolus.value * 60)) {
                             lastBolus = bolusData[bolusData.count - i].value
-                            lastBolusTime = bolusData[bolusData.count - i].date
                         }
                         i += 1
                     }
@@ -693,6 +682,8 @@ extension MainViewController {
     
     func triggerAlarm(sound: String, snooozedBGReadingTime: TimeInterval?, overrideVolume: Bool, numLoops: Int, snoozeTime: Int = 0, snoozeIncrement: Int = 5, audio: Bool = true)
     {
+        LogManager.shared.log(category: .alarm, message: "Alarm triggered: \(AlarmSound.whichAlarm)")
+
         var audioDuringCall = true
         if !UserDefaultsRepository.alertAudioDuringPhone.value && isOnPhoneCall() { audioDuringCall = false }
         
@@ -909,13 +900,8 @@ extension MainViewController {
     func checkQuietHours() {
         if UserDefaultsRepository.quietHourStart.value == nil || UserDefaultsRepository.quietHourEnd.value == nil { return }
         
-        var startDateComponents = DateComponents()
-        
         let today = Date()
         let todayCalendar = Calendar.current
-        let month = todayCalendar.component(.month, from: today)
-        let day = todayCalendar.component(.day, from: today)
-        let year = todayCalendar.component(.year, from: today)
         let hour = todayCalendar.component(.hour, from: today)
         let minute = todayCalendar.component(.minute, from: today)
         let todayMinutes = (60 * hour) + minute

+ 5 - 5
LoopFollow/Controllers/Nightscout/BGData.swift

@@ -19,13 +19,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
             }
@@ -34,7 +34,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
             }
@@ -105,7 +105,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,
@@ -126,7 +126,7 @@ extension MainViewController {
         let graphHours = 24 * UserDefaultsRepository.downloadDays.value
 
         guard !data.isEmpty else {
-            LogManager.shared.log(category: .nightscout, message: "No bg data received. Skipping processing.")
+            LogManager.shared.log(category: .nightscout, message: "No bg data received. Skipping processing.", limitIdentifier: "No bg data received. Skipping processing.")
             return
         }
 

+ 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()