mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor(logging): Reduce log noise by lowering severity of common errors (#4591)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
7ffbbd6113
commit
f012e3818d
14 changed files with 91 additions and 56 deletions
|
|
@ -24,6 +24,7 @@ import androidx.lifecycle.MutableLiveData
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
|
||||
import com.geeksville.mesh.repository.network.NetworkRepository
|
||||
import com.geeksville.mesh.repository.network.NetworkRepository.Companion.toAddressString
|
||||
|
|
@ -51,8 +52,6 @@ import org.meshtastic.core.strings.meshtastic
|
|||
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
|
||||
import javax.inject.Inject
|
||||
|
||||
// ... (DeviceListEntry sealed class remains the same) ...
|
||||
|
||||
@HiltViewModel
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
class BTScanModel
|
||||
|
|
@ -209,11 +208,20 @@ constructor(
|
|||
changeDeviceAddress(entry.fullAddress)
|
||||
} catch (ex: SecurityException) {
|
||||
Logger.w(ex) { "Bonding failed for ${entry.peripheral.address.anonymize} Permissions not granted" }
|
||||
serviceRepository.setErrorMessage("Bonding failed: ${ex.message} Permissions not granted")
|
||||
serviceRepository.setErrorMessage(
|
||||
text = "Bonding failed: ${ex.message} Permissions not granted",
|
||||
severity = Severity.Warn,
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
// Bonding is often flaky and can fail for many reasons (timeout, user cancel, etc)
|
||||
Logger.w(ex) { "Bonding failed for ${entry.peripheral.address.anonymize}" }
|
||||
serviceRepository.setErrorMessage("Bonding failed: ${ex.message}")
|
||||
val message = ex.message ?: ""
|
||||
if (message.contains("Received bond state changed 11")) {
|
||||
// This is a known issue where bonding is still in progress, ignore as error
|
||||
Logger.d { "Bonding still in progress for ${entry.peripheral.address.anonymize}" }
|
||||
} else {
|
||||
Logger.w(ex) { "Bonding failed for ${entry.peripheral.address.anonymize}" }
|
||||
serviceRepository.setErrorMessage(text = "Bonding failed: ${ex.message}", severity = Severity.Warn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,10 +70,12 @@ constructor(
|
|||
fun disconnect() {
|
||||
Logger.i { "MQTT Disconnected" }
|
||||
mqttClient?.apply {
|
||||
ignoreException { disconnect() }
|
||||
close(true)
|
||||
mqttClient = null
|
||||
if (isConnected) {
|
||||
ignoreException { disconnect() }
|
||||
}
|
||||
ignoreException { close(true) }
|
||||
}
|
||||
mqttClient = null
|
||||
}
|
||||
|
||||
val proxyMessageFlow: Flow<MqttClientProxyMessage> = callbackFlow {
|
||||
|
|
@ -166,7 +168,11 @@ constructor(
|
|||
val token = mqttClient?.publish(topic, data, DEFAULT_QOS, retained)
|
||||
Logger.i { "MQTT Publish messageId: ${token?.messageId}" }
|
||||
} catch (ex: Exception) {
|
||||
Logger.e { "MQTT Publish error: ${ex.message}" }
|
||||
if (ex.message?.contains("Client is disconnected") == true) {
|
||||
Logger.w { "MQTT Publish skipped: Client is disconnected" }
|
||||
} else {
|
||||
Logger.e(ex) { "MQTT Publish error: ${ex.message}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,8 @@ constructor(
|
|||
0
|
||||
}
|
||||
thrown?.let { e ->
|
||||
Logger.e(e) { "[$address] Serial error after ${uptime}ms: ${e.message}" }
|
||||
// USB errors are common when unplugging; log as warning to avoid Crashlytics noise
|
||||
Logger.w(e) { "[$address] Serial error after ${uptime}ms: ${e.message}" }
|
||||
}
|
||||
Logger.w {
|
||||
"[$address] Serial device disconnected - " +
|
||||
|
|
|
|||
|
|
@ -84,7 +84,8 @@ constructor(
|
|||
try {
|
||||
stream.write(p)
|
||||
} catch (ex: IOException) {
|
||||
Logger.e(ex) { "[$address] TCP write error: ${ex.message}" }
|
||||
// TCP write errors are common when the connection is lost; log as warning to avoid Crashlytics noise
|
||||
Logger.w(ex) { "[$address] TCP write error: ${ex.message}" }
|
||||
onDeviceDisconnect(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +96,8 @@ constructor(
|
|||
try {
|
||||
stream.flush()
|
||||
} catch (ex: IOException) {
|
||||
Logger.e(ex) { "[$address] TCP flush error: ${ex.message}" }
|
||||
// TCP flush errors are common when the connection is lost; log as warning to avoid Crashlytics noise
|
||||
Logger.w(ex) { "[$address] TCP flush error: ${ex.message}" }
|
||||
onDeviceDisconnect(false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,29 +42,30 @@ internal class SerialConnectionImpl(
|
|||
@Suppress("TooGenericExceptionCaught")
|
||||
override fun sendBytes(bytes: ByteArray) {
|
||||
ioRef.get()?.let {
|
||||
Logger.d { "writing ${bytes.size} byte(s }" }
|
||||
Logger.d { "writing ${bytes.size} byte(s)" }
|
||||
try {
|
||||
it.writeAsync(bytes)
|
||||
} catch (e: BufferOverflowException) {
|
||||
Logger.e(e) { "Buffer overflow while writing to serial port" }
|
||||
Logger.w(e) { "Buffer overflow while writing to serial port" }
|
||||
} catch (e: Exception) {
|
||||
Logger.e(e) { "Failed to write to serial port" }
|
||||
// USB disconnections often cause IOExceptions here; log as warning to avoid Crashlytics noise
|
||||
Logger.w(e) { "Failed to write to serial port (likely disconnected)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun close(waitForStopped: Boolean) {
|
||||
ignoreException {
|
||||
if (closed.compareAndSet(false, true)) {
|
||||
ioRef.get()?.stop()
|
||||
if (closed.compareAndSet(false, true)) {
|
||||
ignoreException(silent = true) { ioRef.get()?.stop() }
|
||||
ignoreException(silent = true) {
|
||||
port.close() // This will cause the reader thread to exit
|
||||
}
|
||||
}
|
||||
|
||||
// Allow a short amount of time for the manager to quit (so the port can be cleanly closed)
|
||||
if (waitForStopped) {
|
||||
Logger.d { "Waiting for USB manager to stop..." }
|
||||
closedLatch.await(1.seconds)
|
||||
}
|
||||
// Allow a short amount of time for the manager to quit (so the port can be cleanly closed)
|
||||
if (waitForStopped) {
|
||||
Logger.d { "Waiting for USB manager to stop..." }
|
||||
ignoreException(silent = true) { closedLatch.await(1.seconds) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,11 +100,9 @@ internal class SerialConnectionImpl(
|
|||
|
||||
override fun onRunError(e: Exception?) {
|
||||
closed.set(true)
|
||||
ignoreException {
|
||||
port.dtr = false
|
||||
port.rts = false
|
||||
port.close()
|
||||
}
|
||||
// Connection is already failing, don't try to set DTR/RTS as it will just throw more
|
||||
// IOExceptions
|
||||
ignoreException(silent = true) { port.close() }
|
||||
closedLatch.countDown()
|
||||
listener.onDisconnected(e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.geeksville.mesh.service
|
|||
|
||||
import android.util.Log
|
||||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import com.geeksville.mesh.BuildConfig
|
||||
import com.geeksville.mesh.concurrent.handledLaunch
|
||||
import com.geeksville.mesh.repository.radio.InterfaceId
|
||||
|
|
@ -459,7 +460,7 @@ constructor(
|
|||
val payload = packet.decoded?.payload ?: return
|
||||
val r = Routing.ADAPTER.decodeOrNull(payload, Logger) ?: return
|
||||
if (r.error_reason == Routing.Error.DUTY_CYCLE_LIMIT) {
|
||||
serviceRepository.setErrorMessage(getString(Res.string.error_duty_cycle))
|
||||
serviceRepository.setErrorMessage(getString(Res.string.error_duty_cycle), Severity.Warn)
|
||||
}
|
||||
handleAckNak(
|
||||
packet.decoded?.request_id ?: 0,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package com.geeksville.mesh.service
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import co.touchlab.kermit.Severity
|
||||
import com.geeksville.mesh.repository.network.MQTTRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -49,7 +50,12 @@ constructor(
|
|||
mqttMessageFlow =
|
||||
mqttRepository.proxyMessageFlow
|
||||
.onEach { message -> packetHandler.sendToRadio(ToRadio(mqttClientProxyMessage = message)) }
|
||||
.catch { throwable -> serviceRepository.setErrorMessage("MqttClientProxy failed: $throwable") }
|
||||
.catch { throwable ->
|
||||
serviceRepository.setErrorMessage(
|
||||
text = "MqttClientProxy failed: $throwable",
|
||||
severity = Severity.Warn,
|
||||
)
|
||||
}
|
||||
.launchIn(scope)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,6 +196,10 @@ constructor(
|
|||
throw RadioNotConnectedException()
|
||||
}
|
||||
sendToRadio(ToRadio(packet = packet))
|
||||
} catch (ex: RadioNotConnectedException) {
|
||||
// Expected when radio is not connected, log as warning to avoid Crashlytics noise
|
||||
Logger.w(ex) { "sendToRadio skipped: Not connected to radio" }
|
||||
deferred.complete(false)
|
||||
} catch (ex: Exception) {
|
||||
Logger.e(ex) { "sendToRadio error: ${ex.message}" }
|
||||
deferred.complete(false)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||
private const val RSSI_DELAY = 10
|
||||
private const val RSSI_TIMEOUT = 5
|
||||
|
||||
@Suppress("LongMethod", "LoopWithTooManyJumpStatements")
|
||||
@Suppress("LongMethod", "LoopWithTooManyJumpStatements", "TooGenericExceptionCaught")
|
||||
@Composable
|
||||
fun CurrentlyConnectedInfo(
|
||||
node: Node,
|
||||
|
|
@ -80,13 +80,17 @@ fun CurrentlyConnectedInfo(
|
|||
rssi = withTimeout(RSSI_TIMEOUT.seconds) { bleDevice.peripheral.readRssi() }
|
||||
delay(RSSI_DELAY.seconds)
|
||||
} catch (e: PeripheralNotConnectedException) {
|
||||
Logger.e(e) { "Failed to read RSSI ${e.message}" }
|
||||
Logger.w(e) { "Failed to read RSSI ${e.message}" }
|
||||
break
|
||||
} catch (e: OperationFailedException) {
|
||||
Logger.e(e) { "Failed to read RSSI ${e.message}" }
|
||||
// RSSI reading failures are common when disconnecting; log as warning to avoid Crashlytics noise
|
||||
Logger.w(e) { "Failed to read RSSI ${e.message}" }
|
||||
break
|
||||
} catch (e: SecurityException) {
|
||||
Logger.e(e) { "Failed to read RSSI ${e.message}" }
|
||||
Logger.w(e) { "Failed to read RSSI ${e.message}" }
|
||||
break
|
||||
} catch (e: Exception) {
|
||||
Logger.w(e) { "Unexpected error reading RSSI: ${e.message}" }
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -14,7 +14,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.geeksville.mesh.util
|
||||
|
||||
import android.os.RemoteException
|
||||
|
|
@ -57,7 +56,7 @@ fun ignoreException(silent: Boolean = false, inner: () -> Unit) {
|
|||
inner()
|
||||
} catch (ex: Throwable) {
|
||||
// DO NOT THROW users expect we have fully handled/discarded the exception
|
||||
if (!silent) Logger.e(ex) { "ignoring exception" }
|
||||
if (!silent) Logger.w(ex) { "ignoring exception" }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue