172 lines
4.1 KiB
Dart
172 lines
4.1 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'log_config.dart';
|
|
import 'log_entry.dart';
|
|
import 'log_file_handler.dart';
|
|
|
|
class LogService {
|
|
final LogConfig _config;
|
|
LogFileHandler? _fileHandler;
|
|
final _buffer = <String>[];
|
|
static const _maxBufferSize = 50;
|
|
|
|
LogService._({required LogConfig config}) : _config = config;
|
|
|
|
static Future<LogService> create({LogConfig? config}) async {
|
|
final isRelease = kReleaseMode;
|
|
|
|
final effectiveConfig =
|
|
config ?? (isRelease ? LogConfig.forRelease() : LogConfig.forDebug());
|
|
|
|
final service = LogService._(config: effectiveConfig);
|
|
|
|
if (effectiveConfig.output == LogOutput.file) {
|
|
service._fileHandler = LogFileHandler();
|
|
await service._fileHandler!.init(
|
|
effectiveConfig.logDir,
|
|
effectiveConfig.logFileName,
|
|
);
|
|
}
|
|
|
|
return service;
|
|
}
|
|
|
|
String? get logFilePath => _fileHandler?.filePath;
|
|
|
|
void _log(LogEntry entry) {
|
|
if (entry.level.index < _config.minLevel.index) return;
|
|
|
|
if (_config.output == LogOutput.console) {
|
|
debugPrint(entry.toConsoleString());
|
|
if (entry.stackTrace != null) {
|
|
debugPrint(entry.stackTrace!);
|
|
}
|
|
} else {
|
|
_buffer.add(entry.toFileString());
|
|
if (_buffer.length >= _maxBufferSize) {
|
|
_flushBuffer();
|
|
}
|
|
}
|
|
}
|
|
|
|
void _flushBuffer() {
|
|
for (final line in _buffer) {
|
|
_fileHandler?.write(line);
|
|
}
|
|
_buffer.clear();
|
|
_fileHandler?.flush();
|
|
}
|
|
|
|
(String?, int?) _extractLocation(StackTrace stackTrace) {
|
|
final frames = stackTrace.toString().split('\n');
|
|
for (final frame in frames) {
|
|
if (frame.contains('.dart')) {
|
|
final match = RegExp(
|
|
r'#\d+\s+(.+?)\s+\((.+?):(\d+)\)',
|
|
).firstMatch(frame);
|
|
if (match != null) {
|
|
return (match.group(1), int.tryParse(match.group(3) ?? ''));
|
|
}
|
|
}
|
|
}
|
|
return (null, null);
|
|
}
|
|
|
|
void debug({
|
|
required String message,
|
|
required String module,
|
|
Map<String, dynamic>? extra,
|
|
StackTrace? stackTrace,
|
|
}) {
|
|
final trace = stackTrace ?? StackTrace.current;
|
|
final (funcName, lineNo) = _extractLocation(trace);
|
|
_log(
|
|
LogEntry(
|
|
timestamp: DateTime.now(),
|
|
level: LogLevel.debug,
|
|
message: message,
|
|
module: module,
|
|
funcName: funcName,
|
|
lineNo: lineNo,
|
|
extra: extra,
|
|
stackTrace: trace.toString(),
|
|
),
|
|
);
|
|
}
|
|
|
|
void info({
|
|
required String message,
|
|
required String module,
|
|
Map<String, dynamic>? extra,
|
|
StackTrace? stackTrace,
|
|
}) {
|
|
final trace = stackTrace ?? StackTrace.current;
|
|
final (funcName, lineNo) = _extractLocation(trace);
|
|
_log(
|
|
LogEntry(
|
|
timestamp: DateTime.now(),
|
|
level: LogLevel.info,
|
|
message: message,
|
|
module: module,
|
|
funcName: funcName,
|
|
lineNo: lineNo,
|
|
extra: extra,
|
|
stackTrace: trace.toString(),
|
|
),
|
|
);
|
|
}
|
|
|
|
void warning({
|
|
required String message,
|
|
required String module,
|
|
Map<String, dynamic>? extra,
|
|
StackTrace? stackTrace,
|
|
}) {
|
|
final trace = stackTrace ?? StackTrace.current;
|
|
final (funcName, lineNo) = _extractLocation(trace);
|
|
_log(
|
|
LogEntry(
|
|
timestamp: DateTime.now(),
|
|
level: LogLevel.warning,
|
|
message: message,
|
|
module: module,
|
|
funcName: funcName,
|
|
lineNo: lineNo,
|
|
extra: extra,
|
|
stackTrace: trace.toString(),
|
|
),
|
|
);
|
|
}
|
|
|
|
void error({
|
|
required String message,
|
|
required Object error,
|
|
required StackTrace stackTrace,
|
|
required String module,
|
|
Map<String, dynamic>? extra,
|
|
}) {
|
|
final (funcName, lineNo) = _extractLocation(stackTrace);
|
|
_log(
|
|
LogEntry(
|
|
timestamp: DateTime.now(),
|
|
level: LogLevel.error,
|
|
message: message,
|
|
module: module,
|
|
funcName: funcName,
|
|
lineNo: lineNo,
|
|
errorType: error.runtimeType.toString(),
|
|
stackTrace: stackTrace.toString(),
|
|
extra: extra,
|
|
),
|
|
);
|
|
}
|
|
|
|
void flush() {
|
|
_flushBuffer();
|
|
_fileHandler?.flush();
|
|
}
|
|
|
|
Future<List<String>> readLogs() async {
|
|
return await _fileHandler?.readAllLines() ?? [];
|
|
}
|
|
}
|