141 lines
3.1 KiB
Dart
141 lines
3.1 KiB
Dart
import 'dart:convert';
|
|
|
|
class RuntimeDiagnostics {
|
|
RuntimeDiagnostics({this.maxEntries = 100});
|
|
|
|
final int maxEntries;
|
|
final List<RuntimeDiagnosticEntry> _entries = [];
|
|
|
|
List<RuntimeDiagnosticEntry> get entries => List.unmodifiable(_entries);
|
|
|
|
Map<String, Object?> toDebugJson() {
|
|
return {
|
|
'maxEntries': maxEntries,
|
|
'count': _entries.length,
|
|
'entries': _entries.map((entry) => entry.toDebugJson()).toList(),
|
|
};
|
|
}
|
|
|
|
String dumpText() {
|
|
if (_entries.isEmpty) {
|
|
return 'RuntimeDiagnostics: no entries';
|
|
}
|
|
|
|
final buffer = StringBuffer(
|
|
'RuntimeDiagnostics (${_entries.length}/$maxEntries)',
|
|
);
|
|
for (final entry in _entries) {
|
|
buffer
|
|
..writeln()
|
|
..write(entry.dumpText());
|
|
}
|
|
return buffer.toString();
|
|
}
|
|
|
|
void record({
|
|
required RuntimeDiagnosticType type,
|
|
required String message,
|
|
Object? error,
|
|
Map<String, Object?> context = const {},
|
|
}) {
|
|
if (_entries.length >= maxEntries) {
|
|
_entries.removeAt(0);
|
|
}
|
|
_entries.add(
|
|
RuntimeDiagnosticEntry(
|
|
type: type,
|
|
message: message,
|
|
error: error,
|
|
context: context,
|
|
timestamp: DateTime.now(),
|
|
),
|
|
);
|
|
}
|
|
|
|
void clear() {
|
|
_entries.clear();
|
|
}
|
|
}
|
|
|
|
class RuntimeDiagnosticEntry {
|
|
const RuntimeDiagnosticEntry({
|
|
required this.type,
|
|
required this.message,
|
|
required this.timestamp,
|
|
this.error,
|
|
this.context = const {},
|
|
});
|
|
|
|
final RuntimeDiagnosticType type;
|
|
final String message;
|
|
final DateTime timestamp;
|
|
final Object? error;
|
|
final Map<String, Object?> context;
|
|
|
|
Map<String, Object?> toDebugJson() {
|
|
return {
|
|
'timestamp': timestamp.toIso8601String(),
|
|
'type': type.name,
|
|
'message': message,
|
|
if (error != null) 'error': error.toString(),
|
|
if (context.isNotEmpty) 'context': _toDebugValue(context),
|
|
};
|
|
}
|
|
|
|
String dumpText() {
|
|
final buffer = StringBuffer(
|
|
'[${timestamp.toIso8601String()}] ${type.name}: $message',
|
|
);
|
|
if (error != null) {
|
|
buffer
|
|
..writeln()
|
|
..write(' error: $error');
|
|
}
|
|
if (context.isNotEmpty) {
|
|
buffer
|
|
..writeln()
|
|
..write(' context: ${_formatDebugValue(context)}');
|
|
}
|
|
return buffer.toString();
|
|
}
|
|
}
|
|
|
|
Object? _toDebugValue(Object? value) {
|
|
if (value == null || value is String || value is num || value is bool) {
|
|
return value;
|
|
}
|
|
if (value is DateTime) {
|
|
return value.toIso8601String();
|
|
}
|
|
if (value is Map) {
|
|
final entries = value.entries.toList()
|
|
..sort((a, b) => a.key.toString().compareTo(b.key.toString()));
|
|
return {
|
|
for (final entry in entries)
|
|
entry.key.toString(): _toDebugValue(entry.value),
|
|
};
|
|
}
|
|
if (value is Iterable) {
|
|
return value.map(_toDebugValue).toList();
|
|
}
|
|
return value.toString();
|
|
}
|
|
|
|
String _formatDebugValue(Object? value) {
|
|
try {
|
|
return jsonEncode(_toDebugValue(value));
|
|
} catch (_) {
|
|
return value.toString();
|
|
}
|
|
}
|
|
|
|
enum RuntimeDiagnosticType {
|
|
luaLog,
|
|
luaEventError,
|
|
diffApplyError,
|
|
packageActivationError,
|
|
resourceLoadError,
|
|
commandError,
|
|
networkError,
|
|
}
|