fix(logs): §C+E · purge dead code 활성화 + record() 통합 관문 (cloud-mvp d8425d0 이식)
This commit is contained in:
@@ -63,6 +63,18 @@ class MainActivity : ComponentActivity() {
|
|||||||
com.medithings.vesiscan.telemetry.AlarmAggregator.start()
|
com.medithings.vesiscan.telemetry.AlarmAggregator.start()
|
||||||
com.medithings.vesiscan.telemetry.NotificationSubscriber.start(this)
|
com.medithings.vesiscan.telemetry.NotificationSubscriber.start(this)
|
||||||
|
|
||||||
|
// 2026-08-04: LOG_STORAGE_ANALYSIS §C fix — 앱 시작 시 오래된 로그 자동 정리.
|
||||||
|
// 실패해도 필수기능 영향 없음 (silent · UC-05).
|
||||||
|
try {
|
||||||
|
val app = applicationContext
|
||||||
|
com.medithings.vesiscan.services.MeasurementLogService.getInstance(app)
|
||||||
|
.purgeOldLogs(keepDays = 365)
|
||||||
|
com.medithings.vesiscan.services.BleDebugLogger.getInstance(app)
|
||||||
|
.purgeOldLogs(keepDays = 7)
|
||||||
|
com.medithings.vesiscan.services.AdcCsvLogger.purgeOldSessions(keepDays = 30)
|
||||||
|
com.medithings.vesiscan.services.ClinicalSessionStore.purgeOldSessions(keepDays = 90)
|
||||||
|
} catch (_: Exception) { }
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
setContent {
|
setContent {
|
||||||
|
|||||||
@@ -121,4 +121,21 @@ object AdcCsvLogger {
|
|||||||
}
|
}
|
||||||
} catch (_: Exception) {}
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VesiScan_ADC/ 폴더의 keepDays 일 이전 CSV 삭제 (§C purge).
|
||||||
|
* 2026-08-04: LOG_STORAGE_ANALYSIS Priority 3 — 시간당 40MB 누적 방지.
|
||||||
|
*/
|
||||||
|
fun purgeOldSessions(keepDays: Int = 30) {
|
||||||
|
try {
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar.add(Calendar.DAY_OF_YEAR, -keepDays)
|
||||||
|
val cutoff = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(calendar.time)
|
||||||
|
val dir = getDir()
|
||||||
|
dir.listFiles { f -> f.extension == "csv" }?.forEach { file ->
|
||||||
|
val prefix = file.nameWithoutExtension.take(10)
|
||||||
|
if (prefix < cutoff) file.delete()
|
||||||
|
}
|
||||||
|
} catch (_: Exception) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -384,4 +384,23 @@ object ClinicalSessionStore {
|
|||||||
lastFinalizedFolder = null
|
lastFinalizedFolder = null
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VesiScan_Sessions/ 폴더의 keepDays 일 이전 세션 삭제 (§C purge).
|
||||||
|
* 2026-08-04: LOG_STORAGE_ANALYSIS Priority 3 — 시간당 최대 40MB 누적 방지.
|
||||||
|
* lastModified 기준. currentSession 진행 중 폴더 제외.
|
||||||
|
*/
|
||||||
|
fun purgeOldSessions(keepDays: Int = 90) {
|
||||||
|
runCatching {
|
||||||
|
val cutoffMs = System.currentTimeMillis() - keepDays * 24L * 3600L * 1000L
|
||||||
|
val activeFolder = currentLogDir()
|
||||||
|
val downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
|
val root = File(downloads, "VesiScan_Sessions")
|
||||||
|
if (!root.exists() || !root.isDirectory) return@runCatching
|
||||||
|
root.listFiles { f -> f.isDirectory }?.forEach { folder ->
|
||||||
|
if (folder == activeFolder) return@forEach
|
||||||
|
if (folder.lastModified() < cutoffMs) folder.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,38 @@ class MeasurementLogService private constructor(private val context: Context) {
|
|||||||
|
|
||||||
// -- Log Events --
|
// -- Log Events --
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 통합 관문 (2026-08-04 · LOG_STORAGE_ANALYSIS §E fix).
|
||||||
|
* 호출부는 이 함수 하나만 호출하면 4개 sink 자동 fan-out.
|
||||||
|
* 기존 개별 함수는 그대로 유지 (backwards compat).
|
||||||
|
*/
|
||||||
|
fun record(outcome: MeasurementOutcome): Int {
|
||||||
|
val scanId = outcome.scanId
|
||||||
|
?: com.medithings.vesiscan.services.AdcCsvLogger.nextScanId()
|
||||||
|
runCatching {
|
||||||
|
com.medithings.vesiscan.ble.BleManager.current?.debugLogger?.measurementResult(
|
||||||
|
volumeMl = outcome.volumeMl,
|
||||||
|
lrRatio = outcome.lrRatio,
|
||||||
|
validChannels = outcome.validChannels,
|
||||||
|
urineLines = outcome.urineLines,
|
||||||
|
otsuThreshold = outcome.otsuThreshold,
|
||||||
|
scanId = scanId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
runCatching {
|
||||||
|
logMeasurement(outcome.volumeMl, outcome.channels, outcome.rawADC, scanId = scanId)
|
||||||
|
}
|
||||||
|
runCatching {
|
||||||
|
com.medithings.vesiscan.services.AdcCsvLogger.log(
|
||||||
|
outcome.rawADC,
|
||||||
|
outcome.volumeMl,
|
||||||
|
outcome.lrRatio,
|
||||||
|
scanId = scanId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return scanId
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a spot measurement result.
|
* Log a spot measurement result.
|
||||||
*/
|
*/
|
||||||
@@ -247,3 +279,18 @@ data class ChannelLogEntry(
|
|||||||
val urineLen: Int? = null,
|
val urineLen: Int? = null,
|
||||||
val score: Double? = null
|
val score: Double? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 단일 측정 사이클의 모든 sink 에 fan-out 될 결과 (2026-08-04 · §E 통합 관문 입력).
|
||||||
|
* scanId = null 이면 record() 가 자동 발급.
|
||||||
|
*/
|
||||||
|
data class MeasurementOutcome(
|
||||||
|
val volumeMl: Double?,
|
||||||
|
val lrRatio: Double = 1.0,
|
||||||
|
val rawADC: List<List<UShort>>,
|
||||||
|
val channels: List<ChannelLogEntry>,
|
||||||
|
val validChannels: Int = 0,
|
||||||
|
val urineLines: List<Int> = emptyList(),
|
||||||
|
val otsuThreshold: Double = 0.0,
|
||||||
|
val scanId: Int? = null,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user