-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Kek-Tech/dev
MIGRATE: Removed unpublished dep for publishing, added CallerLogger in its place from logger package
- Loading branch information
Showing
11 changed files
with
440 additions
and
77 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:flutter_dev_utils/src/caller_logger/caller_logger.dart'; | ||
import 'package:flutter_dev_utils/src/caller_logger/type_filter.dart'; | ||
import 'package:logger/logger.dart'; | ||
|
||
var logger = CallerLogger( | ||
ignoreCallers: { | ||
'syncTryCatchHandler', | ||
}, | ||
filter: TypeFilter( | ||
ignoreTypes: { | ||
IgnoredClass, | ||
}, | ||
ignoreLevel: Level.warning, | ||
), | ||
level: Level.verbose, | ||
); | ||
|
||
void main() { | ||
print( | ||
'Run with either `dart example/main_caller_logger.dart` or `dart --enable-asserts example/main_caller_logger.dart`.'); | ||
demo(); | ||
} | ||
|
||
void demo() { | ||
/// Settings are such that: | ||
/// | ||
/// 1. All logs in ExampleClass are printed (because level: Level.verbose) | ||
/// 2. Logs in IgnoredClass are not printed (because ignoreTypes: IgnoredClass), | ||
/// except for logs at level of warning and above (because ignoreLevel: Level.warning) | ||
ExampleClass.run(); | ||
print('========================================'); | ||
IgnoredClass.run(); | ||
print('========================================'); | ||
|
||
/// 3. Printed log for this will show ExampleClass.nestedRun() instead of | ||
/// syncTryCatchHandler (because ignoreCallers: {'syncTryCatchHandler'}) | ||
ExampleClass.nestedRun(); | ||
} | ||
|
||
class ExampleClass { | ||
static void run() { | ||
logger.log(Level.verbose, 'log: verbose'); | ||
|
||
logger.v('verbose'); | ||
logger.d('debug'); | ||
logger.i('info'); | ||
logger.w('warning'); | ||
logger.e('error'); | ||
logger.wtf('wtf'); | ||
} | ||
|
||
static void nestedRun() { | ||
// nested functions will print | ||
syncTryCatchHandler( | ||
tryFunction: () => jsonDecode('thisIsNotJson'), | ||
); | ||
} | ||
} | ||
|
||
class IgnoredClass { | ||
static void run() { | ||
logger.v('verbose'); | ||
logger.d('debug'); | ||
logger.i('info'); | ||
logger.w('warning'); | ||
logger.e('error'); | ||
logger.wtf('wtf'); | ||
} | ||
} | ||
|
||
/// Synchronous try and catch handler to reduce boilerplate | ||
/// | ||
/// Used as an example to show how nested functions can be ignored in [ignoreCallers] | ||
dynamic syncTryCatchHandler( | ||
{dynamic Function()? tryFunction, | ||
Map<Exception, dynamic Function()?>? catchKnownExceptions, | ||
dynamic Function()? catchUnknownExceptions}) { | ||
try { | ||
try { | ||
return tryFunction?.call(); | ||
} on Exception catch (e, s) { | ||
if (catchKnownExceptions == null) { | ||
rethrow; | ||
} else if (catchKnownExceptions.containsKey(e)) { | ||
logger.w('handling known exception', e, s); | ||
catchKnownExceptions[e]?.call(); | ||
} else { | ||
rethrow; | ||
} | ||
} | ||
} catch (e, s) { | ||
logger.e('catchUnknown:', e, s); | ||
catchUnknownExceptions?.call(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:flutter_dev_utils/flutter_dev_utils.dart'; | ||
import 'package:flutter_dev_utils/src/caller_logger/caller_logger.dart'; | ||
import 'package:logger/logger.dart'; | ||
|
||
void main() { | ||
print( | ||
'Run with either `dart example/main_try_catch_handler.dart` or `dart --enable-asserts example/main_try_catch_handler.dart`.'); | ||
Demo.run(); | ||
} | ||
|
||
class Demo { | ||
static void run() { | ||
syncTryCatchHandler(tryFunction: () { | ||
CallerLogger().i('It works!'); // this should print | ||
return true; | ||
}); | ||
|
||
asyncTryCatchHandler(tryFunction: () async { | ||
CallerLogger().i('It works!'); // this should print | ||
return true; | ||
}); | ||
syncTryCatchHandler( | ||
tryFunction: () => | ||
jsonDecode('notJson'), // this should throw an exception | ||
); | ||
asyncTryCatchHandler( | ||
tryFunction: () => | ||
jsonDecode('notJson'), // this should throw an exception | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
library flutter_dev_utils; | ||
|
||
export 'src/try_catch_handler/sync_try_catch_handler.dart'; | ||
export 'src/try_catch_handler/async_try_catch_handler.dart'; | ||
export 'package:flutter_dev_utils/src/try_catch_handler/sync_try_catch_handler.dart'; | ||
export 'package:flutter_dev_utils/src/try_catch_handler/async_try_catch_handler.dart'; | ||
export 'package:flutter_dev_utils/src/caller_logger/caller_logger.dart'; | ||
export 'package:flutter_dev_utils/src/caller_logger/type_filter.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import 'package:flutter_dev_utils/src/caller_logger/caller_printer.dart'; | ||
import 'package:logger/logger.dart'; | ||
|
||
/// Custom Logger which prints the caller of the Logger.log() method. | ||
/// | ||
/// E.g., if ExampleClass1.method() calls logger.d('some debug message'), | ||
/// then the console will show: ExampleClass1.method: some debug message | ||
/// | ||
/// [ignoreCallers] can be specified to show the most relevant caller | ||
class CallerLogger extends Logger { | ||
CallerLogger._({ | ||
LogFilter? filter, | ||
LogPrinter? printer, | ||
LogOutput? output, | ||
Level? level, | ||
required Set<String> ignoreCallers, | ||
}) : _ignoreCallers = ignoreCallers, | ||
super(filter: filter, printer: printer, output: output, level: level); | ||
|
||
factory CallerLogger({ | ||
LogFilter? filter, | ||
LogPrinter? printer, | ||
LogOutput? output, | ||
Level? level, | ||
Set<String>? ignoreCallers, | ||
}) { | ||
/// Skip callers in stack trace so that the more relevant caller is printed, | ||
/// e.g., methods from the loggers or utility functions | ||
final _defaultIgnoreCallers = { | ||
'CallerLogger.log', | ||
'Logger.', | ||
}; | ||
if (ignoreCallers == null) { | ||
ignoreCallers = _defaultIgnoreCallers; | ||
} else { | ||
ignoreCallers.addAll(_defaultIgnoreCallers); | ||
} | ||
return CallerLogger._( | ||
filter: filter, | ||
printer: printer ?? CallerPrinter(), | ||
output: output, | ||
level: level, | ||
ignoreCallers: ignoreCallers, | ||
); | ||
} | ||
|
||
Set<String> _ignoreCallers; | ||
|
||
@override | ||
void log(Level level, message, [error, StackTrace? stackTrace]) { | ||
// get caller | ||
final lines = StackTrace.current.toString().split('\n'); | ||
var caller = 'CallerNotFound'; | ||
for (var line in lines) { | ||
if (_ignoreCallers.any((element) => line.contains(element))) { | ||
continue; | ||
} else { | ||
// ! caller in StackTrace #x seems to be i=6 when split by spaces | ||
// ! this may bug out if formatting of StackTrace changes | ||
caller = line.split(' ')[6].trim(); | ||
break; // exit loop to save first caller which is not from the logger | ||
} | ||
} | ||
super.log(level, caller + ': ' + message, error, stackTrace); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:logger/logger.dart'; | ||
|
||
class CallerPrinter extends LogPrinter { | ||
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; | ||
|
||
/// The index which to begin the stack trace at | ||
/// | ||
/// This can be useful if, for instance, Logger is wrapped in another class and | ||
/// you wish to remove these wrapped calls from stack trace | ||
final int stackTraceBeginIndex; | ||
|
||
// No of methods to show in StackTrace when no error or exception is thrown | ||
final int methodCount; | ||
|
||
/// No of methods to show in StackTrace when error or exception is thrown | ||
final int errorMethodCount; | ||
|
||
CallerPrinter({ | ||
this.printTime = false, | ||
this.colors = false, | ||
// StackTrace args | ||
this.stackTraceBeginIndex = 0, | ||
this.methodCount = 0, | ||
this.errorMethodCount = 10, | ||
}); | ||
@override | ||
List<String> log(LogEvent event) { | ||
var messageStr = _stringifyMessage(event.message); | ||
var errorStr = event.error != null ? '\nERROR: ${event.error}' : ''; | ||
var timeStr = printTime ? 'TIME: ${DateTime.now().toIso8601String()}' : ''; | ||
|
||
var stackTraceStr; | ||
if (event.stackTrace == null) { | ||
if (methodCount > 0) { | ||
stackTraceStr = _formatStackTrace(StackTrace.current, methodCount); | ||
} | ||
} else if (errorMethodCount > 0) { | ||
stackTraceStr = _formatStackTrace(event.stackTrace, errorMethodCount); | ||
} | ||
stackTraceStr = stackTraceStr == null | ||
? '' | ||
: '\n' + stackTraceStr + '\n========================================'; | ||
|
||
return [ | ||
'${_labelFor(event.level)} $timeStr$messageStr$errorStr$stackTraceStr' | ||
]; | ||
} | ||
|
||
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(); | ||
} | ||
} | ||
|
||
//! Stack Trace formatting | ||
/// 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]+)'); | ||
|
||
String? _formatStackTrace(StackTrace? stackTrace, int methodCount) { | ||
var lines = stackTrace.toString().split('\n'); | ||
if (stackTraceBeginIndex > 0 && stackTraceBeginIndex < lines.length - 1) { | ||
lines = lines.sublist(stackTraceBeginIndex); | ||
} | ||
var formatted = <String>[]; | ||
var count = 0; | ||
for (var line in lines) { | ||
if (_discardDeviceStacktraceLine(line) || | ||
_discardWebStacktraceLine(line) || | ||
_discardBrowserStacktraceLine(line) || | ||
line.isEmpty) { | ||
continue; | ||
} | ||
formatted.add('#$count ${line.replaceFirst(RegExp(r'#\d+\s+'), '')}'); | ||
if (++count == methodCount) { | ||
break; | ||
} | ||
} | ||
|
||
if (formatted.isEmpty) { | ||
return null; | ||
} else { | ||
return formatted.join('\n'); | ||
} | ||
} | ||
|
||
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:'); | ||
} | ||
} |
Oops, something went wrong.