Skip to main content

Logging & tracing

Two interceptors give you observability without touching the transport: LoggingInterceptor for structured logs, and EventTraceInterceptor for a machine-readable trace of every event (the feed koel_devtools consumes).

import 'dart:async';
import 'package:koel/koel.dart' show HttpAgent, KoelClient;
import 'package:koel_http/koel_http.dart'
show EventTraceInterceptor, LoggingInterceptor, TraceEntry;
import 'package:logging/logging.dart' show Level, Logger;

void main() {
// package:logging is the sink LoggingInterceptor writes to.
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((r) => print('${r.level.name}: ${r.message}'));

final traces = StreamController<TraceEntry>();
traces.stream.listen((entry) => print('trace: $entry'));

final client = KoelClient(
agent: HttpAgent(url: Uri.parse('https://your-backend.example/agui')),
interceptors: [
LoggingInterceptor(level: Level.INFO),
EventTraceInterceptor(sink: traces.sink),
],
);
// ... use client; close traces when done.
}

Logging

LoggingInterceptor emits structured request/response records through package:logging at the level you choose, so it routes through your app's existing logging setup rather than print.

Tracing

EventTraceInterceptor writes a TraceEntry to the Sink you supply for each event — wire it to a StreamController (above), a ring buffer, or directly to the koel_devtools observer. It is the structured trail behind time-travel replay and post-hoc inspection.

For redaction before anything reaches a log, add PII redaction ahead of the logger in the chain.