-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
97fcba7
commit 4db2610
Showing
9 changed files
with
728 additions
and
12 deletions.
There are no files selected for viewing
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
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
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,78 @@ | ||
enum Level { | ||
verbose, | ||
debug, | ||
info, | ||
warning, | ||
error, | ||
wtf, | ||
nothing, | ||
} | ||
|
||
class LogEvent { | ||
final Level level; | ||
final dynamic message; | ||
final dynamic error; | ||
final StackTrace? stackTrace; | ||
|
||
LogEvent(this.level, this.message, this.error, this.stackTrace); | ||
} | ||
|
||
class OutputEvent { | ||
final Level level; | ||
final List<String> lines; | ||
|
||
OutputEvent(this.level, this.lines); | ||
} | ||
|
||
abstract class LogFilter { | ||
bool shouldLog(LogEvent logEvent); | ||
} | ||
|
||
abstract class LogPrinter { | ||
List<String> log(LogEvent logEvent); | ||
} | ||
|
||
abstract class LogOutput { | ||
void output(OutputEvent outputEvent); | ||
} | ||
|
||
class Logger { | ||
static Level level = Level.verbose; | ||
bool _active = true; | ||
final LogFilter _filter; | ||
final LogPrinter _printer; | ||
final LogOutput _output; | ||
|
||
Logger(this._filter, this._printer, this._output); | ||
|
||
/// Log a message with [level]. | ||
void log( | ||
Level level, | ||
dynamic message, [ | ||
dynamic error, | ||
StackTrace? stackTrace, | ||
]) { | ||
if (!_active) { | ||
throw ArgumentError('Logger has already been closed.'); | ||
} else if (error != null && error is StackTrace) { | ||
throw ArgumentError('Error parameter cannot take a StackTrace!'); | ||
} else if (level == Level.nothing) { | ||
throw ArgumentError('Log events cannot have Level.nothing'); | ||
} | ||
var logEvent = LogEvent(level, message, error, stackTrace); | ||
|
||
if (_filter.shouldLog(logEvent)) { | ||
var output = _printer.log(logEvent); | ||
|
||
if (output.isNotEmpty) { | ||
var outputEvent = OutputEvent(level, output); | ||
try { | ||
_output.output(outputEvent); | ||
} catch (e, s) { | ||
print(e); | ||
print(s); | ||
} | ||
} | ||
} | ||
} | ||
} |
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,121 @@ | ||
/// Convert `log` function from `logger` package | ||
/// from Imperative to Functional code using `fpdart` | ||
/// | ||
/// Repository: https://github.com/leisim/logger | ||
import 'package:fpdart/fpdart.dart'; | ||
import 'logger.dart'; | ||
|
||
class Logger { | ||
static Level level = Level.verbose; | ||
bool _active = true; | ||
final LogFilter _filter; | ||
final LogPrinter _printer; | ||
final LogOutput _output; | ||
Logger(this._filter, this._printer, this._output); | ||
|
||
/// Imperative (not-functional) code | ||
/// | ||
/// From https://github.com/leisim/logger/blob/6832ee0f5c430321f6a74dce99338b242861161d/lib/src/logger.dart#L104 | ||
void log( | ||
Level level, | ||
dynamic message, [ | ||
dynamic error, | ||
StackTrace? stackTrace, | ||
]) { | ||
if (!_active) { | ||
throw ArgumentError('Logger has already been closed.'); | ||
} else if (error != null && error is StackTrace) { | ||
throw ArgumentError('Error parameter cannot take a StackTrace!'); | ||
} else if (level == Level.nothing) { | ||
throw ArgumentError('Log events cannot have Level.nothing'); | ||
} | ||
var logEvent = LogEvent(level, message, error, stackTrace); | ||
|
||
if (_filter.shouldLog(logEvent)) { | ||
var output = _printer.log(logEvent); | ||
|
||
if (output.isNotEmpty) { | ||
var outputEvent = OutputEvent(level, output); | ||
try { | ||
_output.output(outputEvent); | ||
} catch (e, s) { | ||
print(e); | ||
print(s); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Functional approach 💪 | ||
/// ---------------------------------------------------------------- | ||
/// Use [IOEither] to handle errors and avoid throwing expections 🔨 | ||
/// | ||
/// Use [Unit] instead of `void` to represent a function that returns nothing 🎭 | ||
IOEither<String, Unit> logFunctional({ | ||
required Level level, | ||
required dynamic message, | ||
required dynamic error, | ||
StackTrace? stackTrace, | ||
|
||
/// Add all external dependencies as input to make the function pure 🥼 | ||
required bool active, | ||
required LogFilter filter, | ||
required LogPrinter printer, | ||
required LogOutput output, | ||
}) { | ||
/// Handle errors using [Either] instead of throwing errors 💥 | ||
if (!active) { | ||
return IOEither.left('Logger has already been closed.'); | ||
} else if (error != null && error is StackTrace) { | ||
return IOEither.left('Error parameter cannot take a StackTrace!'); | ||
} else if (level == Level.nothing) { | ||
return IOEither.left('Log events cannot have Level.nothing'); | ||
} | ||
|
||
/// Declare all the variables as `const` or `final` 🧱 | ||
final logEvent = LogEvent(level, message, error, stackTrace); | ||
|
||
/// Make sure to handle all the cases using [Option] 🎉 | ||
/// | ||
/// Use the `identity` function to return the input parameter as it is | ||
final shouldLogOption = Option.fromPredicate( | ||
filter.shouldLog(logEvent), | ||
identity, | ||
); | ||
|
||
/// Using [Option], you must specify both `true` and `false` cases 🌎 | ||
return shouldLogOption.match( | ||
/// Use another [Option] to evaluate `printer.log` | ||
(_) => Option<List<String>>.fromPredicate( | ||
printer.log(logEvent), | ||
(v) => v.isNotEmpty, | ||
).match( | ||
(lines) { | ||
/// All variables are `final` 🧱 | ||
final outputEvent = OutputEvent(level, lines); | ||
return IOEither<String, Unit>.tryCatch( | ||
() { | ||
output.output(outputEvent); | ||
|
||
/// Return [Unit] 🎁 | ||
return unit; | ||
}, | ||
(e, s) { | ||
/// Return an error message 🔨 | ||
/// | ||
/// Do not `print`, it would make the function impure! 🤯 | ||
return 'An error occurred: $e'; | ||
}, | ||
); | ||
}, | ||
|
||
/// Simply return a [Unit] in all other cases 🎁 | ||
() => IOEither.of(unit), | ||
), | ||
|
||
/// Simply return a [Unit] in all other cases 🎁 | ||
() => IOEither.of(unit), | ||
); | ||
} | ||
} |
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
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
Oops, something went wrong.