From 87d4e911d17481d200be3e3ef079d42001604666 Mon Sep 17 00:00:00 2001 From: danielle Date: Thu, 8 Sep 2022 16:55:27 +0300 Subject: [PATCH] feat(printer):create one line printer with stack trace --- lib/src/printers/one_line_printer.dart | 151 +++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 lib/src/printers/one_line_printer.dart diff --git a/lib/src/printers/one_line_printer.dart b/lib/src/printers/one_line_printer.dart new file mode 100644 index 0000000..0174a24 --- /dev/null +++ b/lib/src/printers/one_line_printer.dart @@ -0,0 +1,151 @@ +import 'dart:convert'; +import 'package:logger/src/ansi_color.dart'; +import 'package:logger/src/log_printer.dart'; +import 'package:logger/src/logger.dart'; + +/// An implementation of [LogPrinter] that prints everything on one line, +/// including the function that called the logger function. This makes it +/// possible to use VSCode's log filter more efficiently. +/// For example: +/// +/// ``` +/// [D] _HomePageState.someFunction (package:my_app/pages/home/HomePage.dart:141:12) some_message +/// ``` +/// +/// So by filtering by 'HomePage' one can see all the logs by that page. +/// +/// It is also possible to print the time. Anonymous functions have been +/// replaced by to save space. +class OneLinePrinter extends LogPrinter { + @override + + /// Matches a stacktrace line as generated on Android/iOS devices. + /// For example: + /// #1 Logger.log (package:logger/src/logger.dart:115:29) + static final _deviceStackTraceRegex = + RegExp(r'#[0-9]+[\s]+(.+) \(([^\s]+)\)'); + + /// Matches a stacktrace line as generated by Flutter web. + /// For example: + /// packages/logger/src/printers/pretty_printer.dart 91:37 + static final _webStackTraceRegex = + RegExp(r'^((packages|dart-sdk)\/[^\s]+\/)'); + + /// Matches a stacktrace line as generated by browser Dart. + /// For example: + /// dart:sdk_internal + /// package:logger/src/logger.dart + static final _browserStackTraceRegex = + RegExp(r'^(?:package:)?(dart:[^\s]+|[^\s]+)'); + + static final levelPrefixes = { + Level.verbose: '[V]', + Level.debug: '[D]', + Level.info: '[I]', + Level.warning: '[W]', + Level.error: '[E]', + Level.wtf: '[WTF]', + }; + + static final levelColors = { + Level.verbose: AnsiColor.fg(AnsiColor.grey(0.5)), + Level.debug: AnsiColor.none(), + Level.info: AnsiColor.fg(12), + Level.warning: AnsiColor.fg(208), + Level.error: AnsiColor.fg(196), + Level.wtf: AnsiColor.fg(199), + }; + + final bool printTime; + final bool colors; + + OneLinePrinter({this.printTime = false, this.colors = true}); + + bool _discardDeviceStacktraceLine(String line) { + var match = _deviceStackTraceRegex.matchAsPrefix(line); + if (match == null) { + return false; + } + return match.group(2)!.startsWith('package:logger'); + } + + bool _discardWebStacktraceLine(String line) { + var match = _webStackTraceRegex.matchAsPrefix(line); + if (match == null) { + return false; + } + return match.group(1)!.startsWith('packages/logger') || + match.group(1)!.startsWith('dart-sdk/lib'); + } + + bool _discardBrowserStacktraceLine(String line) { + var match = _browserStackTraceRegex.matchAsPrefix(line); + if (match == null) { + return false; + } + return match.group(1)!.startsWith('package:logger') || + match.group(1)!.startsWith('dart:'); + } + + String? formatStackTrace(StackTrace? stackTrace, int methodCount) { + var lines = stackTrace.toString().split('\n'); + + var formatted = []; + var count = 0; + for (var line in lines) { + if (_discardDeviceStacktraceLine(line) || + _discardWebStacktraceLine(line) || + _discardBrowserStacktraceLine(line) || + line.isEmpty) { + continue; + } + + line = line.replaceFirst(RegExp(r'#\d+\s+'), ''); + //shorten anonymous closures to + formatted.add('${line.replaceFirst(".", '')}'); + if (++count == methodCount) { + break; + } + } + + if (formatted.isEmpty) { + return null; + } else { + return formatted.join('\n'); + } + } + + @override + List log(LogEvent event) { + String? stackTraceStr; + //methodCount is 1 to save space. + if (event.stackTrace == null) { + stackTraceStr = formatStackTrace(StackTrace.current, 1); + } else { + stackTraceStr = formatStackTrace(event.stackTrace, 1); + } + var messageStr = _stringifyMessage(event.message); + var errorStr = event.error != null ? ' ERROR: ${event.error}' : ''; + var timeStr = printTime ? 'TIME: ${DateTime.now().toIso8601String()}' : ''; + return [ + '${_labelFor(event.level)} $stackTraceStr $timeStr $messageStr$errorStr' + ]; + } + + String _labelFor(Level level) { + var prefix = levelPrefixes[level]!; + var color = levelColors[level]!; + + return colors ? color(prefix) : prefix; + } + + String _stringifyMessage(dynamic message) { + final finalMessage = message is Function ? message() : message; + if (finalMessage is Map || finalMessage is Iterable) { + var encoder = JsonEncoder.withIndent(null); + return encoder.convert(finalMessage); + } else { + return finalMessage.toString(); + } + } +}