简体   繁体   English

Elixir 堆栈跟踪是否包括每个输入的 function?

[英]Do Elixir stacktraces include every entered function?

I am working on an issue in Postgrex , an Elixir Postgres driver.我正在处理Postgrex中的一个问题,这是一个 Elixir Postgres 驱动程序。

However, I am confused by the stacktrace below.但是,我对下面的堆栈跟踪感到困惑。 (To make it readable I have removed only the lengthy arguments to msg_recv/4 .) (为了使其可读,我只删除了冗长的 arguments 到msg_recv/4 。)

16:52:54.323 [error] GenServer #PID<0.234.0> terminating
** (FunctionClauseError) no function clause matching in Postgrex.Protocol.msg_recv/4
    (postgrex 0.15.5) lib/postgrex/protocol.ex:2837: Postgrex.Protocol.msg_recv(...SNIP)
    (postgrex 0.15.5) lib/postgrex/protocol.ex:816: Postgrex.Protocol.bootstrap_recv/4
    (postgrex 0.15.5) lib/postgrex/protocol.ex:579: Postgrex.Protocol.handshake/2
    (db_connection 2.1.0) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
    (connection 1.0.4) lib/connection.ex:622: Connection.enter_connect/5
    (stdlib 3.12.1) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
State: Postgrex.Protocol

The stacktrace appears to indicate handshake/2 calls bootstrap_recv/4 , but there is no direct call to bootstrap_recv/4 in handshake/2 .堆栈跟踪似乎表明handshake/2调用bootstrap_recv/4 ,但在handshake/2中没有直接调用bootstrap_recv/4

Line 579 is indeed inside handshake/2 , and is a call to do_handshake/2 , of which there are two variants which themselves call ssl/2 or startup/2 . 第 579 行确实在handshake/2内部,并且是对do_handshake/2的调用,其中有两个变体,它们本身称为ssl/2startup/2

I cannot find where bootstrap_recv/4 is called in this code path.我找不到在此代码路径中调用bootstrap_recv/4的位置。

Why are do_handshake/2 and one of ssl/2 and startup/2 (and whatever other subsequent calls lead to bootstrap_recv/4 and ultimately msg_recv/4 ) not in the stacktrace?为什么do_handshake/2ssl/2startup/2之一(以及任何其他后续调用导致bootstrap_recv/4并最终导致msg_recv/4 )不在堆栈跟踪中?

Presumably, I misunderstand Elixir stacktraces.据推测,我误解了 Elixir 堆栈跟踪。

EDIT: Such a detailed question for a general issue is a shame, but I'll leave the question in case anyone comes to this situation via debugging.编辑:针对一般问题提出如此详细的问题是一种耻辱,但我会留下这个问题,以防有人通过调试遇到这种情况。

No, stacktraces in Elixir do not contain every entered function due to the Erlang VM.不,由于 Erlang VM,Elixir 中的堆栈跟踪不包含每个输入的 function。 I found mention of this in a post on the Elixir forum.我在 Elixir 论坛的帖子中发现了这一点。 It is also mentioned in this GitHub issue . GitHub 问题中也提到了它。

On the erlang-questions mailing list, Joe Armstrong mentions Erlang refers to this as " last call optimization ", and gives an explanation.erlang-questions邮件列表中,Joe Armstrong 提到 Erlang 将其称为“ 最后调用优化”,并给出了解释。

The code below with a few trivial lines to prevent tail-calling demonstrates the difference.下面的代码用几行简单的代码来防止尾调用演示了不同之处。

defmodule Demo do
  def first() do
    second()

    # Uncomment to prevent tail-call, and `first` appears in the stacktrace.
    # case second() do
    #   _ -> {:ok, 0}
    # end
  end

  # Elixir knows third() is still a tail-call.
  def second() do
    r = third()
    _ = 1 + 1
    # dummy() # Uncomment to prevent tail-call, and `second` appears in the stacktrace.
    r
  end

  def third() do
    IO.inspect(Process.info(self(), :current_stacktrace))
    {:ok, 0}
  end

  defp dummy, do: nil
end

IO.inspect(Demo.first)

Results in stacktrace:堆栈跟踪结果:

{:current_stacktrace,
 [
   {Process, :info, 2, [file: 'lib/process.ex', line: 765]},
   {Demo, :third, 0, [file: 'demo.exs', line: 21]},
   {:elixir_compiler_0, :__FILE__, 1, [file: 'demo.exs', line: 30]},
   {:elixir_compiler, :dispatch, 4, [file: 'src/elixir_compiler.erl', line: 75]},
   {:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 60]},
   {:elixir_lexical, :run, 3, [file: 'src/elixir_lexical.erl', line: 15]},
   {:elixir_compiler, :quoted, 3, [file: 'src/elixir_compiler.erl', line: 18]}
 ]}
{:ok, 0}

While adjusting the commented lines (as mentioned) in the same code results in stacktrace:在同一代码中调整注释行(如前所述)时会产生堆栈跟踪:

{:current_stacktrace,
 [
   {Process, :info, 2, [file: 'lib/process.ex', line: 765]},
   {Demo, :third, 0, [file: 'demo.exs', line: 20]},
   {Demo, :second, 0, [file: 'demo.exs', line: 13]},
   {Demo, :first, 0, [file: 'demo.exs', line: 6]},
   {:elixir_compiler_0, :__FILE__, 1, [file: 'demo.exs', line: 29]},
   {:elixir_compiler, :dispatch, 4, [file: 'src/elixir_compiler.erl', line: 75]},
   {:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 60]}
 ]}
{:ok, 0}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM