基础与工程篇(6/6):日志、埋点、错误收集的统一接入

8 阅读2分钟

日志、埋点、错误收集的统一接入

Flutter 实战系列第 6 篇。
目标:建立“可观测性”基础设施,让问题可发现、可定位、可复盘。

1. 问题背景:业务场景 + 现象

中大型业务最怕“线上出问题但看不见”:

  • 用户说卡、说崩,但没有上下文
  • 同一个问题在不同模块重复出现
  • 日志分散在 print、debugPrint、平台日志里
  • 埋点口径不一致,数据无法对齐业务结论
  • 崩溃上报缺关键字段,无法定位到具体链路

2. 原因分析:核心原理 + 排查过程

2.1 核心原理

可观测性至少包含三层:

  1. 日志(Log):还原过程
  2. 事件埋点(Event):量化行为
  3. 错误上报(Error/Crash):定位故障

如果这三层没有统一标准,就会出现“有数据但无结论”。

2.2 常见反模式

  1. 直接到处 print
  2. 事件名随意命名,字段口径混乱
  3. 错误上报不带用户/路由/环境信息
  4. 网络错误和业务错误没有统一编码
  5. 线上日志级别未分级,噪音太多

3. 解决方案:方案对比 + 最终选择

3.1 方案对比

  • 各模块自己打日志/埋点
    快,但无法治理

  • 统一 SDK 封装层(推荐)
    需要初期建设,但长期稳定

3.2 最终选择

建立统一可观测层(Observe):

  • Observe.log(...):结构化日志
  • Observe.event(...):统一事件埋点
  • Observe.error(...):异常与崩溃上报
  • 全部自动注入公共上下文:envuidroutetraceIdappVersion

4. 关键代码:最小必要代码片段

4.1 统一入口接口

class Observe {
  static late String env;
  static late String appVersion;

  static void init({required String envName, required String version}) {
    env = envName;
    appVersion = version;
    FlutterError.onError = (details) {
      error(
        type: 'flutter_error',
        message: details.exceptionAsString(),
        stack: details.stack,
      );
    };
  }

  static void log(String tag, String message, {Map<String, dynamic>? extra}) {
    final payload = {
      'type': 'log',
      'tag': tag,
      'message': message,
      'env': env,
      'appVersion': appVersion,
      ...?extra,
    };
    // 转发到控制台 / 文件 / 远端日志平台
    debugPrint(payload.toString());
  }

  static void event(String name, {Map<String, dynamic>? params}) {
    final payload = {
      'type': 'event',
      'name': name,
      'env': env,
      'appVersion': appVersion,
      ...?params,
    };
    // 转发埋点 SDK
    debugPrint(payload.toString());
  }

  static void error({
    required String type,
    required String message,
    StackTrace? stack,
    Map<String, dynamic>? extra,
  }) {
    final payload = {
      'type': type,
      'message': message,
      'stack': stack?.toString(),
      'env': env,
      'appVersion': appVersion,
      ...?extra,
    };
    // 转发崩溃平台(如 Sentry/Firebase Crashlytics/自建)
    debugPrint(payload.toString());
  }
}