kernel: Optimized log timestamp processing and added manual refresh functionality.
This commit is contained in:
@@ -33,25 +33,21 @@ static struct workqueue_struct *sulog_workqueue;
|
||||
static struct work_struct sulog_work;
|
||||
static bool sulog_enabled = true;
|
||||
|
||||
extern struct timezone sys_tz;
|
||||
|
||||
static void get_timestamp(char *buf, size_t len)
|
||||
{
|
||||
struct timespec64 ts, boottime;
|
||||
struct timespec64 ts;
|
||||
struct tm tm;
|
||||
s64 real_time;
|
||||
|
||||
ktime_get_boottime_ts64(&boottime);
|
||||
ktime_get_ts64(&ts);
|
||||
ktime_get_real_ts64(&ts);
|
||||
|
||||
real_time = boottime.tv_sec;
|
||||
if (real_time < 946684800) {
|
||||
real_time = ts.tv_sec;
|
||||
}
|
||||
time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm);
|
||||
|
||||
time64_to_tm(real_time, 0, &tm);
|
||||
|
||||
snprintf(buf, len, "%04ld-%02d-%02d %02d:%02d:%02d",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
snprintf(buf, len,
|
||||
"%04ld-%02d-%02d %02d:%02d:%02d",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
|
||||
static void get_full_comm(char *comm_buf, size_t buf_len)
|
||||
|
||||
@@ -36,8 +36,11 @@ import com.sukisu.ultra.ui.theme.getCardColors
|
||||
import com.sukisu.ultra.ui.theme.getCardElevation
|
||||
import com.sukisu.ultra.ui.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.*
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
private val SPACING_SMALL = 4.dp
|
||||
private val SPACING_MEDIUM = 8.dp
|
||||
@@ -61,6 +64,9 @@ enum class LogType(val displayName: String, val color: Color) {
|
||||
UNKNOWN("UNKNOWN", Color(0xFF757575))
|
||||
}
|
||||
|
||||
private val utcFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
private val localFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Destination<RootGraph>
|
||||
@Composable
|
||||
@@ -91,6 +97,19 @@ fun LogViewerScreen(navigator: DestinationsNavigator) {
|
||||
val loadingDialog = rememberLoadingDialog()
|
||||
val confirmDialog = rememberConfirmDialog()
|
||||
|
||||
val onManualRefresh: () -> Unit = {
|
||||
scope.launch {
|
||||
loadLogs(selectedLogFile) { logEntries = it }
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(selectedLogFile) {
|
||||
while (true) {
|
||||
delay(3_000)
|
||||
onManualRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(selectedLogFile) {
|
||||
loadLogs(selectedLogFile) { entries ->
|
||||
logEntries = entries
|
||||
@@ -106,6 +125,7 @@ fun LogViewerScreen(navigator: DestinationsNavigator) {
|
||||
searchQuery = searchQuery,
|
||||
onSearchQueryChange = { searchQuery = it },
|
||||
onSearchToggle = { showSearchBar = !showSearchBar },
|
||||
onRefresh = onManualRefresh,
|
||||
onClearLogs = {
|
||||
scope.launch {
|
||||
val result = confirmDialog.awaitConfirm(
|
||||
@@ -435,6 +455,7 @@ private fun LogViewerTopBar(
|
||||
searchQuery: String,
|
||||
onSearchQueryChange: (String) -> Unit,
|
||||
onSearchToggle: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
onClearLogs: () -> Unit
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
@@ -467,6 +488,12 @@ private fun LogViewerTopBar(
|
||||
contentDescription = stringResource(R.string.log_viewer_search)
|
||||
)
|
||||
}
|
||||
IconButton(onClick = onRefresh) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Refresh,
|
||||
contentDescription = stringResource(R.string.log_viewer_refresh)
|
||||
)
|
||||
}
|
||||
IconButton(onClick = onClearLogs) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.DeleteSweep,
|
||||
@@ -574,12 +601,21 @@ private fun parseLogEntries(logContent: String): List<LogEntry> {
|
||||
}
|
||||
.reversed() // 最新的日志在前面
|
||||
}
|
||||
private fun utcToLocal(utc: String): String {
|
||||
return try {
|
||||
val instant = LocalDateTime.parse(utc, utcFormatter).atOffset(ZoneOffset.UTC).toInstant()
|
||||
val local = instant.atZone(ZoneId.systemDefault())
|
||||
local.format(localFormatter)
|
||||
} catch (_: Exception) {
|
||||
utc
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseLogLine(line: String): LogEntry? {
|
||||
// 解析格式: [timestamp] TYPE: UID=xxx COMM=xxx ...
|
||||
val timestampRegex = """\[(.*?)]""".toRegex()
|
||||
val timestampMatch = timestampRegex.find(line) ?: return null
|
||||
val timestamp = timestampMatch.groupValues[1]
|
||||
val timestamp = utcToLocal(timestampMatch.groupValues[1])
|
||||
|
||||
val afterTimestamp = line.substring(timestampMatch.range.last + 1).trim()
|
||||
val parts = afterTimestamp.split(":")
|
||||
|
||||
Reference in New Issue
Block a user