rk_syslog 0.2.0
rk_syslog: ^0.2.0 copied to clipboard
A syslog sink for Dart — RFC 5424 framing, RFC 5425 delivery over TLS, and a bounded on-disk spool so records survive a crash and never block the caller.
example/example.md
Пример #
Нативную часть собрать заранее: cd rust && cargo build --release.
import 'dart:io';
import 'package:rk_syslog/rk_syslog.dart';
void main() {
// Ключи задаются по имени. Опечатка в ключе остановит открытие приёмника,
// а не останется незамеченной.
final config = RkSyslogConfig(spoolDirectory: '/var/lib/telepos/syslog')
..identify(hostName: 'till-01', appName: 'telepos', procId: '$pid')
..facility = RkFacility.local0
..set('spool_max_bytes', '33554432') // 32 МиБ
..set('spool_policy', 'drop_oldest')
// Закреплённый отпечаток вместо удостоверяющего центра: у сборщика в
// магазине обычно нет ни одного, которому мы могли бы доверять заранее.
..set('collector_scheme', 'tls')
..set('collector_host', 'logs.shop.example')
..set('tls_server_fingerprint_sha256',
'5e:88:48:98:da:28:04:71:51:d0:e5:6f:8d:c6:29:27'
':73:60:3d:0d:6a:ab:bd:d6:2a:11:ef:72:1d:15:42:d8');
// Отказ приходит значением, а не исключением из чужого стека (И144).
final opened = RkSyslogSink.open(config);
if (opened case RkSyslogFailure(:final status, :final detail)) {
stderr.writeln('приёмник не открылся: ${status.wireName}: $detail');
return;
}
final sink = opened.valueOrThrow();
// Структурированные данные строятся, а не склеиваются: экранирование
// делает нативная сторона, ровно один раз и по §6.3.3.
final sale = RkStructuredData()
..element('sale@0').param('receipt', '000123').param('total', '1250.00')
..element('till@0').param('id', 'till-01');
final submitted = sink.submit(
severity: RkSeverity.informational,
msgid: 'SALE',
structuredData: sale,
message: 'чек закрыт',
);
// Запись, которую нельзя обрамить, сообщается здесь и сейчас, с названием
// поля, — а не исчезает по дороге.
if (submitted case RkSyslogFailure(:final detail)) {
stderr.writeln('запись не принята: $detail');
}
// Пока сюда шло управление, ничего не ждало сеть. Сборщик может быть
// недоступен неделю — касса торгует на полной скорости.
print('в буфере: ${sink.stat('spool_records').valueOrNull}');
print('отправлено: ${sink.stat('sent').valueOrNull}');
print('потеряно по границе: '
'${sink.stat('spool_dropped_records').valueOrNull}');
// Единственный блокирующий вызов, и блокирует он только того, кто его позвал.
sink.flush(timeout: const Duration(seconds: 5));
// Обязателен: сборщик мусора Dart не знает ни о буфере, ни о рабочем
// потоке, ни о сокете (И146).
sink.close();
}
Проверить, что стороны согласны #
Смысл того, что перечисления пересекают границу по имени (И147), — в том, что таблицы можно сверить, а не предположить их одинаковыми:
final problems = RkSyslogSink.verifyNameTables();
if (problems.isNotEmpty) {
stderr.writeln('пакет и библиотека разошлись:\n${problems.join('\n')}');
}