如何在Android Studio中开启Paho Mqtt Android Client的mqttv3日志
问题背景
原本使用 org.eclipse.paho.client.mqttv3:1.2.0 搭配 org.eclipse.paho.android.service:1.1.1 可以正常连接Mosquitto Broker(明文1883、加密8883/8884/8885均正常),但为了连接AWS IoT需要升级到支持SNI的 mqttv3:1.2.3+ 版本,发现只要升级到 1.2.1+ 就连接失败。现有MqttAndroidClient的Trace日志仅提示connect fail, call connect to reconnect.reason:MqttException,无法获取底层mqttv3的报错细节。
快速排查:打印完整异常栈轨迹
不用先开启复杂的mqttv3日志,首先在连接失败的回调中打印完整异常栈,就能直接获取MqttException的底层原因:
mqttClient.connect(mqttConnectOptions, null, object : IMqttActionListener { override fun onSuccess(asyncActionToken: IMqttToken?) { // 连接成功逻辑 } override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) { exception?.let { Log.e("MQTT_CONNECT", "连接失败", it) // 传入Throwable会自动打印完整栈轨迹 if (it is MqttException) { Log.e("MQTT_CONNECT", "MQTT错误码: ${it.reasonCode}") } } } })
通过完整栈轨迹,你可以直接定位是TLS握手失败、协议版本不兼容还是其他底层问题,这是最直接的排查方式。
开启mqttv3底层日志
如果需要更详细的mqttv3内部运行日志,可以通过以下两种方式实现:
方式1:反射获取内部MqttAsyncClient并打印调试信息
MqttAndroidClient内部持有一个MqttAsyncClient实例,通过反射可以获取它并调用调试方法:
try { // 反射获取MqttAndroidClient内部的client字段 val clientField = MqttAndroidClient::class.java.getDeclaredField("client") clientField.isAccessible = true val mqttAsyncClient = clientField.get(mqttClient) as MqttAsyncClient // 打印客户端调试信息 val debug = mqttAsyncClient.debug debug.dumpClientDebug() // 将mqttv3的日志输出到Logcat val logger = java.util.logging.Logger.getLogger("org.eclipse.paho.client.mqttv3") logger.level = java.util.logging.Level.FINEST logger.addHandler(object : java.util.logging.Handler() { override fun publish(record: java.util.logging.LogRecord?) { record?.let { val logLevel = when (it.level) { java.util.logging.Level.SEVERE -> Log.ERROR java.util.logging.Level.WARNING -> Log.WARN java.util.logging.Level.INFO -> Log.INFO java.util.logging.Level.CONFIG -> Log.DEBUG java.util.logging.Level.FINE, java.util.logging.Level.FINER, java.util.logging.Level.FINEST -> Log.VERBOSE else -> Log.DEBUG } Log.println(logLevel, "MQTTv3", "${it.loggerName}: ${it.message}") } } override fun flush() {} override fun close() {} }) } catch (e: NoSuchFieldException) { Log.e("MQTT_LOG", "反射获取内部client失败", e) } catch (e: IllegalAccessException) { Log.e("MQTT_LOG", "访问内部client字段失败", e) }
注意:反射依赖于MqttAndroidClient的内部实现,不同版本可能字段名或结构变化,若失效需检查对应版本的源码。
方式2:配置Android的java.util.logging系统
mqttv3底层使用java.util.logging框架,你可以在Application初始化时配置全局日志处理器,将mqttv3的日志定向到Logcat:
class MyApp : Application() { override fun onCreate() { super.onCreate() val logger = java.util.logging.Logger.getLogger("org.eclipse.paho") logger.level = java.util.logging.Level.FINEST logger.useParentHandlers = false logger.addHandler(LogcatHandler()) } private class LogcatHandler : java.util.logging.Handler() { override fun publish(record: java.util.logging.LogRecord?) { record?.let { val priority = when (it.level) { java.util.logging.Level.SEVERE -> Log.ERROR java.util.logging.Level.WARNING -> Log.WARN java.util.logging.Level.INFO -> Log.INFO java.util.logging.Level.CONFIG -> Log.DEBUG java.util.logging.Level.FINE, java.util.logging.Level.FINER, java.util.logging.Level.FINEST -> Log.VERBOSE else -> Log.DEBUG } Log.println(priority, "MQTT", "[${it.level.name}] ${it.loggerName}: ${it.message}") } } override fun flush() {} override fun close() {} } }
可能的排查方向
升级到mqttv3 1.2.1+后连接失败,常见原因包括:
- TLS配置变化:新版本默认启用了TLS 1.2+或SNI扩展,而Mosquitto未配置对应支持
- 协议版本不兼容:新版本默认使用MQTT 3.1.1,若Mosquitto仅支持旧版本需手动指定协议
- 证书验证逻辑变化:新版本对证书链的验证更严格
内容的提问来源于stack exchange,提问作者Scott Lohr

