mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-24 11:59:30 +00:00
feat: error reporting with logs (#45)
* feat: add ability to get logs file from ui * test: add unit test for log line parsing in logs_provider * refactor: update all logs to obfuscate sensitive information * feat: generate dynamic zip file name for logs export * feat: enhance logging in audiobook player and provider for better debugging * refactor: extract user display logic into UserBar widget for offline access of settings and logs * feat: add About section with app metadata and source code link in YouPage
This commit is contained in:
parent
7b0c2c4b88
commit
35a2d7cfce
44 changed files with 861 additions and 176 deletions
76
lib/features/logging/providers/logs_provider.dart
Normal file
76
lib/features/logging/providers/logs_provider.dart
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:vaani/features/logging/core/logger.dart';
|
||||
|
||||
part 'logs_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
class Logs extends _$Logs {
|
||||
@override
|
||||
Future<List<LogRecord>> build() async {
|
||||
final path = await getLoggingFilePath();
|
||||
final file = File(path);
|
||||
if (!file.existsSync()) {
|
||||
return [];
|
||||
}
|
||||
final lines = await file.readAsLines();
|
||||
return lines.map(parseLogLine).toList();
|
||||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
final path = await getLoggingFilePath();
|
||||
final file = File(path);
|
||||
await file.writeAsString('');
|
||||
state = AsyncData([]);
|
||||
}
|
||||
|
||||
Future<String> getZipFilePath() async {
|
||||
var encoder = ZipFileEncoder();
|
||||
encoder.create(await generateZipFilePath());
|
||||
encoder.addFile(File(await getLoggingFilePath()));
|
||||
encoder.close();
|
||||
return encoder.zipPath;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> generateZipFilePath() async {
|
||||
Directory appDocDirectory = await getTemporaryDirectory();
|
||||
return '${appDocDirectory.path}/${generateZipFileName()}';
|
||||
}
|
||||
|
||||
String generateZipFileName() {
|
||||
return 'vaani-${DateTime.now().toIso8601String()}.zip';
|
||||
}
|
||||
|
||||
Level parseLevel(String level) {
|
||||
return Level.LEVELS
|
||||
.firstWhere((l) => l.name == level, orElse: () => Level.ALL);
|
||||
}
|
||||
|
||||
LogRecord parseLogLine(String line) {
|
||||
// 2024-10-03 00:48:58.012400 INFO GoRouter - getting location for name: "logs"
|
||||
|
||||
final RegExp logLineRegExp = RegExp(
|
||||
r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}) (\w+) (\w+) - (.+)',
|
||||
);
|
||||
|
||||
final match = logLineRegExp.firstMatch(line);
|
||||
if (match == null) {
|
||||
// return as is
|
||||
return LogRecord(Level.ALL, line, 'Unknown');
|
||||
}
|
||||
|
||||
final timeString = match.group(1)!;
|
||||
final levelString = match.group(2)!;
|
||||
final loggerName = match.group(3)!;
|
||||
final message = match.group(4)!;
|
||||
|
||||
final time = DateTime.parse(timeString);
|
||||
final level = parseLevel(levelString);
|
||||
|
||||
return LogRecord(level, message, loggerName, time);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue