Drops dead code across services, models, utils and widgets, including the connection auth service, which had no implementer, and the Live TV DVR provisioning models, which had no caller. Tests that only covered deleted behaviour are removed or trimmed. No behaviour change.
141 lines
4.2 KiB
Dart
141 lines
4.2 KiB
Dart
import 'dart:collection';
|
|
|
|
import 'package:logger/logger.dart';
|
|
|
|
import 'log_redaction_manager.dart';
|
|
|
|
/// Redacts sensitive information from a log field.
|
|
String _redactSensitiveData(String value) => LogRedactionManager.redact(value);
|
|
|
|
/// Represents a single log entry stored in memory
|
|
class LogEntry {
|
|
final DateTime timestamp;
|
|
final Level level;
|
|
final String message;
|
|
final Object? error;
|
|
final StackTrace? stackTrace;
|
|
|
|
const LogEntry({required this.timestamp, required this.level, required this.message, this.error, this.stackTrace});
|
|
|
|
/// Estimate the memory size of this log entry in bytes
|
|
int get estimatedSize {
|
|
int size = 0;
|
|
size += 8;
|
|
size += 4;
|
|
size += message.length * 2;
|
|
if (error != null) {
|
|
size += error.toString().length * 2;
|
|
}
|
|
if (stackTrace != null) {
|
|
size += stackTrace.toString().length * 2;
|
|
}
|
|
return size;
|
|
}
|
|
}
|
|
|
|
/// Custom log output that stores logs in memory with a circular buffer
|
|
///
|
|
/// Storage is handled by [MemoryAwareLogPrinter.log()] — this class only
|
|
/// forwards formatted lines to the console via the default [ConsoleOutput].
|
|
class MemoryLogOutput extends LogOutput {
|
|
static const int maxLogSizeBytes = 5 * 1024 * 1024;
|
|
static final ListQueue<LogEntry> _logs = ListQueue<LogEntry>();
|
|
static int _currentSize = 0;
|
|
|
|
static final _consoleOutput = ConsoleOutput();
|
|
|
|
static List<LogEntry> getLogs() => _logs.toList().reversed.toList();
|
|
|
|
static void clearLogs() {
|
|
_logs.clear();
|
|
_currentSize = 0;
|
|
}
|
|
|
|
@override
|
|
void output(OutputEvent event) {
|
|
// Only print to console — storage is done in MemoryAwareLogPrinter.log()
|
|
_consoleOutput.output(event);
|
|
}
|
|
}
|
|
|
|
/// Custom log printer that also stores error and stack trace information
|
|
class MemoryAwareLogPrinter extends LogPrinter {
|
|
final LogPrinter _wrappedPrinter;
|
|
|
|
MemoryAwareLogPrinter(this._wrappedPrinter);
|
|
|
|
@override
|
|
List<String> log(LogEvent event) {
|
|
// Store the log with error and stack trace if available
|
|
final message = _redactSensitiveData(event.message.toString());
|
|
final error = event.error != null ? _redactSensitiveData(event.error.toString()) : null;
|
|
final stackTrace = event.stackTrace != null
|
|
? StackTrace.fromString(_redactSensitiveData(event.stackTrace.toString()))
|
|
: null;
|
|
|
|
final logEntry = LogEntry(
|
|
timestamp: DateTime.now(),
|
|
level: event.level,
|
|
message: message,
|
|
error: error,
|
|
stackTrace: stackTrace,
|
|
);
|
|
|
|
MemoryLogOutput._logs.add(logEntry);
|
|
MemoryLogOutput._currentSize += logEntry.estimatedSize;
|
|
|
|
// Maintain buffer size limit (remove oldest entries) — O(1) with ListQueue
|
|
while (MemoryLogOutput._currentSize > MemoryLogOutput.maxLogSizeBytes && MemoryLogOutput._logs.isNotEmpty) {
|
|
final removed = MemoryLogOutput._logs.removeFirst();
|
|
MemoryLogOutput._currentSize -= removed.estimatedSize;
|
|
}
|
|
|
|
return _wrappedPrinter.log(LogEvent(event.level, message, time: event.time, error: error, stackTrace: stackTrace));
|
|
}
|
|
}
|
|
|
|
/// Custom production filter that respects our level setting even in release mode
|
|
class ProductionFilter extends LogFilter {
|
|
Level _currentLevel = Level.debug;
|
|
|
|
void setLevel(Level level) {
|
|
_currentLevel = level;
|
|
}
|
|
|
|
@override
|
|
bool shouldLog(LogEvent event) {
|
|
return event.level.value >= _currentLevel.value;
|
|
}
|
|
}
|
|
|
|
final _productionFilter = ProductionFilter();
|
|
|
|
/// Centralized logger instance for the application.
|
|
///
|
|
/// Usage:
|
|
/// ```dart
|
|
/// import 'package:plezy/utils/app_logger.dart';
|
|
///
|
|
/// appLogger.d('Debug message');
|
|
/// appLogger.i('Info message');
|
|
/// appLogger.w('Warning message');
|
|
/// appLogger.e('Error message', error: e, stackTrace: stackTrace);
|
|
/// ```
|
|
Logger appLogger = Logger(
|
|
printer: MemoryAwareLogPrinter(SimplePrinter()),
|
|
filter: _productionFilter,
|
|
level: Level.debug,
|
|
);
|
|
|
|
/// Update the logger's level dynamically based on debug setting
|
|
/// Recreates the logger instance to ensure it works in release mode
|
|
void setLoggerLevel(bool debugEnabled) {
|
|
final newLevel = debugEnabled ? Level.debug : Level.info;
|
|
|
|
_productionFilter.setLevel(newLevel);
|
|
|
|
appLogger = Logger(printer: MemoryAwareLogPrinter(SimplePrinter()), filter: _productionFilter, level: newLevel);
|
|
|
|
Logger.level = newLevel;
|
|
}
|