Repository navigation
0.0.11
Added
TelescopeRedaction.redactor, a host-set text redactor applied to every log, event, exception and HTTP record at insert.recordLog,recordEvent,recordExceptionandrecordHttp(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 aredactedgetter (true when a redactor ran), serialized intoJson. Only the store's redaction pass sets it: the constructors take noredactedargument andHttpRequestRecord.copyWithreturns 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,redactExceptionRecordandredactEventRecordjoinredactHttpRecordas the per-record entry points, each returning null for a dropped record, andresetForTesting()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.setFramePerfCapacitynow calls theframePerfkind. (lib/src/telescope_store.dart) LogRecordEntry.atUs, a monotonic timestamp. The sameFlutterTimeline.nowclockEventRecord.atUsuses, stamped at construction (LogRecordEntry.fromLogRecordincluded) and serialized intoJson. (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 fromonLogRecord,onEventRecordandonExceptionRecordas one line,{"kind": "log"|"event"|"exception", ...toJson()}, totimeline-<launch stamp>-<n>.jsonl, batched at 64 lines or 500 ms. It starts a new file before a line would passmaxFileBytesand deletes the oldest timeline files in the directory, earlier launches included, beyondmaxFiles. Fail closed: a record withredactedfalse is never written, only counted indroppedUnredacted. A batch write no caller awaits that fails stops the sink instead of raising an uncaught error, counted inwriteFailures, 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 towardmaxFileBytes, rather than truncating it.flush()writes the batch,stop()flushes and closes, andTelescopeFileSink.currentis the running sink. The package looks no directory up. (lib/src/telescope_file_sink.dart)- A cursor and filters on
ext.telescope.eventsandext.telescope.console. Both acceptsince(microseconds, exclusive, compared withatUs); events alsotype(prefix ofeventType), console alsologger(exact name). The filters run beforelimit: withsince,limitkeeps the OLDEST N after it, extended to the end of the run of records sharing the last one'satUs(the page may exceedlimitby those ties), so paging bycursorskips nothing; withoutsinceit keeps the newest N of what matched. Both answer acursor: the largestatUsreturned, else the givensince, else null, so passing it back assinceyields only newer records. Asincethat is not an integer is refused withinvalidParamsrather than read as "from the start". (lib/src/extensions/register_telescope_extensions.dart) ext.telescope.filesandext.telescope.file. Read the runningTelescopeFileSink.current:filesanswers{files: [{name, bytes}]}newest first,filetakesname,offsetandmaxBytesand answers{lines, next}. Both answer{error}when no sink runs, andfileanswers 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,--jsonand--followontelescope:eventsandtelescope:tail.--jsonprints one JSON object per line, the payload as JSON;--followre-reads every second from the returned cursor until interrupted. (lib/src/commands/)followCursor, the one--followloop.followCursor(read:, since:, interval:, delay:, shouldStop:)callsreadwith the cursor the previous round returned and waitsintervalbetween rounds; a null cursor keeps the last one. Pure Dart, exported frompackage:fluttersdk_telescope/cli.dart, and now behind bothtelescope:eventsandtelescope: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.
recordEventstores a valuejsonEncodecannot write (aDateTime, aDuration, any object) as itstoString(), and a non-String map key likewise, so one bad payload can no longer fail the wholeext.telescope.eventsresponse. A payload that is already safe keeps its identity. (lib/src/telescope_redaction.dart) toJsonof the log, event, exception and HTTP records always carriesredacted. (lib/src/records/)- BREAKING:
TelescopeRedaction.redactHttpRecordreturnsHttpRequestRecord?. It wasHttpRequestRecord; 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
minLevelmatched every log line.recentLogs(minLevel: 'bogus')now returns an empty list instead of the whole buffer. (lib/src/telescope_store.dart) - A negative
limitthrew. EveryrecentX(limit:)returns an empty list for a zero or negative limit instead of aRangeError. (lib/src/telescope_store.dart) - A payload
jsonEncodecannot write failed the wholeext.telescope.eventsresponse. The payload is now made JSON-safe when the event is recorded (see Changed). (lib/src/telescope_redaction.dart)