From 63e7d0e92757f0aa9425480aeffb583f9d562599 Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Wed, 6 May 2020 00:17:46 +0200 Subject: [PATCH] Logger: Log all messages to a file For Bug reports we were calling 'adb logcat' and fetching the logs, but the amount of logs we got was quite arbitrary, also this wasn't possible in iOS. With this approach, we don't get the lower level logs of Android/iOS or from libgit2, but since we're slowly moving away from libgit2 anyway, it will have to do. --- lib/utils/logger.dart | 58 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/lib/utils/logger.dart b/lib/utils/logger.dart index 0311c0fc..e0081bbf 100644 --- a/lib/utils/logger.dart +++ b/lib/utils/logger.dart @@ -1,32 +1,88 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:fimber/fimber.dart'; import 'package:flutter/foundation.dart' as foundation; +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as p; class Log { - static void init() { + static String logFolderPath; + static RandomAccessFile logFile; + + static void init() async { if (foundation.kDebugMode) { Fimber.plantTree(DebugTree.elapsed(useColors: true)); } else { Fimber.plantTree(DebugTree.elapsed(useColors: false)); } + + var cacheDir = await getTemporaryDirectory(); + logFolderPath = p.join(cacheDir.path, "logs"); + try { + Directory(logFolderPath).createSync(); + } catch (e) { + // Ignore if it already exists + } + + setLogCapture(true); } static void v(String msg, {dynamic ex, StackTrace stacktrace}) { Fimber.v(msg, ex: ex, stacktrace: stacktrace); + _write('v', msg, ex, stacktrace); } static void d(String msg, {dynamic ex, StackTrace stacktrace}) { Fimber.d(msg, ex: ex, stacktrace: stacktrace); + _write('d', msg, ex, stacktrace); } static void i(String msg, {dynamic ex, StackTrace stacktrace}) { Fimber.i(msg, ex: ex, stacktrace: stacktrace); + _write('i', msg, ex, stacktrace); } static void e(String msg, {dynamic ex, StackTrace stacktrace}) { Fimber.e(msg, ex: ex, stacktrace: stacktrace); + _write('e', msg, ex, stacktrace); } static void w(String msg, {dynamic ex, StackTrace stacktrace}) { Fimber.w(msg, ex: ex, stacktrace: stacktrace); + _write('w', msg, ex, stacktrace); + } + + static void _write( + String level, + String msg, + dynamic ex, + StackTrace stackTrace, + ) { + if (logFile == null) return; + var map = { + 't': DateTime.now().millisecondsSinceEpoch, + 'l': level, + 'msg': msg.replaceAll('\n', ' '), + if (ex != null) 'ex': ex.toString().replaceAll('\n', ' '), + if (stackTrace != null) + 'stack': stackTrace.toString().replaceAll('\n', ' '), + }; + var str = json.encode(map); + logFile.writeStringSync(str + '\n'); + } + + static void setLogCapture(bool state) async { + if (state) { + var today = DateTime.now().toString().substring(0, 10); + var logFilePath = p.join(logFolderPath, '$today.jsonl'); + logFile = await File(logFilePath).open(mode: FileMode.append); + print("Writing logs to file $logFilePath"); + } else { + if (logFile != null) { + await logFile.close(); + } + logFile = null; + } } }