feat(logging): Replace Timber with Kermit for multiplatform logging (#4083)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2025-12-28 08:30:15 -06:00 committed by GitHub
parent a927481e4d
commit 0776e029f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
92 changed files with 727 additions and 957 deletions

View file

@ -62,7 +62,7 @@ dependencies {
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.hilt.lifecycle.viewmodel.compose)
implementation(libs.androidx.navigation.common)
implementation(libs.timber)
implementation(libs.kermit)
implementation(libs.coil)
implementation(libs.markdown.renderer.android)
implementation(libs.markdown.renderer.m3)

View file

@ -3,86 +3,9 @@
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>CommentWrapping:SignalMetrics.kt$Metric.SNR$/* Selected 12 as the max to get 4 equal vertical sections. */</ID>
<ID>ComposableParamOrder:DeviceMetrics.kt$DeviceMetricsChart</ID>
<ID>ComposableParamOrder:ElevationInfo.kt$ElevationInfo</ID>
<ID>ComposableParamOrder:EnvironmentCharts.kt$ChartContent</ID>
<ID>ComposableParamOrder:EnvironmentCharts.kt$EnvironmentMetricsChart</ID>
<ID>ComposableParamOrder:EnvironmentCharts.kt$MetricPlottingCanvas</ID>
<ID>ComposableParamOrder:HostMetricsLog.kt$HostMetricsItem</ID>
<ID>ComposableParamOrder:HostMetricsLog.kt$LogLine</ID>
<ID>ComposableParamOrder:LastHeardInfo.kt$LastHeardInfo</ID>
<ID>ComposableParamOrder:NodeFilterTextField.kt$NodeFilterTextField</ID>
<ID>ComposableParamOrder:NodeItem.kt$NodeItem</ID>
<ID>ComposableParamOrder:PaxMetrics.kt$PaxMetricsChart</ID>
<ID>ComposableParamOrder:PowerMetrics.kt$PowerMetricsChart</ID>
<ID>ComposableParamOrder:SatelliteCountInfo.kt$SatelliteCountInfo</ID>
<ID>ComposableParamOrder:SignalMetrics.kt$SignalMetricsChart</ID>
<ID>ComposableParamOrder:TracerouteButton.kt$TracerouteButton</ID>
<ID>LambdaParameterEventTrailing:TracerouteLog.kt$onNavigateUp</ID>
<ID>LongMethod:EnvironmentMetrics.kt$@Composable fun EnvironmentMetricsScreen(viewModel: MetricsViewModel = hiltViewModel(), onNavigateUp: () -&gt; Unit)</ID>
<ID>LongMethod:NodeDetailsSection.kt$@Composable private fun MainNodeDetails(node: Node)</ID>
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1000L</ID>
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1e-5</ID>
<ID>MagicNumber:MetricsViewModel.kt$MetricsViewModel$1e-7</ID>
<ID>ModifierMissing:CommonCharts.kt$ChartHeader</ID>
<ID>ModifierMissing:CommonCharts.kt$Legend</ID>
<ID>ModifierMissing:CommonCharts.kt$TimeLabels</ID>
<ID>ModifierMissing:DeviceMetrics.kt$DeviceMetricsScreen</ID>
<ID>ModifierMissing:EnvironmentMetrics.kt$EnvironmentMetricsScreen</ID>
<ID>ModifierMissing:HostMetricsLog.kt$HostMetricsLogScreen</ID>
<ID>ModifierMissing:NodeListScreen.kt$NodeListScreen</ID>
<ID>ModifierMissing:NodeStatusIcons.kt$NodeStatusIcons</ID>
<ID>ModifierMissing:PaxMetrics.kt$PaxMetricsItem</ID>
<ID>ModifierMissing:PaxMetrics.kt$PaxMetricsScreen</ID>
<ID>ModifierMissing:PositionLog.kt$PositionItem</ID>
<ID>ModifierMissing:PositionLog.kt$PositionLogScreen</ID>
<ID>ModifierMissing:PowerMetrics.kt$PowerMetricsScreen</ID>
<ID>ModifierMissing:SignalMetrics.kt$SignalMetricsScreen</ID>
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:EnvironmentCharts.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:EnvironmentCharts.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:PaxMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:PowerMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier = modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:SignalMetrics.kt$modifier.width(dp)</ID>
<ID>ModifierNotUsedAtRoot:TracerouteLog.kt$modifier = modifier.fillMaxSize().padding(innerPadding)</ID>
<ID>ModifierReused:DeviceMetrics.kt$Canvas(modifier = modifier.width(dp)) { val height = size.height val width = size.width for (i in telemetries.indices) { val telemetry = telemetries[i] /* x-value time */ val xRatio = (telemetry.time - oldest.time).toFloat() / timeDiff val x = xRatio * width /* Channel Utilization */ plotPoint( drawContext = drawContext, color = Device.CH_UTIL.color, x = x, value = telemetry.deviceMetrics.channelUtilization, divisor = MAX_PERCENT_VALUE, ) /* Air Utilization Transmit */ plotPoint( drawContext = drawContext, color = Device.AIR_UTIL.color, x = x, value = telemetry.deviceMetrics.airUtilTx, divisor = MAX_PERCENT_VALUE, ) } /* Battery Line */ var index = 0 while (index &lt; telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -&gt; val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = telemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Device.BATTERY.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } }</ID>
<ID>ModifierReused:DeviceMetrics.kt$HorizontalLinesOverlay( modifier.width(dp), lineColors = listOf(graphColor, Color.Yellow, Color.Red, graphColor, graphColor), )</ID>
<ID>ModifierReused:DeviceMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval())</ID>
<ID>ModifierReused:EnvironmentCharts.kt$Box( contentAlignment = Alignment.TopStart, modifier = modifier.horizontalScroll(state = scrollState, reverseScrolling = true), ) { HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor }) TimeAxisOverlay(modifier = modifier.width(dp), oldest = oldest, newest = newest, selectedTime.lineInterval()) MetricPlottingCanvas( modifier = modifier.width(dp), telemetries = telemetries, graphData = graphData, selectedTime = selectedTime, oldest = oldest, timeDiff = timeDiff, rightMin = rightMin, rightMax = rightMax, ) }</ID>
<ID>ModifierReused:EnvironmentCharts.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor })</ID>
<ID>ModifierReused:EnvironmentCharts.kt$MetricPlottingCanvas( modifier = modifier.width(dp), telemetries = telemetries, graphData = graphData, selectedTime = selectedTime, oldest = oldest, timeDiff = timeDiff, rightMin = rightMin, rightMax = rightMax, )</ID>
<ID>ModifierReused:EnvironmentCharts.kt$TimeAxisOverlay(modifier = modifier.width(dp), oldest = oldest, newest = newest, selectedTime.lineInterval())</ID>
<ID>ModifierReused:PaxMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { Color.LightGray })</ID>
<ID>ModifierReused:PaxMetrics.kt$Row(modifier = modifier.fillMaxWidth().fillMaxHeight(fraction = 0.33f)) { YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(start = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) Box( contentAlignment = Alignment.TopStart, modifier = Modifier.horizontalScroll(state = scrollState, reverseScrolling = true).weight(CHART_WEIGHT), ) { HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { Color.LightGray }) TimeAxisOverlay(modifier.width(dp), oldest = minTime, newest = maxTime, timeFrame.lineInterval()) Canvas(modifier = Modifier.width(dp).fillMaxHeight()) { val width = size.width val height = size.height fun xForTime(t: Int): Float = if (maxTime == minTime) width / 2 else (t - minTime).toFloat() / (maxTime - minTime) * width fun yForValue(v: Int): Float = height - (v - minValue) / (maxValue - minValue) * height fun drawLine(series: List&lt;Pair&lt;Int, Int&gt;&gt;, color: Color) { for (i in 1 until series.size) { drawLine( color = color, start = Offset(xForTime(series[i - 1].first), yForValue(series[i - 1].second)), end = Offset(xForTime(series[i].first), yForValue(series[i].second)), strokeWidth = 2.dp.toPx(), ) } } drawLine(bleSeries, PaxSeries.BLE.color) drawLine(wifiSeries, PaxSeries.WIFI.color) drawLine(totalSeries, PaxSeries.PAX.color) } } YAxisLabels( modifier = Modifier.weight(Y_AXIS_WEIGHT).fillMaxHeight().padding(end = 8.dp), labelColor = MaterialTheme.colorScheme.onSurface, minValue = minValue, maxValue = maxValue, ) }</ID>
<ID>ModifierReused:PaxMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = minTime, newest = maxTime, timeFrame.lineInterval())</ID>
<ID>ModifierReused:PowerMetrics.kt$Canvas(modifier = modifier.width(dp)) { val width = size.width val height = size.height /* Voltage */ var index = 0 while (index &lt; telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -&gt; val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveVoltage(selectedChannel, telemetry) - voltageMin) / voltageDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = VOLTAGE_COLOR, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } /* Current */ index = 0 while (index &lt; telemetries.size) { val path = Path() index = createPath( telemetries = telemetries, index = index, path = path, oldestTime = oldest.time, timeRange = timeDiff, width = width, timeThreshold = selectedTime.timeThreshold(), ) { i -&gt; val telemetry = telemetries.getOrNull(i) ?: telemetries.last() val ratio = (retrieveCurrent(selectedChannel, telemetry) - Power.CURRENT.min) / currentDiff val y = height - (ratio * height) return@createPath y } drawPath( path = path, color = Power.CURRENT.color, style = Stroke(width = GraphUtil.RADIUS, cap = StrokeCap.Round), ) } }</ID>
<ID>ModifierReused:PowerMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor })</ID>
<ID>ModifierReused:PowerMetrics.kt$TimeAxisOverlay(modifier.width(dp), oldest = oldest.time, newest = newest.time, selectedTime.lineInterval())</ID>
<ID>ModifierReused:PowerMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Power.CURRENT.color, minValue = Power.CURRENT.min, maxValue = Power.CURRENT.max, )</ID>
<ID>ModifierReused:PowerMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), VOLTAGE_COLOR, minValue = voltageMin, maxValue = voltageMax, )</ID>
<ID>ModifierReused:SignalMetrics.kt$Canvas(modifier = modifier.width(dp)) { val width = size.width /* Plot */ for (packet in meshPackets) { val xRatio = (packet.rxTime - oldest.rxTime).toFloat() / timeDiff val x = xRatio * width /* SNR */ plotPoint( drawContext = drawContext, color = Metric.SNR.color, x = x, value = packet.rxSnr - Metric.SNR.min, divisor = snrDiff, ) /* RSSI */ plotPoint( drawContext = drawContext, color = Metric.RSSI.color, x = x, value = packet.rxRssi - Metric.RSSI.min, divisor = rssiDiff, ) } }</ID>
<ID>ModifierReused:SignalMetrics.kt$HorizontalLinesOverlay(modifier.width(dp), lineColors = List(size = 5) { graphColor })</ID>
<ID>ModifierReused:SignalMetrics.kt$TimeAxisOverlay( modifier.width(dp), oldest = oldest.rxTime, newest = newest.rxTime, selectedTime.lineInterval(), )</ID>
<ID>ModifierReused:SignalMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Metric.RSSI.color, minValue = Metric.RSSI.min, maxValue = Metric.RSSI.max, )</ID>
<ID>ModifierReused:SignalMetrics.kt$YAxisLabels( modifier = modifier.weight(weight = Y_AXIS_WEIGHT), Metric.SNR.color, minValue = Metric.SNR.min, maxValue = Metric.SNR.max, )</ID>
<ID>ModifierWithoutDefault:CommonCharts.kt$modifier</ID>
<ID>ModifierWithoutDefault:EnvironmentCharts.kt$modifier</ID>
<ID>MultipleEmitters:CommonCharts.kt$LegendLabel</ID>
<ID>MultipleEmitters:DeviceMetrics.kt$DeviceMetricsChart</ID>
<ID>MultipleEmitters:EnvironmentCharts.kt$EnvironmentMetricsChart</ID>
<ID>MultipleEmitters:NodeDetailsSection.kt$MainNodeDetails</ID>
<ID>MultipleEmitters:PaxMetrics.kt$PaxMetricsChart</ID>
<ID>MultipleEmitters:PowerMetrics.kt$PowerMetricsChart</ID>
<ID>MultipleEmitters:RemoteDeviceActions.kt$RemoteDeviceActions</ID>
<ID>MultipleEmitters:SignalMetrics.kt$SignalMetricsChart</ID>
<ID>ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored</ID>
<ID>PreviewPublic:NodeItem.kt$NodeInfoPreview</ID>
<ID>PreviewPublic:NodeItem.kt$NodeInfoSimplePreview</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import co.touchlab.kermit.Logger
import com.mikepenz.markdown.m3.Markdown
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.stringResource
@ -50,7 +51,6 @@ import org.meshtastic.core.strings.download
import org.meshtastic.core.strings.error_no_app_to_handle_link
import org.meshtastic.core.strings.view_release
import org.meshtastic.core.ui.util.showToast
import timber.log.Timber
@Composable
fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modifier = Modifier) {
@ -72,7 +72,7 @@ fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modi
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
scope.launch { context.showToast(Res.string.error_no_app_to_handle_link) }
Timber.e(e)
Logger.e(e) { "Failed to handle release page URL" }
}
},
modifier = Modifier.weight(1f),
@ -88,7 +88,7 @@ fun FirmwareReleaseSheetContent(firmwareRelease: FirmwareRelease, modifier: Modi
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
scope.launch { context.showToast(Res.string.error_no_app_to_handle_link) }
Timber.e(e)
Logger.e(e) { "Failed to handle release zip URL" }
}
},
modifier = Modifier.weight(1f),

View file

@ -32,6 +32,7 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.core.net.toUri
import co.touchlab.kermit.Logger
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.stringResource
import org.meshtastic.core.database.model.Node
@ -47,7 +48,6 @@ import org.meshtastic.core.ui.component.icon
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.core.ui.util.showToast
import org.meshtastic.proto.ConfigProtos.Config.DisplayConfig.DisplayUnits
import timber.log.Timber
import java.net.URLEncoder
@OptIn(ExperimentalFoundationApi::class)
@ -82,7 +82,7 @@ fun LinkedCoordinatesItem(node: Node, displayUnits: DisplayUnits = DisplayUnits.
coroutineScope.launch { context.showToast("No application available to open this location!") }
}
} catch (ex: ActivityNotFoundException) {
Timber.d("Failed to open geo intent: $ex")
Logger.d { "Failed to open geo intent: $ex" }
}
},
onLongClick = {

View file

@ -20,6 +20,7 @@ package org.meshtastic.feature.node.detail
import android.os.RemoteException
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.touchlab.kermit.Logger
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@ -33,7 +34,6 @@ import org.meshtastic.core.model.TelemetryType
import org.meshtastic.core.service.ServiceAction
import org.meshtastic.core.service.ServiceRepository
import org.meshtastic.feature.node.component.NodeMenuAction
import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
@ -77,20 +77,20 @@ constructor(
try {
nodeRepository.setNodeNotes(nodeNum, notes)
} catch (ex: java.io.IOException) {
Timber.e("Set node notes IO error: ${ex.message}")
Logger.e { "Set node notes IO error: ${ex.message}" }
} catch (ex: java.sql.SQLException) {
Timber.e("Set node notes SQL error: ${ex.message}")
Logger.e { "Set node notes SQL error: ${ex.message}" }
}
}
private fun removeNode(nodeNum: Int) = viewModelScope.launch(Dispatchers.IO) {
Timber.i("Removing node '$nodeNum'")
Logger.i { "Removing node '$nodeNum'" }
try {
val packetId = serviceRepository.meshService?.packetId ?: return@launch
serviceRepository.meshService?.removeByNodenum(packetId, nodeNum)
nodeRepository.deleteNode(nodeNum)
} catch (ex: RemoteException) {
Timber.e("Remove node error: ${ex.message}")
Logger.e { "Remove node error: ${ex.message}" }
}
}
@ -98,7 +98,7 @@ constructor(
try {
serviceRepository.onServiceAction(ServiceAction.Ignore(node))
} catch (ex: RemoteException) {
Timber.e(ex, "Ignore node error")
Logger.e(ex) { "Ignore node error" }
}
}
@ -106,55 +106,55 @@ constructor(
try {
serviceRepository.onServiceAction(ServiceAction.Favorite(node))
} catch (ex: RemoteException) {
Timber.e(ex, "Favorite node error")
Logger.e(ex) { "Favorite node error" }
}
}
private fun requestUserInfo(destNum: Int) {
Timber.i("Requesting UserInfo for '$destNum'")
Logger.i { "Requesting UserInfo for '$destNum'" }
try {
serviceRepository.meshService?.requestUserInfo(destNum)
} catch (ex: RemoteException) {
Timber.e("Request NodeInfo error: ${ex.message}")
Logger.e { "Request NodeInfo error: ${ex.message}" }
}
}
private fun requestNeighborInfo(destNum: Int) {
Timber.i("Requesting NeighborInfo for '$destNum'")
Logger.i { "Requesting NeighborInfo for '$destNum'" }
try {
val packetId = serviceRepository.meshService?.packetId ?: return
serviceRepository.meshService?.requestNeighborInfo(packetId, destNum)
} catch (ex: RemoteException) {
Timber.e("Request NeighborInfo error: ${ex.message}")
Logger.e { "Request NeighborInfo error: ${ex.message}" }
}
}
private fun requestPosition(destNum: Int, position: Position = Position(0.0, 0.0, 0)) {
Timber.i("Requesting position for '$destNum'")
Logger.i { "Requesting position for '$destNum'" }
try {
serviceRepository.meshService?.requestPosition(destNum, position)
} catch (ex: RemoteException) {
Timber.e("Request position error: ${ex.message}")
Logger.e { "Request position error: ${ex.message}" }
}
}
private fun requestTelemetry(destNum: Int, type: TelemetryType) {
Timber.i("Requesting telemetry for '$destNum'")
Logger.i { "Requesting telemetry for '$destNum'" }
try {
val packetId = serviceRepository.meshService?.packetId ?: return
serviceRepository.meshService?.requestTelemetry(packetId, destNum, type.ordinal)
} catch (ex: RemoteException) {
Timber.e("Request telemetry error: ${ex.message}")
Logger.e { "Request telemetry error: ${ex.message}" }
}
}
private fun requestTraceroute(destNum: Int) {
Timber.i("Requesting traceroute for '$destNum'")
Logger.i { "Requesting traceroute for '$destNum'" }
try {
val packetId = serviceRepository.meshService?.packetId ?: return
serviceRepository.meshService?.requestTraceroute(packetId, destNum)
} catch (ex: RemoteException) {
Timber.e("Request traceroute error: ${ex.message}")
Logger.e { "Request traceroute error: ${ex.message}" }
}
}
}

View file

@ -18,13 +18,13 @@
package org.meshtastic.feature.node.list
import android.os.RemoteException
import co.touchlab.kermit.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.meshtastic.core.data.repository.NodeRepository
import org.meshtastic.core.database.model.Node
import org.meshtastic.core.service.ServiceAction
import org.meshtastic.core.service.ServiceRepository
import timber.log.Timber
import javax.inject.Inject
class NodeActions
@ -37,7 +37,7 @@ constructor(
try {
serviceRepository.onServiceAction(ServiceAction.Favorite(node))
} catch (ex: RemoteException) {
Timber.e(ex, "Favorite node error")
Logger.e(ex) { "Favorite node error" }
}
}
@ -45,18 +45,18 @@ constructor(
try {
serviceRepository.onServiceAction(ServiceAction.Ignore(node))
} catch (ex: RemoteException) {
Timber.e(ex, "Ignore node error")
Logger.e(ex) { "Ignore node error" }
}
}
suspend fun removeNode(nodeNum: Int) = withContext(Dispatchers.IO) {
Timber.i("Removing node '$nodeNum'")
Logger.i { "Removing node '$nodeNum'" }
try {
val packetId = serviceRepository.meshService?.packetId ?: return@withContext
serviceRepository.meshService?.removeByNodenum(packetId, nodeNum)
nodeRepository.deleteNode(nodeNum)
} catch (ex: RemoteException) {
Timber.e("Remove node error: ${ex.message}")
Logger.e { "Remove node error: ${ex.message}" }
}
}
}

View file

@ -17,8 +17,8 @@
package org.meshtastic.feature.node.metrics
import co.touchlab.kermit.Logger
import org.meshtastic.proto.MeshProtos
import timber.log.Timber
/**
* Safely extracts the hardware model number from a HardwareModel enum.
@ -34,6 +34,6 @@ import timber.log.Timber
fun MeshProtos.HardwareModel.safeNumber(fallbackValue: Int = -1): Int = try {
this.number
} catch (e: IllegalArgumentException) {
Timber.w("Unknown hardware model enum value: $this, using fallback value: $fallbackValue")
Logger.w { "Unknown hardware model enum value: $this, using fallback value: $fallbackValue" }
fallbackValue
}

View file

@ -23,6 +23,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.toRoute
import co.touchlab.kermit.Logger
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
@ -63,7 +64,6 @@ import org.meshtastic.proto.MeshProtos
import org.meshtastic.proto.MeshProtos.MeshPacket
import org.meshtastic.proto.Portnums
import org.meshtastic.proto.Portnums.PortNum
import timber.log.Timber
import java.io.BufferedWriter
import java.io.FileNotFoundException
import java.io.FileWriter
@ -343,16 +343,16 @@ constructor(
}
}
Timber.d("MetricsViewModel created")
Logger.d { "MetricsViewModel created" }
} else {
Timber.d("MetricsViewModel: destNum is null, skipping metrics flows initialization.")
Logger.d { "MetricsViewModel: destNum is null, skipping metrics flows initialization." }
}
}
}
override fun onCleared() {
super.onCleared()
Timber.d("MetricsViewModel cleared")
Logger.d { "MetricsViewModel cleared" }
}
fun setTimeFrame(timeFrame: TimeFrame) {
@ -395,7 +395,7 @@ constructor(
}
}
} catch (ex: FileNotFoundException) {
Timber.e(ex, "Can't write file error")
Logger.e(ex) { "Can't write file error" }
}
}
}