Sink customizado
Qualquer destino de log pode ser integrado implementando a interface LogSink.
Interface
abstract class LogSink {
Future<void> write(LogModel event);
}
Exemplo: sink para arquivo
import 'dart:convert';
import 'dart:io';
import 'package:structured_logger/structured_logger.dart';
class FileSink extends LogSink {
FileSink(this.file);
final File file;
Future<void> write(LogModel event) async {
final line = json.encode(event.toMap());
await file.writeAsString('$line\n', mode: FileMode.append);
}
}
Uso:
final logger = StructureLogger();
logger.addSink(FileSink(File('/tmp/app.log')));
await logger.log(
'Sync completed in {ms}ms',
level: LogLevel.info,
data: {'ms': 340},
);
Exemplo: sink com filtro por nível
class LevelFilterSink extends LogSink {
LevelFilterSink(this.delegate, {required this.minLevel});
final LogSink delegate;
final LogLevel minLevel;
static const _order = {
LogLevel.verbose: 0,
LogLevel.debug: 1,
LogLevel.info: 2,
LogLevel.warning: 3,
LogLevel.error: 4,
};
Future<void> write(LogModel event) async {
final eventLevel = LogLevel.values.firstWhere(
(l) => l.sValue == event.level,
orElse: () => LogLevel.debug,
);
if (_order[eventLevel]! >= _order[minLevel]!) {
await delegate.write(event);
}
}
}
Boas práticas
- Mantenha
write()rápido — operações pesadas (HTTP, disco) podem bloquear quem chamalog(). Considere enfileirar em background para alto volume. - Não lance exceções não tratadas — falhas no sink não devem derrubar o app. Capture erros internamente.
- Use
LogModel.toMap()— serialização consistente com CLEF. - Implemente dispose se necessário — feche conexões, streams ou clients quando o sink não for mais usado (como
SinkSeq.close()).
Registro e remoção
final sink = FileSink(logFile);
logger.addSink(sink);
// ... mais tarde
logger.removeSink(sink);