Skip to content

0.0.11

Choose a tag to compare

@github-actions github-actions released this 10 Oct 09:37
· 1 commit to master since this release
a4ca348

Added

  • TelescopeRedaction.redactor, a host-set text redactor applied to every log, event, exception and HTTP record at insert. recordLog, recordEvent, recordException and recordHttp (after its key masking) run it over every String field, every String and map key inside an event payload's nested Maps and Lists, and the stack text, before the record enters its queue or its stream; a record the redactor throws on is dropped, neither buffered nor emitted. Each of the four records gains a redacted getter (true when a redactor ran), serialized in toJson. Only the store's redaction pass sets it: the constructors take no redacted argument and HttpRequestRecord.copyWith returns an unredacted copy, so no caller can build a record a persisting consumer would take for masked. A record buffered while no redactor was registered stays false, so a consumer that persists records can write only the redacted ones. A subtree nested past 64 levels is masked whole. redactLogRecord, redactExceptionRecord and redactEventRecord join redactHttpRecord as the per-record entry points, each returning null for a dropped record, and resetForTesting() unregisters the redactor. (lib/src/telescope_redaction.dart, lib/src/telescope_store.dart, lib/src/records/)
  • Per-kind buffer capacity. TelescopeStore.setCapacity(int, {TelescopeKind? kind}) caps one of the ten buffers (TelescopeKind); the call without a kind keeps today's shared behaviour, and a kind cap wins over the shared one. setFramePerfCapacity now calls the framePerf kind. (lib/src/telescope_store.dart)
  • LogRecordEntry.atUs, a monotonic timestamp. The same FlutterTimeline.now clock EventRecord.atUs uses, stamped at construction (LogRecordEntry.fromLogRecord included) and serialized in toJson. (lib/src/records/log_record_entry.dart)
  • TelescopeFileSink, a rotating JSONL timeline on disk that writes only redacted records. TelescopeFileSink.start(directory:, maxFileBytes: 1048576, maxFiles: 8) creates the host-given directory and writes every log, event and exception record from onLogRecord, onEventRecord and onExceptionRecord as one line, {"kind": "log"|"event"|"exception", ...toJson()}, to timeline-<launch stamp>-<n>.jsonl, batched at 64 lines or 500 ms. It starts a new file before a line would pass maxFileBytes and deletes the oldest timeline files in the directory, earlier launches included, beyond maxFiles. Fail closed: a record with redacted false is never written, only counted in droppedUnredacted. A batch write no caller awaits that fails stops the sink instead of raising an uncaught error, counted in writeFailures, and a sink that cannot create its directory or first file neither listens nor becomes current. files() lists {name, bytes} of every timeline file in the directory, earlier launches included, newest first; read(name, offset:, maxBytes:) returns whole lines as {lines, next}, decodes an offset inside a multi-byte character without throwing, and refuses (returns null) any name that is not exactly one of those listed files, so a path, a .. segment or a link reaches nothing. A sink started again within the same second (the stamp has second precision) appends to the file of the sink it replaced, counting its bytes toward maxFileBytes, rather than truncating it. flush() writes the batch, stop() flushes and closes, and TelescopeFileSink.current is the running sink. The package looks no directory up. (lib/src/telescope_file_sink.dart)
  • A cursor and filters on ext.telescope.events and ext.telescope.console. Both accept since (microseconds, exclusive, compared with atUs); events also type (prefix of eventType), console also logger (exact name). The filters run before limit: with since, limit keeps the OLDEST N after it, extended to the end of the run of records sharing the last one's atUs (the page may exceed limit by those ties), so paging by cursor skips nothing; without since it keeps the newest N of what matched. Both answer a cursor: the largest atUs returned, else the given since, else null, so passing it back as since yields only newer records. A since that is not an integer is refused with invalidParams rather than read as "from the start". (lib/src/extensions/register_telescope_extensions.dart)
  • ext.telescope.files and ext.telescope.file. Read the running TelescopeFileSink.current: files answers {files: [{name, bytes}]} newest first, file takes name, offset and maxBytes and answers {lines, next}. Both answer {error} when no sink runs, and file answers one fixed {error} message for every refusal; the name only reaches the sink's own allowlist. (lib/src/extensions/register_telescope_extensions.dart)
  • --since, --type / --logger, --json and --follow on telescope:events and telescope:tail. --json prints one JSON object per line, the payload as JSON; --follow re-reads every second from the returned cursor until interrupted. (lib/src/commands/)
  • followCursor, the one --follow loop. followCursor(read:, since:, interval:, delay:, shouldStop:) calls read with the cursor the previous round returned and waits interval between rounds; a null cursor keeps the last one. Pure Dart, exported from package:fluttersdk_telescope/cli.dart, and now behind both telescope:events and telescope:tail. (lib/src/cursor_follow.dart, lib/cli.dart)
  • telescope:files [--name=<file>] [--offset=<n>]. Lists the timeline files, or prints the lines of one; prints the extension's error message, not a stack, when no sink runs. (lib/src/commands/telescope_files_command.dart, lib/src/telescope_artisan_provider.dart)

Changed

  • Event payloads are JSON-safe at record time. recordEvent stores a value jsonEncode cannot write (a DateTime, a Duration, any object) as its toString(), and a non-String map key likewise, so one bad payload can no longer fail the whole ext.telescope.events response. A payload that is already safe keeps its identity. (lib/src/telescope_redaction.dart)
  • toJson of the log, event, exception and HTTP records always carries redacted. (lib/src/records/)
  • BREAKING: TelescopeRedaction.redactHttpRecord returns HttpRequestRecord?. It was HttpRequestRecord; it now returns null, the record dropped, when the registered redactor throws, so a caller outside the store adds a null check. (lib/src/telescope_redaction.dart)

Fixed

  • An unknown minLevel matched every log line. recentLogs(minLevel: 'bogus') now returns an empty list instead of the whole buffer. (lib/src/telescope_store.dart)
  • A negative limit threw. Every recentX(limit:) returns an empty list for a zero or negative limit instead of a RangeError. (lib/src/telescope_store.dart)
  • A payload jsonEncode cannot write failed the whole ext.telescope.events response. The payload is now made JSON-safe when the event is recorded (see Changed). (lib/src/telescope_redaction.dart)