flutter_bug_report 0.3.3
flutter_bug_report: ^0.3.3 copied to clipboard
Flutter bug reports with the log already attached. Captures logger output, debugPrint and crashes, redacts secrets, and builds a bounded txt/json/zip. No vendor, no SDK.
0.3.3 #
Documentation only.
- The viewer is named at the top of the README now, not four screens down. A bundle arriving in a ticket is somebody else's problem to read, and the person who needs the viewer is often not the person who added the package.
What you getopens with the bundle as it actually reads — a screenshot of the viewer with the sample session in it, the gap and the burst visible — before the raw text of the same file.
0.3.2 #
Documentation only — no library change, nothing to migrate.
-
A viewer for the bundles. A bundle in a ticket still had to be read by somebody, and that meant downloading a zip, unzipping it and scrolling
logs.txtin an editor. The viewer takes all three formats and shows the shape of the session before a word of it is read: the quiet stretch, the gap where nothing was logged, the burst where it went wrong.It runs entirely in the page — no upload, no server, no request of any kind, because its own
Content-Security-Policyforbids one. That is a property somebody can check rather than a promise they have to take, which is the only version of this claim worth making for a package whose whole argument is that your logs are nobody else's business. It is tested against this repository's owntest/fixtures/, so the two cannot drift. -
A logo, shared by the package and the viewer. It is the density strip the viewer draws — quiet, a gap, then the burst. Not a metaphor for what the tool does; a picture of what it shows.
0.3.1 #
Two format defects, found by writing a parser against the output instead of against the description of it.
- A
.txtor.jsonbundle claimed a screenshot it could not carry. Thescreenshot: screenshot.pngline went into the report for every format, but only a zip has anywhere to put the file — so a report built as json with a screenshot attached named an attachment that was never in it, and sent whoever read it looking for a file that does not exist. Named in a zip only now. - A description with a line break in it broke the text header. The sheet
takes four lines, so this is reachable by anyone who presses Enter, and the
second line landed in the header looking like a field of its own.
Continuation lines are wrapped two-space indented, like the metadata block —
wrapped rather than escaped, because the header exists to be read and
\nin the middle of somebody's sentence reads worse than the wrap.
Added — golden bundles
test/fixtures/ now holds bundles written by the builder itself, one per case
worth getting wrong: a multi-line message (a Flutter error banner arrives
through debugPrint as one string, so an entry boundary cannot be "a line that
is not indented"), a multi-line description, every optional field absent at
once, truncated: true, a screenshot, and an empty session — in all three
formats.
They are here for a second reader: a log viewer parses this format from another repository and another language, and a parser written against a description of a format drifts from it the first time the format changes and nobody remembers to say so. Deleting the directory and running the suite regenerates them, so the diff of a format change is reviewable line by line. Not shipped to consumers of the package.
0.3.0 #
Written against a real integration report. Most of what follows is somebody else's afternoon, handed back.
Breaking — one config object instead of a parameter list
BugReportWrapper and BugReportSheet.show each took the same eleven
parameters, kept in step by hand. They now take one BugReportConfig, and the
report opened from a settings row can no longer drift away from the one opened
by the gesture.
// before
BugReportWrapper(onSubmit: upload, strings: ..., theme: ..., child: app)
// after
final config = BugReportConfig(onSubmit: upload, strings: ..., theme: ...);
BugReportWrapper(config: config, child: app)
BugReportSheet.show(context, config: config); // the same report
Added
onTriggeron the wrapper. The gesture no longer has to mean "open the report": an internal build can put a debug menu in front of it and still be handed the report, screenshot and all, rather than rebuilding the path.onTrigger: kReleaseMode ? null : (context, openReport) => ....fieldBuilderandbuttonBuilder. The field and the send button were aTextFieldand aFilledButtonand nothing could reach them, so a sheet in an app with its own design system read as a package bolted on. Draw both yourself and the collecting, redacting and bundling stay where they are.- A Cancel button, on by default (
showCancel: falseto drop it). A modal whose only way out is a swipe is a modal some people are stuck in, and the person stuck in it already had a problem to report.
Fixed
- The sheet opened as a full-screen panel with its content floating in the
middle.
isScrollControlledoffers a bottom sheet the whole screen, and theCenterwrapping the content took all of it. It shrink-wraps its height now and stays on the bottom edge. It also scrolls once there is not room — a short phone with the keyboard up had less height than the sheet wanted. - A successful send no longer leaves a timer running. The self-close was a
Future.delayednothing could call off, so every widget test that sent successfully failed on a pending timer unless it pumped the delay away. It is aTimernow, cancelled indispose. BugReportStrings.sendingand.cancelwere never rendered anywhere — translated by people who then found nothing used them. Both are on screen now: the send button says what it is doing instead of showing a bare spinner, and Cancel is a real button.- The README's Sentry recipe did not compile. It called
BugReport(text), andBugReportis anabstract final class— an accident that says something about the name, so the README now shows thehidefor apps that have aBugReportof their own. - The Privacy section still claimed the package does not read the device. It has since 0.2.0: device facts are collected by default, non-identifying by construction. Says so now.
Documented
- How to feed it the logger you already have. Most apps log through
talker,loggerorpackage:logging— which is where the HTTP calls are — and without a bridge the bundle arrives missing the most useful thing in it.BugReport.logwas always the seam; there is now a recipe for it. - The one ordering caveat that comes with such a bridge: a direct
BugReport.info(...)followed bybuild()is ordered, because the entry is queued synchronously andbuildwaits for the queue. An entry arriving through a stream is not.
0.2.2 #
- The sheet opened as a full-screen panel with its content floating in the
middle.
isScrollControlledoffers a bottom sheet the whole screen, and theCenterwrapping the content took all of it. It now shrink-wraps its height and stays on the bottom edge, where a bottom sheet belongs. - The content scrolls once there is not room for it — a short phone with the keyboard up had less height than the sheet wanted, and an overflow stripe across the form is a poor place to report a bug from.
- Layout is now tested through
BugReportSheet.show. The existing tests pumped the sheet into aScaffoldbody, which hands it a tight full-screen height — so none of them could see how it lays itself out when the height is its own to choose, which is exactly the case that was broken.
0.2.1 #
Setup was not as easy as 0.2.0 claimed. Found by writing the naive setup out and running it.
BugReportWrapperaboveMaterialAppthrew. The documented snippet —runApp(BugReportWrapper(child: MaterialApp(...)))— put the wrapper's own context outside Material, where opening a sheet fails for want ofMaterialLocalizations. The fix in 0.2.0 was to pass anavigatorKey, which is exactly the wiring this package exists to avoid. The wrapper now finds the app's navigator itself, and works aboveMaterialAppor inside itsbuilder.BugReport.init()is no longer needed for the wrapper to work. Collection starts on its own;initis for redactors, a persistent store, and capture ofdebugPrintand the framework's errors.- The README's install section still described 0.1.x and never introduced the sheet or the wrapper at all. Rewritten around what the package now does.
0.2.0 #
A UI, and everything around the log that makes a report worth reading. All of it optional; the ones that could carry somebody's details are off until you ask.
Added — UI
BugReportWrapper— wrap the app, long-press (or double-tap, or nothing) opens the sheet.enabledis a plain bool, so aconst falsefolds the whole thing out of a release build.BugReportSheet— a modal that writes, sends, and says whether it worked. Open it yourself from any trigger you like.BugReportThemeandBugReportStrings— every colour falls back to yourThemeDataand every word is a parameter, so it does not read as a package bolted onto an app.
Added — optional context
BugReportObserver— aNavigatorObserverthat writes the route trail into the log. Names only, never arguments.- Screenshots, off by default:
BugReportWrapper(withScreenshot: true). Taken before the sheet opens, shown to the person with a switch to drop it, and attached asscreenshot.png. A screenshot cannot be redacted, which is why consent comes from someone who can read it. FileLogStore— a log that survives the crash it describes, with retention and a size cap. Not the default and never will be: a file on disk outlives the session.BugReport.identify(id)— an id and nothing else.- Device facts from what Flutter already knows — platform, OS version, locale,
screen, build mode. No device id.
init(deviceFacts: false)to send none. Anything you pass inmetadatawins over what was collected.
0.1.1 #
Bundlenow carries themetadatait was built with. Whatever files the bundle usually wants the same facts beside it — as tags on an event, as fields on a form — and reading them back out of a zip to do that would be absurd.
0.1.0 #
First release under this name. Previously published as log_bundle, which is
now discontinued in favour of this package — the rename is the only difference
between log_bundle 0.1.2 and this release.
BugReport— a static API:BugReport.info(...),BugReport.error(...),await BugReport.build(...). No instance to hold and nothing to inject.- Logging before
init()is collected rather than dropped, andinit()carries those entries forward into the store it was given — so a startup bug is not lost to call ordering. - Automatic capture of
debugPrint, bareprint(viaConsoleCapture.runCaptured),FlutterError.onErrorandPlatformDispatcher.onError. None of it displaces a handler already installed. Redactor.defaults— bearer tokens, JWTs, Luhn-checked card numbers, and the usual credential field names. Applied on the way in, so a store never holds a secret.Redactor.patternandRedactor.keysfor your own rules.BundleFormat.text,.jsonand.zip. Zip carrieslogs.txtandreport.jsonside by side.- Bounded by entry count and by byte size, measured by rendering rather than estimated, and cut from the front so the end of the session survives.
LogStorewithMemoryLogStoreas the default: nothing written to the device.