Last active
September 7, 2021 20:54
-
-
Save lukepighetti/5283229a351ab394376e84cff8277bdb to your computer and use it in GitHub Desktop.
Logging service using extensions for channels with multiple outputs
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
import 'package:logger/logger.dart'; | |
void main() async { | |
/// Setup logging service | |
final remoteUrl = Uri.parse('http://localhost:8080'); | |
final logger = LoggingService( | |
loggers: { | |
ConsoleLogger(), | |
RemoteLogger(baseUrl: remoteUrl), | |
}, | |
); | |
/// Do a normal log event | |
logger.log('main', 'log normally'); | |
/// Time a future and log it | |
await logger.logFuture( | |
'main', | |
'log future', | |
Future.delayed(Duration(seconds: 1)), | |
); | |
} |
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
import 'dart:convert'; | |
import 'package:http/http.dart' as http; | |
/// The base class for a logging channel or service | |
abstract class Logger { | |
/// Log a message | |
void log(String channel, String message); | |
} | |
/// The logging service used by the app | |
class LoggingService implements Logger { | |
LoggingService({required this.loggers}); | |
/// All the loggers to dispatch log events to | |
final Set<Logger> loggers; | |
@override | |
void log(String channel, String message) { | |
/// Dispatch this log event to all [loggers] | |
for (var logger in loggers) { | |
logger.log(channel, message); | |
} | |
} | |
/// Log a future and return the result | |
Future<T> logFuture<T>( | |
String channel, String message, Future<T> future) async { | |
final s = Stopwatch(); | |
s.start(); | |
final result = await future; | |
s.stop(); | |
log(channel, '${s.elapsed}: $message'); | |
return result; | |
} | |
} | |
/// A logging channel that outputs to the local development console | |
class ConsoleLogger implements Logger { | |
@override | |
void log(String channel, String message) { | |
print('[$channel] (${DateTime.now()}) $message'); | |
} | |
} | |
/// A logging channel that sends messages to a remote logging endpoint | |
class RemoteLogger implements Logger { | |
RemoteLogger({required this.baseUrl}); | |
final Uri baseUrl; | |
@override | |
void log(String channel, String message) async { | |
final timestamp = DateTime.now(); | |
try { | |
await http.post( | |
baseUrl.resolve('/log'), | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: json.encode({ | |
'channel': '$channel', | |
'timestamp': '$timestamp', | |
'message': '$message', | |
}), | |
); | |
} catch (e) { | |
print('[RemoteLogger] error: $e'); | |
} | |
} | |
} |
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
name: logger | |
description: A scalable logging system. | |
# version: 1.0.0 | |
# homepage: https://www.example.com | |
environment: | |
sdk: ">=2.12.0 <3.0.0" | |
dependencies: | |
http: ^0.13.1 | |
dev_dependencies: | |
pedantic: ^1.9.0 |
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
import 'dart:convert'; | |
import 'dart:io'; | |
import 'package:logger/logger.dart'; | |
void main(List<String> arguments) async { | |
final host = InternetAddress.loopbackIPv4; | |
final port = 8080; | |
final logger = LoggingService( | |
loggers: { | |
ConsoleLogger(), | |
}, | |
); | |
final server = await HttpServer.bind(host, port); | |
logger.log('setup', 'bound to $host:$port'); | |
server.listen((req) async { | |
/// `/log` | |
if (req.uri.path == '/log') { | |
try { | |
/// Parse the body | |
final body = await utf8.decoder.bind(req).join(); | |
var data = jsonDecode(body) as Map; | |
/// Extract the data | |
final channel = data['channel']; | |
final message = data['message']; | |
/// Log the event | |
logger.log(channel, '$message'); | |
req.response.statusCode = HttpStatus.ok; | |
} catch (e) { | |
logger.log('error', '$e'); | |
req.response.statusCode = HttpStatus.badRequest; | |
} finally { | |
await req.response.close(); | |
} | |
} | |
/// Unknown path | |
else { | |
logger.log('error', 'invalid path ${req.uri.path}'); | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment