我如何 read/debug FunctionClauseError?
How do I read/debug FunctionClauseError?
虽然在 SO () 也有类似的问题,但出于某种原因,错误在我的案例中以另一种方式格式化(而且我理解 FunctionClauseError
的一般含义),所以让我再问一次。
这是我遇到的问题:
{:error, reason} ->
Logger.error(fn -> ["failed to fetch internal transactions for >blocks: ", inspect(reason)] end,
error_count: unique_numbers_count
)
给出(我添加了换行符)
2022-04-13T18:44:19.749 application=indexer fetcher=internal_transaction count=10 error_count=10 [error]
failed to fetch internal transactions for blocks: %FunctionClauseError{args: nil, arity: 1,
clauses: nil, function: :finalize, kind: nil, module: EthereumJSONRPC.Geth.Tracer}
很明显 reason
是
%FunctionClauseError{args: nil, arity: 1, clauses: nil, function: :finalize, kind: nil,
module: EthereumJSONRPC.Geth.Tracer}
我想知道这些位是什么意思,它们可以帮助调试吗?
在模块 EthereumJSONRPC.Geth.Tracer
中函数 finalize
被定义为
defp finalize(%{stack: [top], calls: [calls]}) do
传递给它的参数示例(导致错误)是:
%{
calls: [[], [], [], []],
depth: 4,
stack: [
%{
"callType" => "staticcall",
"from" => nil,
"gas" => 432013,
"gasUsed" => 21661,
"input" => "0xefc4cfa.....",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 4346,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0, 0, 0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "staticcall",
"from" => nil,
"gas" => 438139,
"gasUsed" => 1726,
"input" => "0xefc4c.......",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 4026,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0, 0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "staticcall",
"from" => nil
"gas" => 445060,
"gasUsed" => 2521,
"input" => "0xefc4......",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 3706,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "call",
"from" => "0x9a66644084108a1bc23a9ccd50d6d63e53098db6",
"gas" => 460960,
"gasUsed" => 11500,
"input" => "0xba2c.........",
"output" => "0x",
"to" => "0x841ce48f9446c8e281d3f1444cb859b4a6d0738c",
"traceAddress" => [],
"type" => "call",
"value" => "0x0"
}
],
trace_address: [0, 0, 0, 0]
}
这对我来说还不错(它同时具有 stack
和 calls
属性)。我可以从 args: nil, arity: 1, clauses: nil, function: :finalize, kind: nil
位中提取更多内容用于调试吗?如果你指出原因,它也会有所帮助,但我也想了解如何调试它。额外的道具 (depth
, trace_address
) 会是问题的根源吗?或者我应该在 finalize
函数体内寻找错误原因? (据我了解,没有)
PS 给寻求调试帮助的其他人的注意事项:错误文本前的位
application=indexer fetcher=internal_transaction count=10 error_count=10
可能包含有用的信息:如果您查找 Logger.metadata
,您可能会找到类似
的内容
Logger.metadata(fetcher: :internal_transaction)
这可以提示错误的来源。
默认情况下,如果您不使用 try / rescue
,将记录一个 FunctionClauseError
,其中包含调试它所需的所有信息(值、模式、堆栈跟踪):
> String.downcase(1)
** (FunctionClauseError) no function clause matching in String.downcase/2
The following arguments were given to String.downcase/2:
# 1
1
# 2
:default
...
但是,如果您恢复错误并将其 return 作为一个元组,您将丢失大部分信息:
try do
String.downcase(1)
rescue
err -> {:error, err}
end
结果将只包含一个非常准系统的结构:
{:error,
%FunctionClauseError{
args: nil,
arity: 2,
clauses: nil,
function: :downcase,
kind: nil,
module: String
}}
您可以直接登录 rescue 子句,其中 __STACKTRACE__
可用,使用 this official guide:
中解释的方法
try do
String.downcase(1)
rescue
err ->
# format the exception in a readable way
Exception.format(:error, err, __STACKTRACE__)
|> Logger.error()
# return value
:error
end
话虽这么说,但在 Elixir 中,依赖 try/rescue
并不常见,如上文指南所述。大多数时候你只是让意想不到的事情失败(著名的“让它崩溃”哲学),并使用 :error
元组来处理你实际期望和想要处理的情况。
旁注:@sabiwara 提供的答案有大量有用信息,应标记为正确。
这是您遇到错误的原因:
defp finalize(%{stack: [top], calls: [calls]})
这定义了一个函数,接受带有键的映射,包括但不限于:stack
和:calls
,它们的值是只包含一个元素的列表.
您在那里传递了更长的列表,因此出现错误。这可能是您想要做的:
defp finalize(%{stack: top, calls: calls})
when is_list(top) and is_list(calls)
虽然在 SO (FunctionClauseError
的一般含义),所以让我再问一次。
这是我遇到的问题:
{:error, reason} -> Logger.error(fn -> ["failed to fetch internal transactions for >blocks: ", inspect(reason)] end, error_count: unique_numbers_count )
给出(我添加了换行符)
2022-04-13T18:44:19.749 application=indexer fetcher=internal_transaction count=10 error_count=10 [error] failed to fetch internal transactions for blocks: %FunctionClauseError{args: nil, arity: 1, clauses: nil, function: :finalize, kind: nil, module: EthereumJSONRPC.Geth.Tracer}
很明显 reason
是
%FunctionClauseError{args: nil, arity: 1, clauses: nil, function: :finalize, kind: nil, module: EthereumJSONRPC.Geth.Tracer}
我想知道这些位是什么意思,它们可以帮助调试吗?
在模块 EthereumJSONRPC.Geth.Tracer
中函数 finalize
被定义为
defp finalize(%{stack: [top], calls: [calls]}) do
传递给它的参数示例(导致错误)是:
%{
calls: [[], [], [], []],
depth: 4,
stack: [
%{
"callType" => "staticcall",
"from" => nil,
"gas" => 432013,
"gasUsed" => 21661,
"input" => "0xefc4cfa.....",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 4346,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0, 0, 0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "staticcall",
"from" => nil,
"gas" => 438139,
"gasUsed" => 1726,
"input" => "0xefc4c.......",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 4026,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0, 0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "staticcall",
"from" => nil
"gas" => 445060,
"gasUsed" => 2521,
"input" => "0xefc4......",
"output" => "0x",
"outputLength" => 64,
"outputOffset" => 3706,
"to" => "0x0000000000000000000000000000000000000001",
"traceAddress" => [0],
"type" => "call",
"value" => "0x0"
},
%{
"callType" => "call",
"from" => "0x9a66644084108a1bc23a9ccd50d6d63e53098db6",
"gas" => 460960,
"gasUsed" => 11500,
"input" => "0xba2c.........",
"output" => "0x",
"to" => "0x841ce48f9446c8e281d3f1444cb859b4a6d0738c",
"traceAddress" => [],
"type" => "call",
"value" => "0x0"
}
],
trace_address: [0, 0, 0, 0]
}
这对我来说还不错(它同时具有 stack
和 calls
属性)。我可以从 args: nil, arity: 1, clauses: nil, function: :finalize, kind: nil
位中提取更多内容用于调试吗?如果你指出原因,它也会有所帮助,但我也想了解如何调试它。额外的道具 (depth
, trace_address
) 会是问题的根源吗?或者我应该在 finalize
函数体内寻找错误原因? (据我了解,没有)
PS 给寻求调试帮助的其他人的注意事项:错误文本前的位
application=indexer fetcher=internal_transaction count=10 error_count=10
可能包含有用的信息:如果您查找 Logger.metadata
,您可能会找到类似
Logger.metadata(fetcher: :internal_transaction)
这可以提示错误的来源。
默认情况下,如果您不使用 try / rescue
,将记录一个 FunctionClauseError
,其中包含调试它所需的所有信息(值、模式、堆栈跟踪):
> String.downcase(1)
** (FunctionClauseError) no function clause matching in String.downcase/2
The following arguments were given to String.downcase/2:
# 1
1
# 2
:default
...
但是,如果您恢复错误并将其 return 作为一个元组,您将丢失大部分信息:
try do
String.downcase(1)
rescue
err -> {:error, err}
end
结果将只包含一个非常准系统的结构:
{:error,
%FunctionClauseError{
args: nil,
arity: 2,
clauses: nil,
function: :downcase,
kind: nil,
module: String
}}
您可以直接登录 rescue 子句,其中 __STACKTRACE__
可用,使用 this official guide:
try do
String.downcase(1)
rescue
err ->
# format the exception in a readable way
Exception.format(:error, err, __STACKTRACE__)
|> Logger.error()
# return value
:error
end
话虽这么说,但在 Elixir 中,依赖 try/rescue
并不常见,如上文指南所述。大多数时候你只是让意想不到的事情失败(著名的“让它崩溃”哲学),并使用 :error
元组来处理你实际期望和想要处理的情况。
旁注:@sabiwara 提供的答案有大量有用信息,应标记为正确。
这是您遇到错误的原因:
defp finalize(%{stack: [top], calls: [calls]})
这定义了一个函数,接受带有键的映射,包括但不限于:stack
和:calls
,它们的值是只包含一个元素的列表.
您在那里传递了更长的列表,因此出现错误。这可能是您想要做的:
defp finalize(%{stack: top, calls: calls})
when is_list(top) and is_list(calls)