Julia: 在 Base 中包含 ClearStacktrace.jl 需要什么?

创建于 2020-05-25  ·  99评论  ·  资料来源: JuliaLang/julia

标题说明了一切。 我想我找到了一个很好的格式来呈现堆栈跟踪,我认为所有用户都可以从中受益。 它目前在ClearStacktrace.jl 中,并且取决于Crayons.jl的颜色。

我想知道我能做些什么来使这个公关准备就绪。 我不知道 Julia Base 如何处理 REPL 颜色,我可以使用哪些颜色,我如何在没有Crayons情况下访问它们等。我也不知道是否可能存在特定于系统的堆栈的复杂性我忽略的痕迹,仅在 Windows 和 Mac 机器上测试。

基本思想是有三列,函数、模块和签名。 函数和模块一起应该基本上总是水平地适合 REPL,而签名可能很长,因此允许溢出到新行中,同时在调整 REPL 大小时保持完整(与更复杂但易碎的表格布局相比)。 代码路径每条都有一个新行,如果它们太长,也允许溢出。 这使 Atom / VSCode 等中的可点击链接保持完整。

仅供参考,这里是 README 的前后对比:
前:
grafik
后:
grafik

最有用的评论

另一个迭代:我尝试在那里获取变量名,尽管我对所有内部结构都不是很熟悉,但这对我来说感觉非常糟糕。 我重新给模块上色是因为它总体上似乎得到了积极的回应,尽管应该如何分配颜色是有争议的。 但是在颜色上,我觉得一个条目的模块与下一个的函数名称有点冲突。 所以我引入了换行符。 当然让一切变得更长,但我有点喜欢额外的呼吸空间和清晰度

grafik

所有99条评论

拥有这真是太好了。 或者至少可能是一个精简版,它改进了 Base 中默认情况下堆栈跟踪的打印。

我都赞成。 我没有得到的主要内容是签名中的颜色。 他们似乎……随机? 我想不同的颜色是为了更容易挑选出不同的元素,但这有点奇怪。 颜色 == 嵌套深度怎么样? 我认为主要的奇怪之处在于例如Tuple{Symbol,Symbol} ,其中两个Symbol是不同的颜色。

还有一件事我真的很想看:

julia> foo(x::T, y::T) where T = error("whoops")
foo (generic function with 1 method)

julia> function bar()
           a = rand(3, 5)
           b = view(a, :, 2:3)
           c = reinterpret(Float32, b)
           foo(c, c)
       end
bar (generic function with 1 method)

julia> bar()
ERROR: whoops
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] foo(::Base.ReinterpretArray{Float32,2,Float64,SubArray{Float64,2,Array{Float64,2},Tuple{Base.Slice{Base.OneTo{Int64}},UnitRange{Int64}},true}}, ::Base.ReinterpretArray{Float32,2,Float64,SubArray{Float64,2,Array{Float64,2},Tuple{Base.Slice{Base.OneTo{Int64}},UnitRange{Int64}},true}}) at ./REPL[1]:1
 [3] bar() at ./REPL[2]:5
 [4] top-level scope at REPL[3]:1

但由于

julia> m = first(methods(foo))
foo(x::T, y::T) where T in Main at REPL[1]:1

julia> m.sig
Tuple{typeof(foo),T,T} where T

似乎我们应该能够像这样打印条目 2

[2] foo(::T, ::T) where T = Base.ReinterpretArray{Float32,2,Float64,SubArray{Float64,2,Array{Float64,2},Tuple{Base.Slice{Base.OneTo{Int64}},UnitRange{Int64}},true}}

一个小小的评论,但对我来说,目前可能有点太多颜色的“沙拉”。 堆栈帧计数器是蓝色的,签名中的所有不同颜色等等。到目前为止,对于基本颜色,我们只使用了 16 种系统颜色(8 + 8 种亮色),这使得花哨的着色有点困难。

总体来说很好的建议。 也许有几个评论为什么我到目前为止做出颜色选择:

数字是蓝色的,因为它们很重要,所以不应该变灰,但让我觉得它们是白色的,就像它们在用函数名称争夺注意力。

模块在一个循环中使用原色,我认为这非常有用,因为它允许快速过滤相关模块的跟踪。 这与当前的堆栈跟踪格式非常相关。 这个想法是人们应该被迫尽可能少地阅读以找到他们正在寻找的东西。 (到目前为止,我在学术生活中主要从事眼动和注意力研究,所以这些方面对我很重要;))

签名的颜色非常值得商榷。 上面截图中的那些被选择为与深灰色略有不同。 同时,我希望不同的语义组件是可区分的。 这就是为什么所有类型和类型参数(大括号和逗号)都会导致颜色切换的原因。 有三种颜色,这意味着不会有两个颜色相同的邻居。 我发现如果它们都是白色的,那么在巨大的类型签名中识别单个单词是非常困难的。 略有不同的色调有很大帮助,但也会使一切在视觉上更加嘈杂。

由于 16 色套装没有与深灰色仅略有不同的颜色,因此它可能无法包含在 Base 中。 在最近的更新中,我用 ANSI 设置中的三种略有不同的灰色阴影替换了颜色,但我猜即使这样也不会在任何地方得到支持。

哦,堆栈框架颜色和模块颜色以及深灰色和白色都是系统颜色。 这只是我特定的 VSCode 主题,使它们像您在此处看到的一样。

这将是很棒的。

在扫描参数类型时,通常很难弄清楚一个在哪里停止,另一个从哪里开始。 对顶层进行不同的着色在这里可能会很有帮助,甚至可能对参数进行编号:

 [3] (_1::DataFrames.var"#fun##309#"{ ...更轻... }, _2::NamedTuple{ ...更轻... }, _3::Int64})

我们应该能够显示参数名称,就像我们在打印methods(f)所做的那样。

这个怎么样? 我用深灰色替换了签名颜色,但::是白色的,所以它在参数类型开始的地方很突出。 对位置 11 的类型怪物特别有用
grafik

我喜欢。 使用参数名称会更好。

太糟糕了,“函数 - 模块 - 参数”的顺序对于布局来说效果很好,但在语义上并没有真正意义。 不过我没有解决办法; 显然,最好让函数先出现。 也许模块可以在文件位置之前进入下一行? 毕竟它是位置的一部分。 那么也许我们也不需要标题。

我认为我们也可以将数字放在普通文本中,将函数名称放在粗体和/或白色中。

代码路径末尾的文件名(也可能是行号)是否也能获得自己的浅色?

也许模块可以在文件位置之前进入下一行? 毕竟它是位置的一部分。 那么也许我们也不需要标题。

我会根据这些建议尝试一些事情。

代码路径末尾的文件名(也可能是行号)是否也能获得自己的浅色?

它在技术上当然可以 ;) 它总是在更好的可见性和吸引注意力的噪音之间进行权衡。

为什么不先编写模块,因为它们是函数全名的一部分? 也许使用颜色,只需编写Core.eval等就足够清楚了,或者它们仍然可以作为列对齐。 (或者也许你试过这个,它看起来很糟糕。)

真的很疯狂的想法:如果打印参数类型会占用多于一行,请以折叠形式打印签名,然后使用REPL.TerminalMenus以允许查看者展开它。 就像是:

julia> run_command(args...)
    Function    Arguments              Location
[1] f           (x::Int, y::Float64)   MyModule1, /path/to/file1.jl: 15
[2] g          +(...)                  MyModule2, /path/to/file2.jl: 64
...

julia> lasttrace()
# presents the above in menu form, allowing user to expand line 2

相关:#35915(我计划用它来创建折叠树菜单,https://github.com/JuliaCollections/FoldingTrees.jl)。

按以下顺序重新排列的代码路径看起来如何: LineNumber Filename Path
然后你的眼睛有一个稳定的位置来寻找行号和文件名,不需要额外的颜色(我似乎总是在寻找隐藏在细节中的文件名和行号,你能告诉我吗?)
对于交互式 REPL 工作,我喜欢上面折叠的想法:)

为什么不先写模块,因为它们是函数全名的一部分

是的,我有点喜欢这个想法,我想我一开始没有颜色,效果不太好,但像这样它实际上非常可读。 接下来我将尝试不使用列,尽管列总是很好,因为它们引导您的眼睛。

grafik

不确定; 函数名称是比模块重要得多的信息。 至少对我来说,最重要的信息绝对是函数名、文件名和行号。 同样对于脚本,左列将有很多Main或空白,这对于该用例来说并不理想。

我认为当我阅读堆栈跟踪时,我主要是在我的代码中寻找最后一个调用,然后再转到基础/包代码,因为通常错误在我的代码中。 所以在那种情况下,模块非常重要,函数调用不是我首先要扫描的。

这个怎么样:

[1]  get_ticklabels   ::AbstractPlotting.Automatic, ::Int64
     in MakieLayout at ~/.julia/packages/MakieLayout/COfBu/src/lineaxis.jl:372

模块名称仍会对齐,因此它们很容易扫描。

我实际上只是尝试了一些接近的东西。 这次我给函数名本身着色,所以它们仍然是最显着的,但以它们的颜色携带模块信息。 所以仍然有一个明显的分组,但对所有模块名称的关注较少。

grafik

我第一次看到我可能会疯狂地试图弄清楚颜色的含义 :joy: 如果每个模块都有颜色,那么将颜色应用于模块名称似乎更好。

我喜欢模块名称,它们在这张最新图片中有点迷失。

如果它们在底部,也许使它们具有相同的明亮颜色会连接事物? (并明确你跨越模块边界的位置。)而且,也许,如果模块名称出现在路径中,它可以简单地在那里突出显示 - 这也会将彩色名称从函数所在的左边缘移开。

为了获得一些灵感,我发布了一些上次调整堆栈跟踪格式时的图像。

bild

bild

通常,确切的包不像代码的性质那么令人感兴趣:它是核心 julia、我正在使用的库、我正在开发的库还是脚本? 我们可以有四种颜色:core/base/dev/stdlib、包、包当前]dev ed,以及所有其他的(包括脚本/REPL)。 其中一些区别非常随意,分类也有点脆弱,但是基于此着色的方法(至少对我而言)可以最大化信息,而无需显示任何额外的文本,并保留一组小而易于记忆的颜色。

对我来说,颜色更多地是关于边界变化,一个模块的代码开始而另一端结束。 这就是为什么我可能不会给它们赋予内在的意义。 另一方面,这可能令人困惑。

我试图简化更多,并再次删除列,因为没有模块列它们不再那么有用了。 然后首先我只按模块着色行号,但这仍然使文件名不那么明显,许多评论说这很重要。 所以我也用模块颜色给它上色。 模块名称本身没有着色,因为它太接近函数名称并且太嘈杂。

这是带有数字和文件名的版本:

grafik

这里没有彩色文件名

grafik

您也可以尝试为完整的文件路径着色吗?

一些想法...
文件名和行号在一致的位置,用双空格将它们分开。
堆栈级别颜色和模块颜色相互匹配,以直观地配对相关行。
文件名、行号和路径的色调与参数类型略有不同,以区分清晰。
stacktrace
[这个例子中的颜色是任意的,更多的是考虑它们的位置之间的关系。
示例中缺少堆栈级别和最后一项上缩短的参数类型列表是因为我手动输入了示例。]

用于生成上述示例的代码,以防有人想使用它:

function main()

    errors = [
              ("1", "get_ticklabels", ("AbstractPlotting.Automatic", "Int64"), "372", "lineaxis.jl", "MakieLayout", "~/.julia/packages/MakieLayout/COfBu/src")
              ("2", "get_ticklabels", ("AbstractPlotting.Automatic", "Int64"), "351", "lineaxis.jl", "MakieLayout", "~/.julia/packages/MakieLayout/COfBu/src")
              ("3", "#105", ("AbstractPlotting.Automatic",), "152", "lineaxis.jl", "MakieLayout", "~/.julia/packages/MakieLayout/COfBu/src")
              ("8", "OnUpdate", ("Tuple{Float32,Float32}",), "218", "Observables.jl", "Observables", "~/.julia/packages/Observables/0wrF6/src")
              ("9", "#setindex!#5", ("Observables.var\"#6#8\"",), "138", "Observables.jl", "Observables", "~/.julia/packages/Observables/0wrF6/src")
              ("10", "setindex!", ("Observables.Observable{Any}",), "126", "Observables.jl", "Observables", "~/.julia/packages/Observables/0wrF6/src")
              ("11", "#LineAxis#95", ("Base.Iterators.Pairs{Symbol,Observables.Observable,NTuple{28,Symbol},NamedTuple{(:endpoints, :limits, :flipped, :ticklabelrotation, :ticklabelalign, :lables
ize, :labelpadding, :ticklabelpad, :labelvisible, :label, :labelfont, :ticklabelfont, :ticklabelcolor}",), "270", "lineaxis.jl", "MakieLayout", "~/.julia/packages/MakieLayout/COfBu/src/lobjects")
    ]

    println()
    for (idx, err) in enumerate(errors)
        # Module color
        mc = idx <= 3 ? :light_red : (idx >= 7 ? :light_red : :light_yellow)
        # Path color
        pc = :blue
        printstyled("[", color=mc)
        printstyled("$(err[1])", color=mc)     # errorno
        printstyled("]  ", color=mc)
        printstyled("$(err[5])", color=pc)     # filename
        printstyled(":", color=pc)             # colon
        printstyled("$(err[4])", color=pc)     # lineno
        printstyled("  $(err[7])", color=pc)   # path
        println()
        printstyled("$(err[6]) ", color=mc)    # module
        printstyled("$(err[2]) ", color=:bold) # function
        printstyled("(", color=:light_blue)    # param types
        for t in err[3]
            printstyled("::", color=:white)
            printstyled("$t", color=:light_blue)
        end
        printstyled(")", color=:light_blue)
        println()
    end
end

这样做的问题是,这不会使 Atom / VSCode 等中的链接可点击。这是我经常使用的东西,我相信其他人也这样做。 事实上,我什至明确地扩展了基本路径以使其可点击。 这当然打印更多。 但我认为它增加了实用性。 我知道有一些方法可以使用一些快捷方式在 REPL 中按编号跳转到堆栈跟踪条目,但这远不如我认为仅单击链接那么直观。

借此机会统一使用日志系统打印行信息的方式可能是有意义的,例如:

bild

另外,请注意日志系统确实收缩了 homedir

julia> include("foo.jl")
┌ Warning: foo
└ @ Main ~/julia/foo.jl:1

我认为这里的提案有两个核心思想:

  • 将行信息放在与签名不同的行上(也许用某种颜色分隔它以使其更容易找到)。
  • 显示模块。

因此,这里对这两个想法进行了稍微保守的尝试:

bild

添加了变量名称的版本,仅在模块名称上着色(但与@info打印路径的方式相匹配):

Screenshot 2020-05-28 at 15 55 56

这个没有很长的类型签名,但也许有这样的变量名(如果可能?)可以更容易地发现每个参数的最外层类型。

如果有三个可用的中性级别(如粗体/正常/灰色),那么比签名更轻地打印文件路径似乎(IMO)是阻止事情一起运行的好方法。 (这也是@info所做的。)

调整@timotaularson的代码

让
 printstyled("\njulia> ", color=:green)
 println("f()")
 printstyled("""ERROR: DimensionMismatch("A 有维度 (1,2) 但 B 有维度 (3,4)")""", color=:light_red)
 println("\n堆栈跟踪:")
 for (idx, err) in enumerate(errors)
 mc = idx <= 3 ? :blue : (idx >= 7 ? :blue : :yellow) # 模块颜色
 printstyled("[$(err[1])] ", color=:normal, bold=true) # errorno
 printstyled(err[2], color=:normal, bold=true) # 函数
 printstyled("(", color=:normal) # 参数类型
 for (i,t) in enumerate(err[3])
 i != 1 && printstyled(", ", color=:normal)
 printstyled(rand('a':'z')^2, color=:light_black)
 打印样式(“::”,颜色=:正常)
 printstyled("$t", color=:normal)
 结尾
 打印样式(“)”,颜色=:正常)
 打印()
 printstyled(" @ ", color=:light_black)
 printstyled(err[6], color=mc) # 模块
 printstyled(" $(err[7])/$(err[5]):$(err[4])", color=:light_black) # 路径
 打印()
 结尾
结尾

我认为这里的提案有两个核心思想:

* Have the line info on a separate line from the signature (and perhaps delimited it with some color to make it easier to find).

* Show the module.

因此,这里对这两个想法进行了稍微保守的尝试:

我喜欢这个。 我认为这个词是“杀死你的宝贝”,我的宝贝可能是颜色。 但是我可以看出低调的东西如何更适合如此基本的东西。 我稍微改变了它,使模块名称和函数名称对齐,这会创建一条几乎像列一样的垂直对比线。 这应该有助于找到相关信息。 虽然我仍然认为我不会把字体放在白色的,因为它们太乱了。 如果我们有变量名,也许那些白色的会很好看。

grafik

我喜欢这个。 我认为这个词是“杀死你的宝贝”,我的宝贝可能是颜色。

为了让您知道我知道您的情况, https://github.com/JuliaLang/julia/pull/18228。 这是一个bikeshed很好玩的话题,每个人都有一桶油漆,呵呵。 正如你所看到的,那个公关也很雄心勃勃地开始,但慢慢变得越来越保守呵呵。

对我来说,最后一个提议绝对是对现状的改进。 我在想两件事:

  • 如果可能,最好为您的眼睛提供某种“挂钩”来获取线路信息,因为当签名很长时,它往往会与签名混合在一起。
  • 当堆栈帧数量超过 10 个时,我们可能应该对齐堆栈帧编号:
    [ 8] [ 9] [10] [11]
    等等。这将使@也排队。

我喜欢它,我想我们正在取得进展。 明智地使用颜色总是好的,因为这样可以减少自行车棚的表面积,并且降低了在某人的终端上无法读取颜色的风险。

把东西分开是好的,但不幸的是语法f (...)是明确禁止的,所以我认为我们需要删除空格或删除括号。

最近的样本通常看起来不错,但我的想法是:

如果可能,最好为您的眼睛提供某种“挂钩”来获取线路信息,因为当签名很长时,它往往会与签名混合在一起。

我希望钩子是不同的颜色或(最好)亮度。

也许您可以为模块执行颜色循环,但仅将其应用于堆栈级别编号两侧的 [],因此如果由于某种原因您看不到颜色,则不会丢失太多颜色。

也许您可以为模块执行颜色循环,但仅将其应用于 []

如果只是括号并且它们处于对比区域,甚至很难正确看到颜色,所以我认为这不太好。

语法 f (...) 被明确禁止

我认为即使没有空间它也能很好地工作,因为对比度差异。

如果可能,最好为您的眼睛提供某种“挂钩”以获取线路信息

我同意,我认为将行号保留为灰色但将它们加粗很有效,如果您寻找它们,这会使它们稍微突出一些,但在我看来,将它们设置为白色的下一步太嘈杂了。

我们可能应该对齐堆栈帧编号

我像在你的例子中那样用括号内的空格尝试过,但发现这看起来有点奇怪,所以现在我正好对齐括号内的数字。 我认为这很好用。

这是包含所有这些想法的最新版本:

grafik

作为奖励,这是使用(随机)变量名称时的外观。 我再次使用粗体灰色,因为所有这些变量名称不应该引起您的注意,但是如果您查找它们应该有点可辨别
grafik

我也喜欢这里的发展方向。 我只想对模块名称的某种突出显示进行投票。 我实际上非常喜欢相同模块以相同方式着色并且它在颜色中循环的样式(如果您认为两条堆栈跟踪线相邻作为它们模块之间的图形边缘,则此处存在图形颜色问题)。 然而,不幸的是,这种颜色的含义并不明显。 也许用一种颜色为所有模块名称着色?

这种对齐方式对我来说看起来不错。

我仍然认为让路径与签名更清晰地区别将有助于分解 - 3 个重要性级别,名称/签名/路径。 记录宏@info等比其他行打印得更轻。

拥有变量名会非常好。 可能会投票认为它们不如签名信息重要吗?

将模块名称排列在左侧确实可以帮助您扫描它们,尽管我很难过看到颜色消失。

我的眼睛似乎知道在哪里可以找到关于这个的东西:)
模块之间的空行会占用太多的垂直空间吗?

用 2 种不同的颜色为行着色,以便交替行具有相同的颜色 - 正如在表格中经常做的那样,可能有助于提高可读性。

模块名称旁边的@ 颜色循环而不是模块名称本身突出(因为@ 是一个非常大的字符)而不会与突出显示的函数名称竞争太多。

我经常希望参数名称,因为它们可以帮助您找到正确的参数类型,而无需计算它们。

路径(也许是它旁边的模块名称)与类型的亮度不同吗? 也许只是匹配参数名称? (或者,如果你按照 mcabbott 的建议,让名称比类型更暗,那么所有的灯光都会一起昏暗)

您可以明确反映日志记录使用的内容,但最好使用不同的颜色:

for i in 1:3
    printstyled("┌[", color=:magenta, bold=true); print(i); printstyled("] ", color=:magenta, bold=true)
    printstyled("get_ticklabels", bold=true); print("("); printstyled("style", color=:light_black); print("::AbstractPlotting.Automatic, "); printstyled("n", color=:light_black); print("::Int64")
    i!=2 ? println(")") : begin print(", "); printstyled("xs", color=:light_black);  print("::Array{Float64,2}, ");  printstyled("ys", color=:light_black);  print("::Array{Float64,1}, ");  printstyled("yes", color=:light_black);  print("::Bool, ");  printstyled("no", color=:light_black);  println("::Bool)") end
    printstyled("└ @ ", color=:magenta, bold=true); printstyled("MakieLayout", color=:magenta); printstyled(" ~/.julia/packages/MakieLayout/COfBu/src/lineaxis.jl:372", color=:light_black); println();
end
<strong i="6">@error</strong> join([join(rand('a':'z', rand(1:9))) for _ in 1:25]," ") pi

编辑:现在有一条较长的环绕线和一张图片:
Screenshot 2020-05-28 at 20 21 48

您可以明确反映日志记录使用的内容

我不太喜欢这一点的一点是,如果您调整窗口/REPL 的大小(例如,如果您想为更长的行腾出空间,那么仅因特定 REPL 宽度而出现的换行符就不能很好地传输) ) 或将文本复制/粘贴到不同宽度的窗口中

是的,我不建议明确打破界限以使标记连续。 事实上,让包裹线突破可能是一件好事,因此看起来不同。 主要是考虑如何将颜色与函数名称联系起来,以及如何使它不那么突兀,如果它是边框的一部分而不是看起来像最重要的标题。

我必须说我喜欢这种颜色,但我可以理解对它保守的偏好。

然而,我想把我的支持抛在后面

通常,确切的包不像代码的性质那么令人感兴趣:它是核心 julia、我正在使用的库、我正在开发的库还是脚本? 我们可以有四种颜色:core/base/dev/stdlib、包、包当前]dev ed,以及所有其他的(包括脚本/REPL)。 [...]

由于我不是在基础上进行黑客攻击,而且很少在包上进行黑客攻击(我认为大多数人都这样做),因此需要在我的脚本中修复 90% 的错误,在包中修复 9%,在基础中修复 1%。 如果我在调用函数时犯了错误,我不需要在这里确切地知道错误是抛出的,因为无论如何我都不会去那里修复它,我需要修复我的代码。

所以我很感激一些视觉助手来看看我在哪里留下我的代码(也许还有我离开包代码的地方,进入基础),因为在大多数情况下,我现在可以安全地忽略之后的任何事情。 如果不是通过颜色,也许用--------------------------------------------或其他什么? 应该只有 2-3 个。

如果模块有颜色,那么也许 Base/Core 应该被排除在外并且没有颜色。

我实际上非常喜欢相同模块以相同方式着色并在颜色之间循环的样式

我也很好。 如果我们要使用多种颜色,我认为应该使用它们。 它还有助于在不占用太多垂直空间的情况下挑选出用户和包代码之间的边界。

如果模块有颜色,那么也许 Base/Core 应该被排除在外并且没有颜色。

是的,Base 和 Core 可以总是深灰色或其他颜色,为其他人留下更多颜色:)

如果这放弃了 16 种颜色的完美工作,那么将它们设为模块名称的散列可能会很好,以便您记住其中的一些。

或者只有两种颜色,一种用于基础/核心,一种用于外部模块?

我认为循环颜色应该不是什么大问题,因为我当前的版本有 6 个非灰度选项:

crayon"blue",
crayon"yellow",
crayon"red",
crayon"green",
crayon"cyan",
crayon"magenta",

我猜也有浅色变体,但我在 VSCode(材料)中的配色方案将它们设置为与深色兄弟姐妹相同,所以我认为这可能发生在某些方案中。 但是堆栈跟踪通过 6 个以上不同的非基础或非标准库模块的可能性有多大? 当然,包使用来自许多模块的代码,但在一个特定的堆栈中不应该有那么多。 至少,即使存在颜色冲突,在破译堆栈跟踪时也不应该造成大问题。

那么让它们成为模块名称的散列可能会很好,这样你就会记住其中的一些

这实际上是一种辉煌。

很高兴看到有人在做这方面的工作。
我很想看看函数名称的正确对齐方式:

 [1] get_ticklabels(code_lowered::...
 [2] get_ticklabels(real::AbstractPlotting
 [3] #105(mtime::
 [4] OnUpdate(vecormat::
 [5] #setindex!#5(atexti::

对比

 [1] get_ticklabels(code_lowered::...
 [2] get_ticklabels(real::AbstractPlotting
 [3]           #105(mtime::
 [4]       OnUpdate(vecormat::
 [5]   #setindex!#5(atexti::
 [6]      setindex!(mapslices

眼睛可能更容易捕捉到函数参数的开始位置,并在不浪费太多空间的情况下帮助解析函数调用链。 它仍然需要颜色支持,否则位置信息和参数会淹没一切。

那么让它们成为模块名称的散列可能会很好,这样你就会记住其中的一些

这实际上是一种辉煌。

哦,你好,深青色,我的老朋友……

那么让它们成为模块名称的散列可能会很好,这样你就会记住其中的一些

我曾经让 emacs 对 IRC 昵称做同样的事情。 效果不太好,因为我的一些朋友被分配了相同的颜色,这比任何事情都更令人困惑,所以我最终为我的朋友硬编码颜色。 我不建议走那条路,不管它看起来多么酷。 为每种代码类型(例如 Julia、包、开发包、用户)减少一组颜色似乎更有用。

我找到了一个编辑器配色方案,它可以做到这一点,它非常有用——所有可能是蓝色的变量都是不同的绿色和蓝色阴影,字符串和关键字等不同。 也许理想的情况是像您建议的那样在广泛的类中是这样的(例如,红紫色的标准库,以绿蓝色下载,以橙黄色开发,以灰色为基础)。 或者这可能是太多的工作!

另一个迭代:我尝试在那里获取变量名,尽管我对所有内部结构都不是很熟悉,但这对我来说感觉非常糟糕。 我重新给模块上色是因为它总体上似乎得到了积极的回应,尽管应该如何分配颜色是有争议的。 但是在颜色上,我觉得一个条目的模块与下一个的函数名称有点冲突。 所以我引入了换行符。 当然让一切变得更长,但我有点喜欢额外的呼吸空间和清晰度

grafik

我喜欢你的最后一个样本,它非常清晰易读:)

下面只是一个实验,将模块着色应用于“@”而不是模块名称,以减少您提到的与函数名称的冲突,并尝试突出显示类型,以便在不必引入空白的情况下更容易区分路径线。

stacktrace2

@jkrumbiegel太美了。 我的生活中需要这个。

我喜欢那些柔和的蓝调

@jkrumbiegel太好了,我不确定是否需要 @ 符号,没有它它可能看起来更干净。 如果你想解释这些信息是什么,你不妨像杰夫建议的那样写:
in MakieLayout at ~/.julia/packages/MakieLayout/COfBu/src/lineaxis.jl:372

@jkrumbiegel看起来很棒! 有没有办法只突出显示文件名(而不是完整路径)和行号? 也许是稍微亮一点的灰色?

迷人的! 我实际上真的很喜欢换行符——它们在视觉上确实有帮助,而且我们的堆栈跟踪往往很长,无论如何我都必须滚动,我宁愿它清楚一点也不愿减少一点滚动。

突出显示的::非常棒。 如果我必须绘制一条曲线,显示参数列表中每个字符的信息内容与字符位置的关系,则::正好标记了该曲线的局部最大值。 我知道向左看名称,向右看类型中最重要的部分,之后信息内容只会下降。

我不同意这种评论:突出显示应该强调重要的事情,以便眼睛知道要阅读什么,而 :: 绝对不是我应该阅读的重要内容。 就目前而言,白色比大胆的深蓝色更引人注目。 通过将参数名称设为白色(也许没有命名参数的情况除外,在这种情况下::也可以使用白色来分隔参数),可以更清楚地区分参数。 行号也是如此,我宁愿强调文件名而不是行号。

有颜色的包名冒着掩盖最重要的东西的风险,函数名,但用粗体和换行符确实限制了这种风险,做得好!

在我把它们变成白色之前,我想了很多。 当然,参数名称和类型是实际信息,因此您可能认为应该突出显示它们。 但是我在强调它们时的强烈印象是它们引起了你的注意。 但是阅读每个名称和类型并不重要。 您应该能够在特定功能中找到您正在寻找的那些。 我如何看待读取堆栈跟踪的步骤:

  1. 获取总体概览
  2. 哪个模块中的哪个函数出错了?
  3. 哪些其他函数从哪些其他模块调用了这个函数?
  4. 我自己的代码和基础代码或其他包代码之间是否存在临界边界? 它在哪里?
  5. 那个边界是什么功能?
  6. 使用了哪些类型/参数? 一个论点在哪里结束,下一个论点从哪里开始? 现在对于长参数类型来说这尤其困难。
  7. 这能解释错误吗?
  8. 如果这没有帮助,请仔细梳理所有内容

所以类型/参数信息在我看来只有在定位和理解一般结构后才使用。 关于突出显示要理解的一件事是,它不一定会使查找事物变得更容易,只有当突出显示相对稀疏时。 所以我认为 :: highlight 不会妨碍并吸引你的注意力,直到你开始寻找变量/类型信息。 在这一步,它让你的眼睛有钩子跳到,不多也不少。 我觉得这很有效率。

作为旁注,并非每个参数都有名称,因此突出显示变量名称并不总是能给你很好的分离。 我认为 :: 总是在那里。

这似乎是一个很好的列表,我的主要抱怨是第 6 点,找到长类型签名中的差距。 打印::超亮确实有帮助,尽管我同意这有点奇怪。 打印参数名称(或者可能是一些_1占位符,如果没有)会有所帮助。 也许正常打印最外面的类型,然后将其所有参数都打印为灰色,会有很大帮助吗?

实际可用的高亮级别有多少? :white不会在浅色背景中脱颖而出,事实上我认为我们可能仅限于正常、粗体和:light_black (加上颜色)。 现在函数名和路径是粗体的。 在@error等中,路径是 light_black,这看起来很棒。

我喜欢使用颜色来突出模块。 在上面的一些示例中,它比其他文本更耀眼,但对于简单的颜色是否如此? 在几个不同的主题中,这里的“模块”相对静音(并且::Array, ::Adjoint, ::Int很明显是顶级签名):

    printstyled("\nfunction", bold=true); print("(x::Array"); printstyled("{Float64,1}", color=:light_black); print(", y::Adjoint"); printstyled("{Float64,2,Array{Float64,2}}", color=:light_black); println(", z::Int64)")
    printstyled(" @ ", color=:light_black); printstyled("Module", color=:blue); printstyled(" ~/.julia/dev/Package/src/Package.jl:33 \n", color=:light_black)
end

Screenshot 2020-05-31 at 16 14 35

另一个迭代:我尝试在那里获取变量名,尽管我对所有内部结构都不是很熟悉,但这对我来说感觉非常糟糕。 我重新给模块上色是因为它总体上似乎得到了积极的回应,尽管应该如何分配颜色是有争议的。 但是在颜色上,我觉得一个条目的模块与下一个的函数名称有点冲突。 所以我引入了换行符。 当然让一切变得更长,但我有点喜欢额外的呼吸空间和清晰度

grafik

可能有点题外话,但既然我们有了这个,我们可以为methodsmethodswith的输出提供一个更漂亮的show methodswith吗? 这也是一种痛苦。

此外,模块的颜色可以是暗色,比如不是完全的黄色,而是灰黄色。 或者,我们可以将这些颜色配置startup.jl吗?

@jkrumbiegel看起来很棒! 有没有办法只突出显示文件名(而不是完整路径)和行号? 也许是稍微亮一点的灰色?

它可以: https :

我已经不再使用 Crayon.jl,现在我实际上不再使用复杂的颜色了。 也有助于缩短包的加载时间。 我找到了一种方法来增强文件名和行号的可见性,而不会通过深灰色下划线在视觉上变得压倒一切。 这看起来也很合理,因为我们习惯于路径/链接带有下划线。 白色或其他突出显示在那里太强了,粗体太弱了。

此外,我已经切换到浅色作为循环仪中的第一种颜色,我本来应该这样做的,但它们在我的主题中看起来是一样的,所以我从未注意到。 对于几乎看不到深蓝色的主题,这应该会更好(尽管这是主题的错)。

我已经在ClearStacktrace.jl将此样式注册为 0.2 版,因此我们可以多尝试一下。

两个例子:

example 1

example 2

这真是一件很棒的工作。
您的参数名称更亮,类型更暗。 与类型更浅、名称更深的情况相比,这种方式看起来更好/读起来更好吗?

是的,因为类型通常更长,所以让它们更轻并没有多大帮助。

随意的想法:

  • 也许同一模块中的堆栈跟踪条目组之间的水平规则? 也许太忙了
  • 在堆栈跟踪的顶部也可能很好,以将其与错误消息清楚地分开

所有这些都比我们现在拥有的要好得多......

我已经不再使用 Crayon.jl,现在我实际上不再使用复杂的颜色了。 也有助于缩短包的加载时间。

它是否导致了显着的加载时间? 对我来说它自己加载得很快

julia> <strong i="8">@time</strong> using Crayons
  0.014410 seconds (22.60 k allocations: 2.274 MiB)

这个版本很棒,让我们把它放在 Base 中。

同意:让我们只做最后一个版本。

感谢您在这里完成所有工作, @jkrumbiegel 。 很高兴有一个我们可以尝试的版本......

和叉子:我想我认为这有点与rand(5) .* rand(7)加上错误占用 35 行有关? 所以我做了https://github.com/mcabbott/ClearStacktrace.jl/tree/milder来试用。 (加上上面讨论的颜色问题等。)这几乎是https://github.com/JuliaLang/julia/issues/36026#issuecomment -635294818 有更多颜色。

请注意,在当前的堆栈跟踪中,该示例中的 8-11 打印帧未显示(它们是 REPL 的一部分,并且将在每个 REPL 堆栈跟踪中)。

确实,这已经有所改善,这很棒。 但它仍然从 8 行(仅针对堆栈跟踪)到 20 行(ClearStacktrace 0.2)。 在它有多漂亮和不失去你的位置之间有一些权衡。

路径也在 Base 中打印得更紧凑, ./broadcast.jl:495而不是//Applications/Julia-1.5.app/Contents/Resources/julia/bin/../share/julia/base/broadcast.jl:495 ,这也将减少对空行的需求。

基本路径被有意扩展以使其可点击。 您可以在 ClearStacktrace 中禁用它。 对于不喜欢换行符的人,我还可以将换行符设为可选。 可能只是一个环境变量。

我想我一定错过了复制功能的一部分,该部分剪辑掉了永远不会改变的最后几帧

我已经不再使用 Crayon.jl,现在我实际上不再使用复杂的颜色了。 也有助于缩短包的加载时间。 我找到了一种方法来增强文件名和行号的可见性,而不会通过深灰色下划线在视觉上变得压倒一切。 这看起来也很合理,因为我们习惯于路径/链接带有下划线。 白色或其他突出显示在那里太强了,粗体太弱了。

此外,我已经切换到浅色作为循环仪中的第一种颜色,我本来应该这样做的,但它们在我的主题中看起来是一样的,所以我从未注意到。 对于几乎看不到深蓝色的主题,这应该会更好(尽管这是主题的错)。

我已经在ClearStacktrace.jl将此样式注册为 0.2 版,因此我们可以多尝试一下。

两个例子:

example 1

example 2

很好奇为什么/中有一个额外的//Applications/Julia-1.4.app/

可能是拆分和重新加入路径的错误

我已经不再使用 Crayon.jl,现在我实际上不再使用复杂的颜色了。 也有助于缩短包的加载时间。

它是否导致了显着的加载时间? 对我来说它自己加载得很快

julia> <strong i="9">@time</strong> using Crayons

  0.014410 seconds (22.60 k allocations: 2.274 MiB)

不,我主要是删除了它,因为我不会在 base 中使用它 :) 加载时间只是一个猜测

我想如果我们有很多堆栈跟踪帧,如https://github.com/JuliaLang/julia/issues/36026#issuecomment -636912686 所示,可能会有太多的空行?

不是为了破坏讨论(最后一个版本很棒并且有很大的改进),而是关于太多换行符的话题,问题是在终端工作时,对我来说打印堆栈跟踪“反转”似乎要好得多(如我最初在 https://github.com/JuliaLang/julia/pull/18228) 中提出:

...
[3] frame
[2] frame
[1] frame
Error: Some error happened
blah blah

最重要的信息是错误消息本身和堆栈顶部(更接近错误)的帧,并按此顺序打印,无需滚动即可始终可见。 现在我经常需要向上滚动才能看到错误消息,而不仅仅是堆栈跟踪的尾部。

但是,在从终端复制粘贴的网站上读取堆栈跟踪时,您需要相反的顺序,因为您从上到下滚动,而不是像在终端中那样从下到上滚动......这两种情况的良好设计。

但是,在从终端复制粘贴的网站上读取堆栈跟踪时,您需要相反的顺序,因为您从上到下滚动,而不是像在终端中那样从下到上滚动......这两种情况的良好设计。

我实际上在ClearStacktrace.jl中有一段代码,让我可以重新打印最后一个堆栈跟踪。 我曾设想过在某些字符最大值处切断超长类型,并在需要整个信息时能够完整重印。 但是您的用例也会很有趣。 我可以想象一个reprint(inverted = true)甚至reprint(html = true)它将打印一个 html 版本,该版本将保留颜色以粘贴到网站中。

另外,我同意给定滚动方向,默认情况下反转整个事情是有意义的。

ipython以相反的顺序打印帧,尽管不必滚动,但我总是发现它莫名其妙地令人困惑。 也许这只是由于我之前使用 gdb 和其他最内层框架位于顶部的系统的经验,或者其他人也有这种感觉?

说到 gdb,他们有一个合理的解决方案,可以用他们的寻呼机解决很长的跟踪:“按 Enter 以获得更多帧”。

顺便说一句,我喜欢https://github.com/JuliaLang/julia/issues/36026#issuecomment -636912686 中最新的视觉设计,如果我们合并它会非常高兴。 更改帧顺序或添加交互功能似乎是单独的问题。

关于文件名,我希望我们最终可以使用终端超链接 OSC 序列(是的,终端中的超链接在某种程度上得到了广泛的支持! )并且有一种方法让用户的编辑器可以选择它。

说到寻找“最内层框架”,我在工作过程中使用了足够多的语言,以至于我永远不记得是否应该查看我的代码的堆栈跟踪的顶部或底部的任何特定语言。 所以我最终通过查看文件名进行扫描,直到我看到一个我认识的。 此处显示的下划线会有所帮助,因此这是一个明显的改进。 但是我仍然想知道是否有一个好方法可以告诉我是应该查看顶部还是底部。 原则上,在一端打印YOUR CODE HERE在另一端打印OTHER CODE HERE会帮助我,但它看起来并不优雅。

我在这里做了一个 PR 到 Base https://github.com/JuliaLang/julia/pull/36134
据我所知,它可以工作,但我需要一些帮助才能为合并做好准备

有没有办法省略类型参数? 我们经常看到的问题是 DiffEq、ForwardDiff 等中类型参数的数量会让事情变得……令人生畏。 如果默认情况下它只是说Dual ,除了由于类型参数而分派到其他方法的情况,那么我认为你会减少我读到的大多数堆栈跟踪中 90% 的噪音(以及在其他情况下, @timholy的建议确实是必需的,因为它通常是关于创建类型或匹配类型参数)

如果它们对应于一些现有的类型别名,它们现在会自动消失(#36107)。 否则,它们表明可能存在编译性能瓶颈——所以可能值得研究?

现在已经完成了。

对于某些人来说,但大多数人只是在打印出需要 3 页打印纸的类型时感到困惑,因此它可能应该是可选的。 我将打开另一个问题来讨论这个问题。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

dpsanders picture dpsanders  ·  3评论

i-apellaniz picture i-apellaniz  ·  3评论

TotalVerb picture TotalVerb  ·  3评论

Keno picture Keno  ·  3评论

yurivish picture yurivish  ·  3评论