Files
clide/lib/kernel/src/log.dart
T
jpmschweitzerandClaude Opus 4.6 46329700d5 dissolve app/ into repo root (D-056)
Single Flutter package at the repo root. All code, tests, assets,
and platform directories moved from app/ to root. Package renamed
from clide_app to clide — all imports rewritten. Merged pubspec
combines core (ffi) and app (flutter, yaml, xterm) dependencies.
Makefile simplified: no APP_PRESENT conditionals, no cd, no daemon
lifecycle. 317 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 00:37:20 +02:00

89 lines
2.4 KiB
Dart

import 'dart:async';
import 'dart:io';
enum LogLevel { trace, debug, info, warn, error }
class LogRecord {
LogRecord({
required this.level,
required this.source,
required this.message,
required this.timestamp,
this.error,
this.stackTrace,
});
final LogLevel level;
final String source;
final String message;
final DateTime timestamp;
final Object? error;
final StackTrace? stackTrace;
@override
String toString() {
final lv = level.name.toUpperCase().padRight(5);
final buf =
StringBuffer('${timestamp.toIso8601String()} $lv [$source] $message');
if (error != null) buf.write(' | error=$error');
return buf.toString();
}
}
typedef LogSink = void Function(LogRecord);
class Logger {
Logger({this.minLevel = LogLevel.info, List<LogSink>? sinks})
: _sinks = List<LogSink>.from(sinks ?? <LogSink>[stderrSink]);
LogLevel minLevel;
final List<LogSink> _sinks;
final StreamController<LogRecord> _stream =
StreamController<LogRecord>.broadcast();
Stream<LogRecord> get records => _stream.stream;
void addSink(LogSink sink) => _sinks.add(sink);
void trace(String source, String message) =>
_emit(LogLevel.trace, source, message);
void debug(String source, String message) =>
_emit(LogLevel.debug, source, message);
void info(String source, String message) =>
_emit(LogLevel.info, source, message);
void warn(String source, String message, {Object? error}) =>
_emit(LogLevel.warn, source, message, error: error);
void error(String source, String message,
{Object? error, StackTrace? stackTrace}) =>
_emit(LogLevel.error, source, message,
error: error, stackTrace: stackTrace);
void _emit(LogLevel level, String source, String message,
{Object? error, StackTrace? stackTrace}) {
if (level.index < minLevel.index) return;
final rec = LogRecord(
level: level,
source: source,
message: message,
timestamp: DateTime.now().toUtc(),
error: error,
stackTrace: stackTrace,
);
for (final sink in _sinks) {
try {
sink(rec);
} catch (_) {
// a broken sink must not kill logging
}
}
if (!_stream.isClosed) _stream.add(rec);
}
Future<void> dispose() => _stream.close();
}
void stderrSink(LogRecord r) {
stderr.writeln(r);
if (r.stackTrace != null) stderr.writeln(r.stackTrace);
}