-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LOOP-1169 - Upload device logs #100
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// | ||
// DeviceLogUploader.swift | ||
// TidepoolServiceKit | ||
// | ||
// Created by Pete Schwamb on 5/28/24. | ||
// Copyright © 2024 LoopKit Authors. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import os.log | ||
import LoopKit | ||
import TidepoolKit | ||
|
||
/// Periodically uploads device logs in hourly chunks to backend | ||
actor DeviceLogUploader { | ||
private let log = OSLog(category: "DeviceLogUploader") | ||
|
||
private let api: TAPI | ||
|
||
private var delegate: RemoteDataServiceDelegate? | ||
|
||
private var logChunkDuration = TimeInterval(hours: 1) | ||
|
||
func setDelegate(_ delegate: RemoteDataServiceDelegate?) { | ||
self.delegate = delegate | ||
} | ||
|
||
init(api: TAPI) { | ||
self.api = api | ||
|
||
Task { | ||
await main() | ||
} | ||
} | ||
|
||
func main() async { | ||
let backfillLimitInterval = TimeInterval(days: 2) | ||
// Default start uploading logs from 2 days ago | ||
var nextUploadStart = Date().addingTimeInterval(-backfillLimitInterval).dateFlooredToTimeInterval(logChunkDuration) | ||
|
||
// Fetch device log metadata records | ||
while true { | ||
do { | ||
// TODO: fetching logs is not implemented on the backend yet: awaiting https://tidepool.atlassian.net/browse/BACK-3011 | ||
// For now, we expect this to error, so the catch has been modified to break out of the loop. Once this is implemented, | ||
// We will want to retry on error, so the break should eventually be removed. | ||
|
||
var uploadMetadata = try await api.listDeviceLogs(start: Date().addingTimeInterval(-backfillLimitInterval), end: Date()) | ||
uploadMetadata.sort { a, b in | ||
return a.endAtTime > b.endAtTime | ||
} | ||
if let lastEnd = uploadMetadata.last?.endAtTime { | ||
nextUploadStart = lastEnd.dateFlooredToTimeInterval(logChunkDuration) | ||
} | ||
break | ||
} catch { | ||
log.error("Unable to fetch device log metadata: %@", String(describing: error)) | ||
try? await Task.sleep(nanoseconds: TimeInterval(minutes: 1).nanoseconds) | ||
break // TODO: Remove when backend has implemented device log metadata fetching (see above) | ||
} | ||
} | ||
// Start upload loop | ||
while true { | ||
let nextUploadEnd = nextUploadStart.addingTimeInterval(logChunkDuration) | ||
let timeUntilNextUpload = nextUploadEnd.timeIntervalSinceNow | ||
if timeUntilNextUpload > 0 { | ||
log.debug("Waiting %@s until next upload", String(timeUntilNextUpload)) | ||
try? await Task.sleep(nanoseconds: timeUntilNextUpload.nanoseconds) | ||
} | ||
await upload(from: nextUploadStart, to: nextUploadEnd) | ||
nextUploadStart = nextUploadEnd | ||
} | ||
} | ||
|
||
func upload(from start: Date, to end: Date) async { | ||
log.default("Uploading from %@ to %@", String(describing: start), String(describing: end)) | ||
do { | ||
if let logs = try await delegate?.fetchDeviceLogs(startDate: start, endDate: end) { | ||
log.default("Fetched %d logs", logs.count) | ||
if logs.count > 0 { | ||
let data = logs.map({ | ||
entry in | ||
TDeviceLogEntry( | ||
type: entry.type.tidepoolType, | ||
managerIdentifier: entry.managerIdentifier, | ||
deviceIdentifier: entry.deviceIdentifier ?? "unknown", | ||
timestamp: entry.timestamp, | ||
message: entry.message | ||
) | ||
}) | ||
do { | ||
let metatdata = try await api.uploadDeviceLogs(logs: data, start: start, end: end) | ||
log.default("metadata: %@", String(describing: metatdata)) | ||
print("hi") | ||
} catch { | ||
log.error("error uploading device logs:: %@", String(describing: error)) | ||
print("hi") | ||
} | ||
} | ||
} | ||
} catch { | ||
log.error("Upload failed: %@", String(describing: error)) | ||
} | ||
} | ||
} | ||
|
||
extension TimeInterval { | ||
var nanoseconds: UInt64 { | ||
return UInt64(self * 1e+9) | ||
} | ||
} | ||
|
||
extension DeviceLogEntryType { | ||
var tidepoolType: TDeviceLogEntry.TDeviceLogEntryType { | ||
switch self { | ||
case .send: | ||
return .send | ||
case .receive: | ||
return .receive | ||
case .error: | ||
return .error | ||
case .delegate: | ||
return .delegate | ||
case .delegateResponse: | ||
return .delegateResponse | ||
case .connection: | ||
return .connection | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this mean that the upload will potentially upload redundant data each time Tidepool Loop is restarted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I noted this in the ticket.