Skip to content

factor out the stack parsing nonsense into a reusable library #4021

Closed

Description

@Hixie

If we do any more stack parsing, it's time to bite the bullet and just write a library to parse them. It's becoming far too brittle to do it with handcrafted RegExps everywhere.

Activity

  1. added
    c: contributor-productivityTeam-specific productivity, code health, technical debt.
    frameworkflutter/packages/flutter repository. See also f: labels.
    on May 18, 2016
  2. added this to the milestone on May 18, 2016
  3. yjbanov commented on Nov 14, 2016

    @yjbanov
    Contributor

    Can it be extracted from package:stack_trace? In fact, I'd rather keep using package:stack_trace if it provided a way to customize how the stack frames are formatted.

    @nex3, is any of the above possible today or in the future?

  4. Hixie commented on Nov 14, 2016

    @Hixie
    ContributorAuthor

    Stack frame parsing is pretty trivial (https://github.com/dart-lang/stack_trace/blob/master/lib/src/frame.dart#L130 is the bulk of it in stack_frame). The problem with reusing stack_frame is we're paying the cost for a lot of functionality we don't need in Flutter (for example, parsing Safari stack frames). In principle the async chain support would be good too, but in practice it's not because what you really want is the conceptual stack, which you can't really derive from the chains (the chains generally just consist of a bunch of privates in dart:async, followed by a single frame or so that's the continuation of the previous code... which doesn't really match what the code looks like any more than the regular stack trace without the chaining).

  5. eseidelGoogle commented on Nov 14, 2016

    @eseidelGoogle
    Contributor

    My understanding was also that the VM planned to make stack-trace handling better/prettier (like handling of async by default). @a-siva or @johnmccutchan would know.

  6. nex3 commented on Nov 14, 2016

    @nex3

    Can it be extracted from package:stack_trace?

    I'm not sure what you mean by "extract". The stack_trace package is already the place to which we extract stack parsing.

    The problem with reusing stack_frame is we're paying the cost for a lot of functionality we don't need in Flutter (for example, parsing Safari stack frames).

    Pretty much any package you use is going to have some stuff you don't use. That's the nature of packaging related functionality for re-use. Luckily Dart tools tend to have pretty good support for tree-shaking to ditch unused code before it's distributed to the public.

    (the chains generally just consist of a bunch of privates in dart:async, followed by a single frame or so that's the continuation of the previous code... which doesn't really match what the code looks like any more than the regular stack trace without the chaining).

    I'm surprised that you don't find stack chains useful. That's contrary to the vast majority of user feedback I get.

    Terse and folded stacks usually eliminate most of the core library cruft. Even if they didn't, though, surely having full information about where an error happened is more useful than having no information, even if you have to dig through some irrelevant lines.

  7. yjbanov commented on Nov 14, 2016

    @yjbanov
    Contributor

    I'm not sure what you mean by "extract".

    Nothing, I didn't realize it was public already :)

    But, if we don't want to depend on Safari, then it could be extracted into a standalone package that only knows how to parse VM stack traces and not JS stack traces.

    I'm surprised that you don't find stack chains useful. That's contrary to the vast majority of user feedback I get.

    👍

    Losing asynchronous stacks makes it much harder to debug async code. Perhaps we're not writing a lot of async code in Flutter, but I'm sure our users will. Any time you talk to the network, file system, or a Redux-like framework, you are dealing with asynchrony that's super hard to debug without chaining.

  8. Hixie commented on Nov 14, 2016

    @Hixie
    ContributorAuthor

    I'd be curious to see an example of how a chain is useful. I see them all the time (e.g. from flutter_test) but have literally never been able to use them to help me debug the problem.

  9. yjbanov commented on Nov 14, 2016

    @yjbanov
    Contributor

    I'd be curious to see an example

    Sure. In this commit I added a chain because when a devicelab test failed to run a process (btw, here's another async use-case right there), all we got was:

    Task failed: Executable failed with exit code 2.
    
    #0      fail (package:flutter_devicelab/framework/utils.dart:71:3)
    #1      exec.<exec_async_body> (package:flutter_devicelab/framework/utils.dart:210:5)
    #2      _RootZone.runUnary (dart:async/zone.dart:1404)
    #3      _FutureListener.handleValue (dart:async/future_impl.dart:131)
    #4      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:637)
    #5      _Future._propagateToListeners (dart:async/future_impl.dart:667)
    #6      _Future._completeWithValue (dart:async/future_impl.dart:477)
    #7      _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:528)
    #8      _microtaskLoop (dart:async/schedule_microtask.dart:41)
    #9      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50)
    #10     _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:96)
    #11     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:149)
    

    After the change it reports this:

    Task failed: Executable failed with exit code 2.
    
    Stack trace:
    package:flutter_devicelab/framework/utils.dart 71:3        fail
    package:flutter_devicelab/framework/utils.dart 210:5       exec.<async>
    ===== asynchronous gap ===========================
    dart:async                                                 _Completer.completeError
    package:flutter_devicelab/framework/utils.dart 218:1       exec.<async>
    ===== asynchronous gap ===========================
    dart:async                                                 _asyncThenWrapperHelper
    package:flutter_devicelab/framework/utils.dart             exec
    package:flutter_devicelab/framework/utils.dart 236:10      flutter
    package:flutter_devicelab/tasks/perf_tests.dart 66:13      StartupTest.call.<async>.<fn>.<async>
    dart:async                                                 _SyncCompleter.complete
    package:flutter_devicelab/framework/utils.dart 212:3       exec.<async>
    ===== asynchronous gap ===========================
    package:flutter_devicelab                                  StartupTest.call.<async>.<fn>
    package:flutter_devicelab/framework/utils.dart 249:24      inDirectory.<async>
    ===== asynchronous gap ===========================
    dart:async                                                 Future.Future.microtask
    package:flutter_devicelab/framework/utils.dart             inDirectory
    package:flutter_devicelab/tasks/perf_tests.dart 57:18      StartupTest.call.<async>
    ===== asynchronous gap ===========================
    dart:async                                                 Future.Future.microtask
    package:flutter_devicelab/tasks/perf_tests.dart            StartupTest.call
    package:flutter_devicelab/framework/framework.dart 122:36  _TaskRunner._performTask.<fn>.<async>
    ===== asynchronous gap ===========================
    dart:async                                                 Future.Future.microtask
    package:flutter_devicelab/framework/framework.dart         _TaskRunner._performTask.<fn>
    package:stack_trace                                        Chain.capture
    package:flutter_devicelab/framework/framework.dart 121:11  _TaskRunner._performTask
    package:flutter_devicelab/framework/framework.dart 81:33   _TaskRunner.run.<async>
    

    A-ha! So a StartUp test is trying to run a flutter command which fails. I can now go to that code and try to debug it.

  10. Hixie commented on Nov 14, 2016

    @Hixie
    ContributorAuthor

    Ah, yeah, that's a good example where it's useful. Not as good as a true async view of the stack (one that only had exec. in the stack once, that is), but still, more useful than the original.

  11. nex3 commented on Nov 15, 2016

    @nex3

    But, if we don't want to depend on Safari, then it could be extracted into a standalone package that only knows how to parse VM stack traces and not JS stack traces.

    I think the current factoring of the package is fine. It doesn't depend on Safari, it just has some logic for parsing stack frames that could come from Safari. It's no different than using the collection package without calling the compareNatural() function, for example.

    Not as good as a true async view of the stack (one that only had exec. in the stack once, that is), but still, more useful than the original.

    The extra exec frames are actually a factor of how the VM implements async/await, not something inherent to stack chains.

  12. modified the milestones: , on Jan 30, 2017
  13. eseidelGoogle commented on Feb 23, 2017

    @eseidelGoogle
    Contributor

    I'm not sure what to do with this bug? It seems like package:stacktrace is the library? Is there a concrete bug we can file with package:stacktrace, or does this bug still serve utility?

  14. yjbanov commented on Feb 23, 2017

    @yjbanov
    Contributor

    Now that we're teaching crash reporting back-ends about Dart stack traces it would help to keep the number of different formats to a minimum. This also means that future changes to stack trace formats (VM or package:stack_trace) should be planned and driven by some level of consensus across teams.

  15. Hixie commented on Feb 24, 2017

    @Hixie
    ContributorAuthor

    We would like to avoid adding new dependencies (and remove many of our existing ones), for reasons we can discuss offline, but that is one reason not to just defer to another package (especially for something this trivial). If we do this, we should just implement it in the foundation layer. I would have done this already except that the stack logic on the Dart side has been in flux (e.g. adding an annotation for asynchronous continuations and so on) and may change some more (e.g. I've been hoping the StackTrace class itself would become more introspectable), so I've been waiting for that to settle down.

  16. Hixie commented on Mar 3, 2017

    @Hixie
    ContributorAuthor

    One of the things this would enable is fixing the "ourFault" logic in assertions.dart in a more robust way.

  17. modified the milestones: 3: Current Milestone, on Oct 17, 2017
  18. self-assigned this
    on Jan 18, 2018
  19. modified the milestones: , on May 21, 2018
  20. removed their assignment
    on Jul 16, 2019
  21. github-actions commented on Aug 17, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  22. locked as resolved and limited conversation to collaborators on Aug 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: qualityA truly polished experiencec: contributor-productivityTeam-specific productivity, code health, technical debt.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions