forked from lichess-org/mobile
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp_log_storage.dart
More file actions
92 lines (80 loc) · 3.02 KB
/
app_log_storage.dart
File metadata and controls
92 lines (80 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import 'package:collection/collection.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:lichess_mobile/src/db/database.dart';
import 'package:logging/logging.dart';
import 'package:sqflite/sqflite.dart';
part 'app_log_storage.g.dart';
part 'app_log_storage.freezed.dart';
/// Provides an instance of [AppLogStorage] using Riverpod.
final appLogStorageProvider = FutureProvider<AppLogStorage>((Ref ref) async {
final db = await ref.watch(databaseProvider.future);
return AppLogStorage(db);
}, name: 'AppLogStorageProvider');
const kAppLogStorageTable = 'app_log';
/// Manages the storage of app logs in a SQLite database.
class AppLogStorage {
const AppLogStorage(this._db);
final Database _db;
/// Retrieves a paginated list of [AppLogEntry] entries from the database.
///
/// If [minLevelValue] is provided, only entries with a level value greater than
/// or equal to [minLevelValue] are returned.
Future<AppLogPage> page({int? cursor, int? minLevelValue, int limit = 100}) async {
final whereClause = [
if (cursor != null) 'id <= $cursor',
if (minLevelValue != null) 'levelValue >= $minLevelValue',
];
final res = await _db.query(
kAppLogStorageTable,
limit: limit + 1,
orderBy: 'id DESC',
where: whereClause.isNotEmpty ? whereClause.join(' AND ') : null,
);
return AppLogPage(
items: res.take(limit).map(AppLogEntry.fromJson).toIList(),
next: res.elementAtOrNull(limit)?['id'] as int?,
);
}
/// Saves an [AppLogEntry] to the database.
Future<void> save(AppLogEntry entry) async {
await _db.insert(kAppLogStorageTable, {
...entry.toJson(),
'lastModified': DateTime.now().toIso8601String(),
}, conflictAlgorithm: ConflictAlgorithm.replace);
}
/// Deletes all app log entries from the database.
Future<void> deleteAll() async {
await _db.delete(kAppLogStorageTable);
}
}
/// Represents a persisted app log entry.
@Freezed(fromJson: true, toJson: true)
sealed class AppLogEntry with _$AppLogEntry {
const AppLogEntry._();
const factory AppLogEntry({
required DateTime logTime,
required String loggerName,
required int levelValue,
required String levelName,
required String message,
String? error,
String? stackTrace,
}) = _AppLogEntry;
factory AppLogEntry.fromLogRecord(LogRecord record) => AppLogEntry(
logTime: record.time,
loggerName: record.loggerName,
levelValue: record.level.value,
levelName: record.level.name,
message: record.message,
error: record.error?.toString(),
stackTrace: record.stackTrace?.toString(),
);
factory AppLogEntry.fromJson(Map<String, dynamic> json) => _$AppLogEntryFromJson(json);
}
/// A paginated collection of app log entries.
@freezed
sealed class AppLogPage with _$AppLogPage {
const factory AppLogPage({required IList<AppLogEntry> items, required int? next}) = _AppLogPage;
}