Giter VIP home page Giter VIP logo

abbreviatedstacktraces.jl's Introduction

AbbreviatedStackTraces.jl

The goal of this is to demonstrate an improvement to the display of stack traces in the Julia REPL, associated with this PR: JuliaLang/julia#40537

Rationale

Julia's stacktraces are often too long to be practical for most users. This can form a barrier to entry and become an annoyance.

So how can we maximize the utility of the stack traces for the common case?

My philosophy is this: 95% of the time, a given exception is due to a mistake in your own code. The probability of the exception being due to a mistake in a well-used dependency is much lower, and the probability of the exception being due to a mistake in Base is even smaller. The probability of an exception being due to a mistake in the compiler is infinitesimal (but nonzero).

Thus, the highest value stack frames, the majority of the time, are those relating to code you have written or are actively developing. The stack frames between your call into a foreign method and the frame where the validation occurs is usually irrelevant to you. And for composed functions, the internal frames between the call into a foreign function and where it emerges back into your code also doesn't usually matter. Those frames are implementation details that don't make a difference to whether your code works.

Which raised the question: what counts as "your" code?

I think clearly these sources can be assumed to not be your code, and more likely stable:

  • Julia Base
  • Julia Stdlibs
  • Dependencies acquired using Pkg add

Whereas these sources are "yours":

  • Activated local package
  • Code defined in the REPL
  • Dependencies acquired using Pkg dev
  • Modules or files matching ENV["JULIA_DEBUG"] (file basename and/or module names; comma-separated, ! to exclude)

All frames originating from "your" code are shown by default, as well as the immediate next frame to show what function your code called. This information should be sufficient in most cases to understand that you made a mistake, and where that mistake was located. Note that this only works by default in interactive usage. Running unit tests (e.g. via pkg>test) or execution on distributed processes will show the full trace. This behavior can be customized via the options below.

But in the rarer case where the issue was not in your code, the full trace can be retrieved from the err global variable.

Options

  • ENV["JULIA_STACKTRACE_ABBREVIATED"] = true enables abbreviated stack traces for all traces, not just those originating from an interactive session
  • ENV["JULIA_STACKTRACE_MINIMAL"] = true omits type information for a one-line-per-frame minimal variant (see below)
  • ENV["JULIA_STACKTRACE_PUBLIC"] = true will re-insert all functions from a module's public API (part of names(module); Julia < 1.11, this will just be exported names)

startup.jl and VSCode

Unfortunately, startup.jl is executed before VSCodeServer loads, which means the appropriate methods won't be overwritten. Some workarounds are discussed here: #38

Examples

Here's an example of a stack trace by chaining BenchmarkTools and Plots:

]add AbbreviatedStackTraces
using AbbreviatedStackTraces # over-writes error-related `Base` methods
using BenchmarkTools, Plots
@btime plot([1,2,3], seriestype=:blah)
image

It aims to find the stack frames of code you don't control and excludes them by default, except for the first frame into that package. In it's place, it lists the modules called in the intervening frames. The theory is that errors in your code are much more likely than errors inside Base, the Stdlibs, or published packages, so their internals are usually superfluous.

image

(Note: italics only works on Julia 1.10+)

The global err variable stores the last error and can show the full, original stack trace easily.

You can also add back functions with public (Julia 1.11) or exported (Julia 1.9, 1.10) names by setting ENV["JULIA_STACKTRACE_PUBLIC"] = true.

image

There is an optional minimal display available, accessed by setting ENV["JULIA_STACKTRACE_MINIMAL"] = true.

image

Here's an example a beginner might readily run into:

image

Yikes!

With this package:

image

Much better!

abbreviatedstacktraces.jl's People

Contributors

alecloudenback avatar antoine-levitt avatar axsk avatar bioturbonick avatar datseris avatar jameswrigley avatar rafaqz avatar sloede avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

abbreviatedstacktraces.jl's Issues

Extra frames in nested exception when error `include`ing

Consider trimming top-level frames when an error is encountered when using a package.

To reproduce, just add an undefined variable name inside a module then trigger precompilation via using.

[ Info: Precompiling BioFetch [f8217676-c24a-4825-a874-ba6ce2a4fe08]
ERROR: LoadError: UndefVarError: Format not defined
Stacktrace:
 [1] top-level scope
   @ ~/.julia/dev/BioFetch/src/BioFetch.jl:72
 [2] include
   @ ./Base.jl:389 [inlined]
 [3] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::Nothing)
   @ Base ./loading.jl:1219
 [4] top-level scope
   @ none:1
 [5] eval
   @ ./boot.jl:369 [inlined]
 [6] eval(x::Expr)
   @ Base.MainInclude ./client.jl:456
 [7] top-level scope
   @ none:1
in expression starting at /home/nicho/.julia/dev/BioFetch/src/BioFetch.jl:1
ERROR: Failed to precompile BioFetch [f8217676-c24a-4825-a874-ba6ce2a4fe08] to /home/nicho/.julia/compiled/v1.7/BioFetch/jl_kjdfEq.

Support VSCode using startup.jl

Currently AbbreviatedStackTraces doesn't work in VSCode if you have using AbbreviatedStackTraces in your startup.jl file. If you try to using again after startup, it still doesn't work. However it does work outside of VSCode using the startup.jl file and inside of VSCode not using the startup.jl file.

Allow user to turn this off

Some people just want to see the REPL burn. Provide an environment variable, REPL option(?), or similar that turns this off.

Bonus: See if there's a way to have development Julia versions to default this behavior to off to make the core Julia developers happier.

How to handle custom sys images?

I'm using a custom system image that contains OhMyREPL.jl. In this case, the output isn't as minimal as shown in the README.md anymore:

julia> @btime plot([1,2,3], seriestype=:blah)
ERROR: The backend must not support the series type Val{:blah}, and there isn't a series recipe defined.
Stacktrace:
     [1] error(s::String)
       @ Base ~/.julia/sysimgs/std.so:-1
   [2-7] ⋮ [internal frames]
       @ RecipesPipeline, Plots, [inlined methods]
     [8] plot(args::Any; kw::Any)
       @ Plots ~/.julia/packages/Plots/kyYZF/src/plot.jl:58
  [9-16] ⋮ [internal frames]
       @ Main, BenchmarkTools, [inlined methods]
    [17] top-level scope
       @ ~/.julia/packages/BenchmarkTools/ms0Xc/src/execution.jl:565
    [18] eval_user_input(ast::Any, backend::REPL.REPLBackend)
       @ REPL ~/.julia/sysimgs/std.so:-1
    [19] repl_backend_loop(backend::REPL.REPLBackend)
       @ REPL ~/.julia/sysimgs/std.so:-1
    [20] start_repl_backend(backend::REPL.REPLBackend, consumer::Any)
       @ REPL ~/.julia/sysimgs/std.so:-1
    [21] run_repl(repl::REPL.AbstractREPL, consumer::Any; backend_on_current_task::Bool)
       @ REPL ~/.julia/sysimgs/std.so:-1
    [22] run_repl(repl::REPL.AbstractREPL, consumer::Any)
       @ REPL ~/.julia/sysimgs/std.so:-1
    [23] (::Base.var"#874#876"{Bool, Bool, Bool})(REPL::Module)
       @ Base ~/.julia/sysimgs/std.so:-1
    [24] run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_file::Bool, color_set::Bool)
       @ Base ~/.julia/sysimgs/std.so:-1
    [25] exec_options(opts::Base.JLOptions)
       @ Base ~/.julia/sysimgs/std.so:-1    [26] _start()
       @ Base ~/.julia/sysimgs/std.so:-1
Use `err` to retrieve the full stack trace.

julia> ENV["JULIA_STACKTRACE_MINIMAL"] = true
true

julia> @btime plot([1,2,3], seriestype=:blah)
ERROR: The backend must not support the series type Val{:blah}, and there isn't a series recipe defined.
Stacktrace:
     [1] error @ Base ~/.julia/sysimgs/std.so:-1
   [2-7] ⋮ [internal frames] @ RecipesPipeline, Plots, [inlined methods]
     [8] plot @ Plots ~/.julia/packages/Plots/kyYZF/src/plot.jl:58
  [9-16] ⋮ [internal frames] @ Main, BenchmarkTools, [inlined methods]
    [17] top-level scope @ ~/.julia/packages/BenchmarkTools/ms0Xc/src/execution.jl:565
    [18] eval_user_input @ REPL ~/.julia/sysimgs/std.so:-1
    [19] repl_backend_loop @ REPL ~/.julia/sysimgs/std.so:-1
    [20] start_repl_backend @ REPL ~/.julia/sysimgs/std.so:-1
    [21] YY.run_replYY.42 @ REPL ~/.julia/sysimgs/std.so:-1
    [22] run_repl @ REPL ~/.julia/sysimgs/std.so:-1
    [23] YY.874 @ Base ~/.julia/sysimgs/std.so:-1
    [24] run_main_repl @ Base ~/.julia/sysimgs/std.so:-1
    [25] exec_options @ Base ~/.julia/sysimgs/std.so:-1    [26] _start @ Base ~/.julia/sysimgs/std.so:-1
Use `err` to retrieve the full stack trace.

Personally, I wouldn't want to see the lines with ~/.Julia/sysimgs/std.so:-1 because they aren't really under my control. Also, I can get the full stack trace via err if I care anyways.

Release?

I understand the goal is to eventually get this into Julia's default, but wouldn't it help to release this as a package for now?

Idea: Show MethodErrors originating from an "internal" frame differently.

Brainstorm: What if MethodErrors from "internal" frames (in the sense I'm using for AbbreviatedStackTraces) were shown differently?

May not belong in this package but I'll document it here anyway.

A big problem for people getting into Julia is not getting why an internal MethodError is being thrown. Is it because the input up the stack didn't conform to an interface expected down the stack? Or is it due to an internal error?

Perhaps a solution is to render those differently. Currently, the error is oriented towards someone who has control over the internals.

Do something about huge type parameters

     [4] _typed_hvncat(::Type{Int64}, ::Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Tuple{Int64}}, ::Bool, ::Array{Int64, 0}, ::Array{Int64, 0}, ::Vararg{Any})

Do not print last frame?

I know I'm the one who suggested printing more frames, but after trying this out I feel it's more confusing than anything. Possibly the simplest option is to just not print any extra frame.

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

Highlight ellipsis in some way?

Ellipsis are quite easy to miss in a stacktrace, and should be highlighted better. Maybe by putting them at the first column, so they stand out from the [n]?

Ensure worker processes show full trace?

I think when I changed to using an IOContext option, it caused worker processes to start using the compact code.

Although the full trace can be retrieved, it may be deemed too risky for losing information.

Also, worker processes don't seem to store Module information in their stack frames, which complicates the abbreviated display even if we wanted to.

Code executed headless (e.g. ./julia --eval) is not affected.

1.10 broken?

On the 1.10 beta, this seems to just not work; I'm getting the very long (unfolded) stacktraces again.

Using `AbbreviatedStackTraces` in another module breaks precompilation

Something about the recent move of the includes to the __init__ function makes it such that you can't add AbbreviatedStackTraces as a dependency for another module. Things work fine if I go back to AbbreviatedStackTraces v0.1.9. EDIT: Turns out that only fixes it at one level. If I have another package that depends on the package that depends on AbbreviatedStackTraces, it breaks even on AbbreviatedStackTraces v0.1.9.

Reproducer:

(@v1.8) pkg> generate Blah

(@v1.8) pkg> activate Blah

(Blah) pkg> add AbbreviatedStackTraces

Then editing src/Blah.jl to look like this

module Blah
using AbbreviatedStackTraces
end

and precompiling gives the following error:

(Blah) pkg> precompile
Precompiling project...
  ✗ Blah
  0 dependencies successfully precompiled in 1 seconds. 1 already precompiled.

ERROR: The following 1 direct dependency failed to precompile:

Blah [501caa54-5604-45a8-b8b7-ddcb4fd2be46]

Failed to precompile Blah [501caa54-5604-45a8-b8b7-ddcb4fd2be46] to /Users/jonnie.diegelman/.julia/compiled/v1.8/Blah/jl_OIpo3S.
ERROR: LoadError: InitError: LoadError: Evaluation into the closed module `AbbreviatedStackTraces` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `AbbreviatedStackTraces` with `eval` during precompilation - don't do this.
Stacktrace:
  [1] include(mod::Module, _path::String)
    @ Base ./Base.jl:419
  [2] include
    @ ~/.julia/packages/AbbreviatedStackTraces/tYd7d/src/AbbreviatedStackTraces.jl:1 [inlined]
  [3] __init__()
    @ AbbreviatedStackTraces ~/.julia/packages/AbbreviatedStackTraces/tYd7d/src/AbbreviatedStackTraces.jl:200
  [4] _include_from_serialized(pkg::Base.PkgId, path::String, depmods::Vector{Any})
    @ Base ./loading.jl:831
  [5] _require_search_from_serialized(pkg::Base.PkgId, sourcepath::String, build_id::UInt64)
    @ Base ./loading.jl:1039
  [6] _require(pkg::Base.PkgId)
    @ Base ./loading.jl:1315
  [7] _require_prelocked(uuidkey::Base.PkgId)
    @ Base ./loading.jl:1200
  [8] macro expansion
    @ ./loading.jl:1180 [inlined]
  [9] macro expansion
    @ ./lock.jl:223 [inlined]
 [10] require(into::Module, mod::Symbol)
    @ Base ./loading.jl:1144
 [11] include
    @ ./Base.jl:419 [inlined]
 [12] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::Nothing)
    @ Base ./loading.jl:1554
 [13] top-level scope
    @ stdin:1
in expression starting at /Users/jonnie.diegelman/.julia/packages/AbbreviatedStackTraces/tYd7d/src/override-vscode.jl:1
during initialization of module AbbreviatedStackTraces
in expression starting at /Users/jonnie.diegelman/Blah/src/Blah.jl:1
in expression starting at stdin:1

`err` only recovers top-level error?

[ Info: Precompiling BioFetch [f8217676-c24a-4825-a874-ba6ce2a4fe08]
ERROR: LoadError: UndefVarError: Format not defined
Stacktrace:
 [1] top-level scope
   @ ~/.julia/dev/BioFetch/src/BioFetch.jl:72
 [2] include
   @ ./Base.jl:389 [inlined]
 [3] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt64}}, source::Nothing)
   @ Base ./loading.jl:1219
 [4] top-level scope
   @ none:1
 [5] eval
   @ ./boot.jl:369 [inlined]
 [6] eval(x::Expr)
   @ Base.MainInclude ./client.jl:456
 [7] top-level scope
   @ none:1
in expression starting at /home/nicho/.julia/dev/BioFetch/src/BioFetch.jl:1
ERROR: Failed to precompile BioFetch [f8217676-c24a-4825-a874-ba6ce2a4fe08] to /home/nicho/.julia/compiled/v1.7/BioFetch/jl_kjdfEq.
 [1-5] ⋮ internal
     @ Base
Use `err` to retrieve the full stack trace.

julia> err
ERROR: Failed to precompile BioFetch [f8217676-c24a-4825-a874-ba6ce2a4fe08] to /home/nicho/.julia/compiled/v1.7/BioFetch/jl_kjdfEq.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, ignore_loaded_modules::Bool)
   @ Base ./loading.jl:1367
 [3] compilecache(pkg::Base.PkgId, path::String)
   @ Base ./loading.jl:1311
 [4] _require(pkg::Base.PkgId)
   @ Base ./loading.jl:1021
 [5] require(uuidkey::Base.PkgId)
   @ Base ./loading.jl:914
 [6] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:901

Improve broadcasted calls

When broadcasting a method, materialize may be shown but not the function directly called that emits the error.

isempty.([:,:])
ERROR: MethodError: no method matching iterate(::Colon)
Closest candidates are:
  iterate(::Union{LinRange, StepRangeLen}) at range.jl:737
  iterate(::Union{LinRange, StepRangeLen}, ::Int64) at range.jl:737
  iterate(::T) where T<:Union{Base.KeySet{<:Any, <:Dict}, Base.ValueIterator{<:Dict}} at dict.jl:693
  ...
Stacktrace:
 [1-5] ⋮ internal
     @ Base, Unknown
   [6] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(isempty), Tuple{Vector{Colon}}})
     @ Base.Broadcast ./broadcast.jl:904
Use `err` to retrieve the full stack trace.

Stacktrace:
 [1] isempty(itr::Function)
   @ Base ./essentials.jl:785
 [2] _broadcast_getindex_evalf
   @ ./broadcast.jl:670 [inlined]
 [3] _broadcast_getindex
   @ ./broadcast.jl:643 [inlined]
 [4] getindex
   @ ./broadcast.jl:597 [inlined]
 [5] copy
   @ ./broadcast.jl:943 [inlined]
 [6] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(isempty), Tuple{Vector{Colon}}})
   @ Base.Broadcast ./broadcast.jl:904
 [7] top-level scope
   @ REPL[279]:1

Trim `error(s::String)` and `top-level scope`?

These two are unrelated, but always seem like useless information. Why not print only [2] here?

julia> f(x) = x>0 ? x : error("negative!");

julia> f(-1)
ERROR: negative!
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] f(x::Int64)
   @ Main ./REPL[16]:1
 [3] top-level scope
   @ REPL[17]:1

ENV["JULIA_STACKTRACE_MINIMAL"] = true doesn't apply for non-interactive errors

Love this project, it'll save me a lot of scrolling. I'm noticing that the minimal display doesn't work on non-interactive cases:

File: a.jl
ENV["JULIA_STACKTRACE_MINIMAL"] = true
using AbbreviatedStackTraces
sum([])
$ julia a.jl
ERROR: LoadError: MethodError: no method matching zero(::Type{Any})
Closest candidates are:
  zero(::Type{Union{Missing, T}}) where T at missing.jl:105
  zero(::Union{Type{P}, P}) where P<:Dates.Period at /usr/share/julia/stdlib/v1.8/Dates/src/periods.jl:53
  zero(::LinearAlgebra.Diagonal) at /usr/share/julia/stdlib/v1.8/LinearAlgebra/src/special.jl:381
  ...
Stacktrace:
  [1-16] ⋮ internal @ Base, Unknown
    [17] sum(a::Vector{Any})
       @ Base ./reducedim.jl:994
    [18] top-level scope
       @ ~/a.jl:5
Use `err` to retrieve the full stack trace.

text/html stacktraces

Stacktraces could use <display> or other handy tags to hide likely irrelevant info when displayed in html environments.

Could use other markup to make the errors a bit easier to read, too.

Make the code clearer about what is being overwritten

I think it would be good to split out all the functions that are overwriting methods in Base/REPL into their own file and all the auxiliary stuff into another file. Then you could enable precompilation on this package but include the file that overwrites method in the __init__ function.

Think about worker processes in interactive context

Currently, workers show all stack frames even if launched at the REPL.

It might be better to abbreviate them, too, so long as it only happens when launched from the REPL and their errors halt all execution, such that the full trace is accessible via err.

However, worker stack traces are currently stripped of module information. That may need to change first.

Externally located packages (e.g. VSCode, in `/.vscode`) aren't skipped

Occasionally a VSCode interpreter frame ends up in a stack trace in its REPL, but it's packages are located in another location, /.vscode/ which is not recognized as skippable.

Could consider a special case for its default directory, since it is the main supported IDE for Julia.

Could also exclude any non-Julia directory starting with /.___ (necessary to ensure dev package frames are included), though going broad could have unintended effects.

Initial stacks omitted even though they contain user code

Maybe I have misunderstood how it is decided which frames are shown and which are omitted, but it seems like sometimes user frames are omitted as well. For a given error triggered in our package Trixi.jl, I get the following stacktrace with AbbreviatedStackTraces.jl:

Stacktrace:
   [1-8] ⋮ internal
       @ Base.Math, Unknown
     [9] macro expansion
       @ ~/hackathon/main-Trixi.jl/src/auxiliary/auxiliary.jl:216 [inlined]
    [10] calc_volume_integral!(du...

while the fully expanded trace for stacks 1-8 gives me

Stacktrace:
  [1] throw_complex_domainerror(f::Symbol, x::Float64)
    @ Base.Math ./math.jl:33
  [2] _log(x::Float64, base::Val{:ℯ}, func::Symbol)
    @ Base.Math ./special/log.jl:301
  [3] log
    @ ./special/log.jl:267 [inlined]
  [4] ln_mean
    @ ~/hackathon/main-Trixi.jl/src/auxiliary/math.jl:62 [inlined]
  [5] flux_ranocha
    @ ~/hackathon/main-Trixi.jl/src/equations/compressible_euler_2d.jl:610 [inlined]
  [6] flux_differencing_kernel!
    @ ~/hackathon/main-Trixi.jl/src/solvers/dgsem_tree/dg_2d.jl:242 [inlined]
  [7] macro expansion
    @ ~/hackathon/main-Trixi.jl/src/solvers/dgsem_tree/dg_2d.jl:318 [inlined]
  [8] macro expansion
    @ ~/.julia/packages/Polyester/JGkMZ/src/closure.jl:420 [inlined]
  [9] macro expansion
    @ ~/hackathon/main-Trixi.jl/src/auxiliary/auxiliary.jl:216 [inlined]
 [10] calc_volume_integral!(du...

In this case, I believe at least stacks 3 through 8 should be shown (to understand which function failed), and at the very least 4 through 8, since they are for user code and not Base or other stdlib code. Is the current way it is displayed intended, i.e., am I seeing a bug or a feature?

P.S.: Thanks for creating this very nice package!

Can't throw a string

Perhaps this is an abuse, but it does normally work:

julia> throw("msg")
ERROR: 
SYSTEM (REPL): showing an error caused an error
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Exception
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:205
Use `err` to retrieve the full stack trace.

julia> err
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Exception
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:205
Stacktrace:
  [1] AbbreviatedStackTraces.ExceptionInfo(error::String, stack::Vector{Base.StackTraces.StackFrame})
    @ AbbreviatedStackTraces ~/.julia/packages/AbbreviatedStackTraces/IBaVh/src/AbbreviatedStackTraces.jl:21

precompile on Julia v1.8

Since Julia v1.8 aims to incrementally precompile modules, importing this package in my startup.jl causes a little Info warning every time I start a REPL that AbbreviatedStackTraces is skipping precompilation. Not a big nuisance but it has made me curious as to why __precompile__(false) is necessary for this amazing package.

"Unknown" modules

Inlined methods and some others don't carry module information with them, so they show up as "Unknown" when abbreviated.

May want to look into how that could be corrected so that "Unknown" rarely or never appears.

Use precompilation?

There's quite a wait time until the first error is displayed on my machine, when using AbbreviatedStackTraces. As a MWE, I'm frozen on the below screen for some seconds

julia> x = y
ERROR:

before getting

julia> x = y
ERROR: UndefVarError: `y` not defined

Is there any way to make this faster using the precompilation tooling?

Think about VS Code's "alt-enter"

When code is executed in VS Code with "ALT-Enter", it shows the full stack trace. "CTRL-Enter" which works by copying code into the REPL, abbreviates it.

Is there a way to make it work for both that doesn't also prevent full errors from being shown in non-interactive contexts?

Could just say that the VSCode REPL is always interactive. But may need to make sure any worker processes spawned by VSCode still show full errors I think?

Odd frames revealed and hidden in included test file containing error

julia> open("test.jl", "w") do f
       write(f, "a() = k; b() = a(); c() = b(); c()")
       end

julia> include("test.jl")
ERROR: LoadError: UndefVarError: k not defined
Stacktrace:
   [1] ⋮ internal
     @ Unknown
   [2] b
     @ /mnt/c/Users/nicho/source/repos/julia/test.jl:1 [inlined]
 [3-4] ⋮ internal
     @ Main, Unknown
   [5] include(fname::String)
     @ Base.MainInclude ./client.jl:448
Use `err` to retrieve the full stack trace.
in expression starting at /mnt/c/Users/nicho/source/repos/julia/test.jl:1

julia> err
1-element ExceptionStack:
LoadError: UndefVarError: k not defined
Stacktrace:
 [1] a
   @ /mnt/c/Users/nicho/source/repos/julia/test.jl:1 [inlined]
 [2] b
   @ /mnt/c/Users/nicho/source/repos/julia/test.jl:1 [inlined]
 [3] c()
   @ Main /mnt/c/Users/nicho/source/repos/julia/test.jl:1
 [4] top-level scope
   @ /mnt/c/Users/nicho/source/repos/julia/test.jl:1
 [5] include(fname::String)
   @ Base.MainInclude ./client.jl:448
 [6] top-level scope
   @ REPL[3]:1
in expression starting at /mnt/c/Users/nicho/source/repos/julia/test.jl:1
  1. Why is b shown but the others not?
  2. Perhaps all frames inside a REPL-originating include should always be shown, since it is code being developed regardless of location?

Idea: Customizable filter

The heuristic may be good for most cases, but someone might want to temporarily change what is shown, without changing whether a package is deved or added, for example. A publicly accessible filter to add exceptions to the heuristic could be useful.

Base submodules not hidden

     [1] throw_complex_domainerror(f::Symbol, x::Float64)
       @ Base.Math .\math.jl:33
     [2] _log(x::Float64, base::Val{:ℯ}, func::Symbol)
       @ Base.Math .\special\log.jl:304
     [3] log
       @ .\special\log.jl:269 [inlined]

`err` not defined

Not sure what's going on here, but err doesn't appear to get populated on error:

❯ julia
[ Info: Precompiling AbbreviatedStackTraces [ac637c84-cc71-43bf-9c33-c1b4316be3d4]
[ Info: Skipping precompilation since __precompile__(false). Importing AbbreviatedStackTraces [ac637c84-cc71-43bf-9c33-c1b4316be3d4].
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.9.2 (2023-07-05)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> sum([])
ERROR: MethodError: no method matching zero(::Type{Any})

Closest candidates are:
  zero(::Type{Union{Missing, T}}) where T
   @ Base missing.jl:105
  zero(::Union{Type{P}, P}) where P<:Dates.Period
   @ Dates ~/.julia/juliaup/julia-1.9.2+0.x64.linux.gnu/share/julia/stdlib/v1.9/Dates/src/periods.jl:51
  zero(::LinearAlgebra.Diagonal)
   @ LinearAlgebra ~/.julia/juliaup/julia-1.9.2+0.x64.linux.gnu/share/julia/stdlib/v1.9/LinearAlgebra/src/special.jl:374
  ...

Stacktrace:
  [1-12] ⋮ internal
       @ Base, Unknown
    [13] sum(a::Vector{Any})
       @ Base ./reducedim.jl:994
Use `err` to retrieve the full stack trace.

julia> err
ERROR: UndefVarError: `err` not defined

Using AbbreviatedStatckTraces v1.1.12 on Julia 1.9.2

Julia Version 1.9.2
Commit e4ee485e909 (2023-07-05 09:39 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 256 × AMD EPYC 7713 64-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, znver3)
  Threads: 1 on 256 virtual cores
Environment:
  JULIA_PKG_USE_CLI_GIT = true

Consider showing Main frames, even if it's a macro evaluation

One oddity about the example in the README (@btime plots(...) is that it never shows the plot() stack frame.

This is because the code is generated by BenchmarkTools but evaluated in Main.

If frames associated with Main were always shown, the first call into Plots would be shown. However, you also end up with three unrecognizable internal frames.

Alternatives:

  • Show only the last excludable Main frame and one lower
  • Show one frame less than a Main frame that would be excluded, but not the Main frame that called it.

However, if this code appeared inside another module, like a package you are developing, that wouldn't be caught by a special case for Main.

It might be possible to generically detect module names that should have this same behavior as Main from the visible frames, and then treat those along with Main in the same way.

Nothing/Int64 conversion error in `show_compact_backtrace` AbbreviatedStackTraces.jl:133 when calling `union!`

ERROR: TypeError: in keyword argument range, expected Union{Nothing, AbstractUnitRange}, got a value of type Vector{UnitRange{Int64}}
SYSTEM (REPL): showing an error caused an error
ERROR: MethodError: Cannot `convert` an object of type Nothing to an object of type Int64
Closest candidates are:
  convert(::Type{T}, ::Base.TwicePrecision) where T<:Number at twiceprecision.jl:250
  convert(::Type{T}, ::AbstractChar) where T<:Number at char.jl:183
  convert(::Type{T}, ::CartesianIndex{1}) where T<:Number at multidimensional.jl:138

Reproduced by:

]dev BioFetch
using BioFetch
fetchseq.(["test"], [1:3]) # only when broadcasting

Info message every time I start julia

I have added AbbreviatedStackTraces.jl to my global environment, and the line using AbbreviatedStackTraces to my startup.jl file. Ever since (I think), Julia 1.9, I get the following @info messages whenever I start a Julia session:

me@dhcp-72-191 folder % julia
[ Info: Precompiling AbbreviatedStackTraces [ac637c84-cc71-43bf-9c33-c1b4316be3d4]
[ Info: Skipping precompilation since __precompile__(false). Importing AbbreviatedStackTraces [ac637c84-cc71-43bf-9c33-c1b4316be3d4].
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.9.1 (2023-06-07)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 

Is this expected, and should I just ignore it? Or should I consider another approach for loading this package?

versioninfo()
julia> versioninfo()
Julia Version 1.9.1
Commit 147bdf428cd (2023-06-07 08:27 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 8 × Apple M1
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 4 virtual cores
Environment:
  JULIA_EDITOR = code

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.