Files
plezy/lib/utils/app_logger.dart
T
edde746 4307c49cd2 refactor: remove unreachable code paths and unused members
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.
2026-07-26 06:09:47 +02:00

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;
}