跳转到正文
YGJoon 技术博客

Android Kotlin 日志监控与可观测性

发布于:
·982 字 · 约 2 分钟·作者:
移动端可观测性搭建:日志分级与脱敏、崩溃上报、性能指标采集,从本地调试到线上仪表板的完整链路。
Android Kotlin 日志监控与可观测性文章封面
目录

可观测性组件

维度工具目标
日志Timber、Logger、Logcat记录调试与业务轨迹
崩溃Firebase Crashlytics、Sentry捕获崩溃与非致命异常
性能Firebase Performance、Macrobenchmark监控启动、网络、帧率
业务指标自建埋点、Analytics SDK分析用户行为

日志体系

Kotlin 封装

object AppLogger {
    fun init() {
        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        } else {
            Timber.plant(ReleaseTree())
        }
    }

    fun d(message: String, vararg args: Any?) = Timber.d(message, *args)
    fun e(throwable: Throwable, message: String, vararg args: Any?) = Timber.e(throwable, message, *args)
}

class ReleaseTree : Timber.Tree() {
    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        if (priority >= Log.ERROR) {
            Crashlytics.log(priority, tag, message)
            t?.let { Crashlytics.recordException(it) }
        }
    }
}

日志脱敏

fun String.maskMiddle(): String {
    return if (length > 7) replaceRange(3, length - 4, "***") else this
}

AppLogger.d("phone=%s", phone.maskMiddle())

崩溃监控

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        FirebaseApp.initializeApp(this)
        AppLogger.init()
    }
}
val crashHandler = CoroutineExceptionHandler { _, throwable ->
    Crashlytics.recordException(throwable)
}

viewModelScope.launch(crashHandler) { ... }

性能指标

class MetricInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val start = SystemClock.elapsedRealtime()
        return try {
            chain.proceed(chain.request())
        } finally {
            val cost = SystemClock.elapsedRealtime() - start
            Metrics.logNetwork(chain.request().url.toString(), cost)
        }
    }
}

事件追踪与关联

val traceId = UUID.randomUUID().toString()
AppLogger.d("traceId=%s start login", traceId)

Crashlytics.setCustomKey("traceId", traceId)

Monitoring 仪表板

{
  "alerts": [
    {
      "metric": "app_startup_time",
      "condition": "> 3000",
      "notify": ["lark-webhook-url"]
    }
  ]
}

本地调试技巧

常见问题

问题原因解决方案
日志过多调试日志在 Release 未关闭根据 BuildConfig 控制日志级别
崩溃无 Trace混淆未保留符号表上传符号文件,保留 Crashlytics 映射
指标不准确采集点不统一统一埋点规范与时钟,避免重复上报

实战案例:日志的”三级火箭”

我在货运项目(某物流冷链项目)里用了 logger: ^2.6.0(pubspec 可查),Android 侧对等的是 Timber。但”打日志”只是第一级,完整的可观测性是三级火箭:

  1. 本地日志(Timber / logger):开发期看,Timber.plant(DebugTree()),release 包用 ReleaseTree 只上报不打印。千万别把用户隐私打进日志——身份证号、token 打进 logcat,等于明文广播。
  2. 崩溃上报(Firebase Crashlytics / Sentry):flutter_brightness 这种桌面应用我没接(用户量小),但货运这种 toB 应用必须接。Crashlytics 的 recordException + 自定义 key(用户 id、页面),是线上救火的核心依据。
  3. 业务埋点(Firebase Analytics / 自研):PV/UV、关键转化漏斗。注意国内合规:埋点 SDK 的隐私政策必须在《隐私政策》里声明,否则应用市场审核会被打回。

还有个血泪教训:日志级别要能远程开关。线上出诡异 bug,最需要的是 verbose 日志,但发版时全量开又影响性能。Firebase Remote Config 配个 log_level 开关,救过我不止一次。

参考:Firebase 官方文档 Crashlytics;Android 官方文档《Log》

总结

可观测性是保障应用质量的关键。通过构建标准化的日志、崩溃与性能监控体系,结合自动化报警与仪表板,可快速发现问题、定位根因,支撑稳定迭代。Kotlin 提供的封装能力可让这些工具更易于使用与维护。


分享这篇文章:


相关文章

上一篇
Android Kotlin 性能分析与内存调优
下一篇
Android Kotlin 架构组件与多模块协同