Flutter - 列印好用的Debug日誌

LinXunFeng發表於2020-06-25

一、思考

iOS 開發時這個功能很常用, 在 OCSwift 中都可以很輕鬆實現,因為系統本來就提供了用於日誌輸出的預處理巨集,只要我們拿來拼接就可以了,但是在 Dart 中並不提供這些,那有什麼辦法實現它呢?

我們回想在開發過程中,是不是發現只要一不小心拋異常,就可以看到類似如下的列印內容,而且還能清楚的知道異常是在哪個檔案和哪一行的程式碼造成的。

Flutter - 列印好用的Debug日誌

所以如果我們可以在呼叫函式時拿到當前呼叫堆疊,就可以取到一系列想要的資料。

二、實踐

dart:core 中提供了 堆疊跟蹤(StackTrace),可以通過 StackTrace.current 取到當前的堆疊資訊,列印如下圖所示,會發現這不好拿到我們想要的資訊。

Flutter - 列印好用的Debug日誌

這裡我用到了官方開發的一個包 stack_trace,它可以將堆疊資訊變得更多人性化,並方便我們檢視堆疊資訊和獲取想要的資料。

ps: stack_traceFlutter 環境下直接導包即可使用,而在純 Dart 下需要將其新增為依賴於pubspec.yaml中。

dependencies:
  stack_trace: ^1.9.3
複製程式碼

那下面我們來試試 stack_trace 的威力吧

import 'package:stack_trace/stack_trace.dart';

// 將 StackTrace 物件轉換成 Chain 物件
// 當然,這裡也可以直接用 Chain.current();
final chain = Chain.forTrace(StackTrace.current);
// 拿出其中一條資訊
final frames = chain.toTrace().frames;
final frame = frames[1];
// 列印
print("所在檔案:${frame.uri} 所在行 ${frame.line} 所在列 ${frame.column}");

// 列印結果
// flutter: 所在檔案:package:flutterlog/main.dart 所在行 55 所在列 23
複製程式碼

三、呈上程式碼

下面我做了一點封裝,直接拿走即可使用,列印效果如下所示:

完整的程式碼和示例請到GitHub上【檢視】

列印效果

程式碼:

// log.dart

enum FLogMode {
  debug,    // ? DEBUG
  warning,  // ? WARNING
  info,     // ? INFO
  error,    // ❤️ ERROR
}

void FLog(dynamic msg, { FLogMode mode = FLogMode.debug }) {
  if (kReleaseMode) { // release模式不列印
    return;
  }
  var chain = Chain.current(); // Chain.forTrace(StackTrace.current);
  // 將 core 和 flutter 包的堆疊合起來(即相關資料只剩其中一條)
  chain = chain.foldFrames((frame) => frame.isCore || frame.package == "flutter");
  // 取出所有資訊幀
  final frames = chain.toTrace().frames;
  // 找到當前函式的資訊幀
  final idx = frames.indexWhere((element) => element.member == "FLog");
  if (idx == -1 || idx+1 >= frames.length) {
    return;
  }
  // 呼叫當前函式的函式資訊幀
  final frame = frames[idx+1];

  var modeStr = "";
  switch(mode) {
    case FLogMode.debug:
      modeStr = "? DEBUG";
      break;
    case FLogMode.warning:
      modeStr = "? WARNING";
      break;
    case FLogMode.info:
      modeStr = "? INFO";
      break;
    case FLogMode.error:
      modeStr = "❤️ ERROR";
      break;
  }

  print("$modeStr ${frame.uri.toString().split("/").last}(${frame.line}) - $msg ");
}
複製程式碼

Flutter - 列印好用的Debug日誌

相關文章