日志与崩溃上报不是“有就行”,而是稳定性工程的基础设施。本文用完整代码范式讲清:日志分级、统一入口、崩溃捕获与上报。
1. 统一日志入口
先定义一个全局 Logger,避免散落的 print:
enum LogLevel { debug, info, warn, error }
class Log {
static LogLevel level = LogLevel.debug;
static void d(String tag, String msg) => _log(LogLevel.debug, tag, msg);
static void i(String tag, String msg) => _log(LogLevel.info, tag, msg);
static void w(String tag, String msg) => _log(LogLevel.warn, tag, msg);
static void e(String tag, String msg) => _log(LogLevel.error, tag, msg);
static void _log(LogLevel lv, String tag, String msg) {
if (lv.index < level.index) return;
final now = DateTime.now().toIso8601String();
debugPrint('[$now][$lv][$tag] $msg');
}
}
2. 崩溃捕获入口
Flutter 侧至少需要捕获两类异常:
- Flutter 线程异常
- 非 Flutter(Zone)异常
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (details) {
Log.e('crash', details.exceptionAsString());
CrashReporter.report(details.exception, details.stack);
};
runZonedGuarded(() {
runApp(const MyApp());
}, (error, stack) {
Log.e('zone', error.toString());
CrashReporter.report(error, stack);
});
}
3. 崩溃上报接口
class CrashReporter {
static Future<void> report(Object error, StackTrace? stack) async {
// TODO: upload to your backend
Log.e('report', error.toString());
}
}
你可以在这里对接 Sentry、Firebase Crashlytics 或自建平台。
4. 日志持久化(可选)
线上问题排查时,持久化日志很有用:
class FileLogger {
final File file;
FileLogger(this.file);
Future<void> append(String line) async {
await file.writeAsString(line + '\n', mode: FileMode.append);
}
}
配合 Log._log 可以写入本地文件。
5. 埋点:让行为可观测
class EventTracker {
static void track(String event, Map<String, dynamic> data) {
Log.i('event', '$event $data');
}
}
埋点不要侵入业务代码太深,统一入口即可。
6. 实践清单
- 统一日志入口
- FlutterError + Zone 捕获
- 崩溃上报
- 可选日志持久化
- 统一埋点入口
总结
日志与崩溃上报是工程稳定性的底线。只要统一入口、集中捕获并可上报,就能把线上问题变成可追踪的数据。