Skip to content

Commit

Permalink
Added per-instance addLogListener, closes #83
Browse files Browse the repository at this point in the history
  • Loading branch information
Bungeefan committed Oct 23, 2024
1 parent e5f1b78 commit 38358c5
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 13 deletions.
39 changes: 37 additions & 2 deletions lib/src/logger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class Logger {

static final Set<OutputCallback> _globalOutputCallbacks = {};

final Set<LogCallback> _logCallbacks = {};

final Set<OutputCallback> _outputCallbacks = {};

late final Future<void> _initialization;

/// All logs with levels below this level will be omitted.
Expand Down Expand Up @@ -188,7 +192,9 @@ class Logger {
error: error,
stackTrace: stackTrace,
);
for (var callback in _globalLogCallbacks) {

var collectedLogCallbacks = [..._logCallbacks, ..._globalLogCallbacks];
for (var callback in collectedLogCallbacks) {
callback(logEvent);
}

Expand All @@ -203,9 +209,14 @@ class Logger {
// Issues with log output should NOT influence
// the main software behavior.
try {
for (var callback in _globalOutputCallbacks) {
var collectedOutputCallbacks = [
..._outputCallbacks,
..._globalOutputCallbacks,
];
for (var callback in collectedOutputCallbacks) {
callback(outputEvent);
}

_output.output(outputEvent);
} catch (e, s) {
print(e);
Expand All @@ -227,6 +238,30 @@ class Logger {
await _output.destroy();
}

/// Register a [LogCallback] which is called for each new [LogEvent].
void addLogListener(LogCallback callback) {
_logCallbacks.add(callback);
}

/// Removes a [LogCallback] which was previously registered.
///
/// Returns whether the callback was successfully removed.
bool removeLogListener(LogCallback callback) {
return _logCallbacks.remove(callback);
}

/// Register an [OutputCallback] which is called for each new [OutputEvent].
void addOutputListener(OutputCallback callback) {
_outputCallbacks.add(callback);
}

/// Removes a [OutputCallback] which was previously registered.
///
/// Returns whether the callback was successfully removed.
bool removeOutputListener(OutputCallback callback) {
return _outputCallbacks.remove(callback);
}

/// Register a global [LogCallback] which is called for each new [LogEvent] on each logger.
static void addGlobalLogListener(LogCallback callback) {
_globalLogCallbacks.add(callback);
Expand Down
182 changes: 182 additions & 0 deletions test/listener_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import 'package:logger/logger.dart';
import 'package:test/test.dart';

import 'logger_test.dart';

class NoOutput extends LogOutput {
@override
void output(OutputEvent event) {
// No-op.
}
}

void main() {
group("Local", () {
LogEvent? loggedLogEvent;
logCallback(LogEvent event) {
loggedLogEvent = event;
}

OutputEvent? loggedOutputEvent;
outputCallback(OutputEvent event) {
loggedOutputEvent = event;
}

test('LogListener', () {
var stackTrace = StackTrace.current;

var logger = Logger(filter: NeverFilter(), output: NoOutput());
logger.addLogListener(logCallback);
logger.i('Test', error: 'Error', stackTrace: stackTrace);

expect(loggedLogEvent?.level, Level.info);
expect(loggedLogEvent?.message, 'Test');
expect(loggedLogEvent?.error, 'Error');
expect(loggedLogEvent?.stackTrace, stackTrace);

logger.removeLogListener(logCallback);
logger.i('Test2');

// event stays the same
expect(loggedLogEvent?.level, Level.info);
expect(loggedLogEvent?.message, 'Test');
expect(loggedLogEvent?.error, 'Error');
expect(loggedLogEvent?.stackTrace, stackTrace);
});

test('OutputListener', () {
var stackTrace = StackTrace.current;

var logger = Logger(filter: AlwaysFilter(), output: NoOutput());
logger.addOutputListener(outputCallback);
logger.i('Test', error: 'Error', stackTrace: stackTrace);

expect(loggedOutputEvent?.origin.level, Level.info);
expect(loggedOutputEvent?.origin.message, 'Test');
expect(loggedOutputEvent?.origin.error, 'Error');
expect(loggedOutputEvent?.origin.stackTrace, stackTrace);

logger.removeOutputListener(outputCallback);
logger.i('Test2');

// event stays the same
expect(loggedOutputEvent?.origin.level, Level.info);
expect(loggedOutputEvent?.origin.message, 'Test');
expect(loggedOutputEvent?.origin.error, 'Error');
expect(loggedOutputEvent?.origin.stackTrace, stackTrace);
});

test('OutputListener Filter', () {
var stackTrace = StackTrace.current;
OutputEvent? loggedEvent;
callback(OutputEvent event) {
loggedEvent = event;
}

var logger = Logger(filter: NeverFilter(), output: NoOutput());
logger.addOutputListener(callback);
logger.i('Test', error: 'Error', stackTrace: stackTrace);

expect(loggedEvent, isNull);

logger.close();
logger = Logger(filter: AlwaysFilter(), output: NoOutput());
logger.addOutputListener(callback);

logger.i('Test', error: 'Error', stackTrace: stackTrace);

expect(loggedEvent?.origin.level, Level.info);
expect(loggedEvent?.origin.message, 'Test');
expect(loggedEvent?.origin.error, 'Error');
expect(loggedEvent?.origin.stackTrace, stackTrace);

logger.removeOutputListener(callback);
logger.i('Test2');

// event stays the same
expect(loggedEvent?.origin.level, Level.info);
expect(loggedEvent?.origin.message, 'Test');
expect(loggedEvent?.origin.error, 'Error');
expect(loggedEvent?.origin.stackTrace, stackTrace);
});
});

group("Global", () {
LogEvent? localEvent;
localCallback(LogEvent event) {
localEvent = event;
}

LogEvent? globalEvent;
globalCallback(LogEvent event) {
globalEvent = event;
}

OutputEvent? localOutputEvent;
localOutputCallback(OutputEvent event) {
localOutputEvent = event;
}

OutputEvent? globalOutputEvent;
globalOutputCallback(OutputEvent event) {
globalOutputEvent = event;
}

setUp(() {
Logger.addGlobalLogListener(globalCallback);
Logger.addGlobalOutputListener(globalOutputCallback);
});

tearDown(() {
Logger.removeGlobalLogListener(globalCallback);
localEvent = null;
globalEvent = null;

Logger.removeGlobalOutputListener(globalOutputCallback);
localOutputEvent = null;
globalOutputEvent = null;
});

test(' LogListener', () {
var logger = Logger(filter: NeverFilter(), output: NoOutput());
var secondLogger = Logger(filter: NeverFilter(), output: NoOutput());

secondLogger.addLogListener(localCallback);

logger.i('Test');
expect(globalEvent, isNotNull);
expect(localEvent, isNull);

secondLogger.i('Test2');
expect(globalEvent?.message, 'Test2');
expect(localEvent?.message, 'Test2');

Logger.removeGlobalLogListener(globalCallback);
logger.i('Test3');

// event stays the same
expect(globalEvent?.message, 'Test2');
});

test(' OutputListener', () {
var logger = Logger(filter: AlwaysFilter(), output: NoOutput());
var secondLogger = Logger(filter: AlwaysFilter(), output: NoOutput());

secondLogger.addOutputListener(localOutputCallback);

logger.i('Test');
expect(globalOutputEvent, isNotNull);
expect(localOutputEvent, isNull);

secondLogger.i('Test2');
expect(globalOutputEvent?.origin.message, 'Test2');
expect(localOutputEvent?.origin.message, 'Test2');

Logger.removeGlobalOutputListener(globalOutputCallback);
logger.i('Test3');

// event stays the same
expect(globalOutputEvent?.origin.message, 'Test2');
});
});
}
22 changes: 11 additions & 11 deletions test/logger_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ typedef PrinterCallback = List<String> Function(
StackTrace? stackTrace,
);

class _AlwaysFilter extends LogFilter {
class AlwaysFilter extends LogFilter {
@override
bool shouldLog(LogEvent event) => true;
}

class _NeverFilter extends LogFilter {
class NeverFilter extends LogFilter {
@override
bool shouldLog(LogEvent event) => false;
}
Expand Down Expand Up @@ -107,12 +107,12 @@ void main() {
});

test('Logger.log', () {
var logger = Logger(filter: _NeverFilter(), printer: callbackPrinter);
var logger = Logger(filter: NeverFilter(), printer: callbackPrinter);
logger.log(Level.debug, 'Some message');

expect(printedMessage, null);

logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);

var levels = [
Level.trace,
Expand Down Expand Up @@ -170,7 +170,7 @@ void main() {
});

test('Logger.t', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.t('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.trace);
Expand All @@ -180,7 +180,7 @@ void main() {
});

test('Logger.d', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.d('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.debug);
Expand All @@ -190,7 +190,7 @@ void main() {
});

test('Logger.i', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.i('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.info);
Expand All @@ -200,7 +200,7 @@ void main() {
});

test('Logger.w', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.w('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.warning);
Expand All @@ -210,7 +210,7 @@ void main() {
});

test('Logger.e', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.e('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.error);
Expand All @@ -220,7 +220,7 @@ void main() {
});

test('Logger.f', () {
var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
var stackTrace = StackTrace.current;
logger.f('Test', error: 'Error', stackTrace: stackTrace);
expect(printedLevel, Level.fatal);
Expand All @@ -232,7 +232,7 @@ void main() {
test('Deal with function messages', () {
final heavyComputation = 'heavily computed very pretty Message';

var logger = Logger(filter: _AlwaysFilter(), printer: callbackPrinter);
var logger = Logger(filter: AlwaysFilter(), printer: callbackPrinter);
logger.f(() => heavyComputation);
expect(printedMessage, heavyComputation);
});
Expand Down

0 comments on commit 38358c5

Please sign in to comment.