问题
I have printed all code loaded as follows, why {lager_default_tracer,[]}, where beam file?
(lager_test_1@macbook.local)10> io:format("~p",[code:all_loaded()]).
[{io,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io.beam"},
{erl_distribution,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_distribution.beam"},
{edlin,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/edlin.beam"},
{beam_clean,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_clean.beam"},
{v3_core,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_core.beam"},
{erl_epmd,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/erl_epmd.beam"},
{love_misc,"/usr/local/bin/lager_test/lib/hanoch-0.0.1.6/ebin/love_misc.beam"},
{zlib,preloaded},
{error_handler,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/error_handler.beam"},
{io_lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/io_lib.beam"},
{lib,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/lib.beam"},
{mnesia,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia.beam"},
{lager_test_app,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_app.beam"},
{beam_jump,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_jump.beam"},
{v3_codegen,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/v3_codegen.beam"},
{beam_flatten,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_flatten.beam"},
{mnesia_tm,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_tm.beam"},
{prim_eval,preloaded},
{beam_bool,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_bool.beam"},
{error_logger_lager_h,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/error_logger_lager_h.beam"},
{lager_msg,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_msg.beam"},
{mnesia_frag,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_frag.beam"},
{filename,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/filename.beam"},
{lager_default_tracer,[]},
{lager_default_formatter,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_default_formatter.beam"},
{mnesia_locker,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_locker.beam"},
{mnesia_recover,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_recover.beam"},
{mnesia_dumper,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_dumper.beam"},
{mnesia_kernel_sup,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_kernel_sup.beam"},
{mnesia_sp,"/usr/local/lib/erlang/lib/mnesia-4.12.4/ebin/mnesia_sp.beam"},
{erts_internal,preloaded},
{unicode,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/unicode.beam"},
{lager_backend_throttle,"/usr/local/bin/lager_test/lib/lager-2.0.0/ebin/lager_backend_throttle.beam"},
{beam_type,"/usr/local/lib/erlang/lib/compiler-5.0.3/ebin/beam_type.beam"},
{orddict,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/orddict.beam"},
{gb_sets,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/gb_sets.beam"},
{sofs,"/usr/local/lib/erlang/lib/stdlib-2.3/ebin/sofs.beam"},
{inet_db,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet_db.beam"},
{lager_test_a,"/usr/local/bin/lager_test/lib/lager_test-0.0.1.0/ebin/lager_test_a.beam"},
{inet,"/usr/local/lib/erlang/lib/kernel-3.1/ebin/inet.beam"},
When I call module_info(), it is as follows:
(lager_test_1@macbook.local)11> lager_default_tracer:module_info().
[{exports,[{table,1},
{handle,1},
{module_info,0},
{module_info,1},
{info,1}]},
{imports,[]},
{attributes,[{vsn,[203040246025344403396962742072895880482]}]},
{compile,[{options,[]},
{version,"5.0.3"},
{time,{2017,8,27,5,43,32}},
{source,"/private/tmp/lager_test-0.0.1.0"}]}]
When I call lager_default_tracer:table(111)
, it is as follows:
(lager_test_1@macbook.local)12> lager_default_tracer:table(aaa).
** exception error: bad argument
in function lager_default_tracer:table/1
回答1:
The lager_default_tracer
module has no associated beam file because it's created at runtime. The lager
application uses goldrush, which uses runtime code compilation and loading.
If you look through the goldrush sources you'll see that it calls the standard compile:forms/2 for dynamic compilation. By tracing that call, we can reconstruct the source code for lager_default_tracer
using the steps below, which assume you've already cloned the lager source repository and successfully compiled it. In some of the steps, the output of the Erlang shell command is too large to put here, so those parts are abbreviated using ellipses.
In your already-compiled cloned
lager
repo directory, runrebar shell
to start an Erlang shell, which ensures all necessary directories are in the Erlang load path.In the shell, turn on dbg tracing and trace
compile:forms/2
:1> dbg:tracer(), dbg:p(all, call). {ok,[{matched,nonode@nohost,34}]} 2> dbg:tpl(compile, forms, []). {ok,[{matched,nonode@nohost,2}]}
Start the
lager
application and its dependencies:3> application:ensure_all_started(lager).
This will cause the
dbg
trace to produce some lengthy output like this:(<0.94.0>) call compile:forms([{attribute,0,module,lager_default_tracer}, ... {tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}],[nowarn_unused_vars]) {ok,[syntax_tools,compiler,goldrush,lager]} 08:29:21.478 [info] Application lager started on node nonode@nohost
Here, the output is abbreviated to show only the first line and last few lines. The final two lines are the results from
application:ensure_all_started/1
. Everything above those lines is the abstract format for thelager_default_tracer
module.Copy the traced output starting from
[{attribute,0,module,lager_default_tracer}
in the first line of the output trace all the way to{tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}]
in the final line of output trace. Do not include the ending text[nowarn_unused_vars])
in what you copy.Paste the copied data to assign it to a variable named
M
in the Erlang shell:4> M = [{attribute,0,module,lager_default_tracer}, ... {tuple,0,[{integer,0,2},{integer,0,1}]}]}]}]}].
Don't forget to add the final period (aka full stop) to complete the expression.
Turn off
dbg
tracing:5> dbg:stop_clear(). ok
Compile the abstract format:
6> {ok, _, B} = compile:forms(M, [no_unused_vars, debug_info]). {ok,lager_default_tracer, <<70,79,82,49,0,0,6,164,66,69,65,77,65,116,85,56,0,0,1,9, 0,0,0,23,20,108,...>>}
The variable
B
now holds, as a binary, the compiled code for thelager_default_tracer
module.Extract the abstract code chunk from the compiled binary stored in
B
:7> {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(B,[abstract_code]). {ok,{lager_default_tracer, [{abstract_code, ... [{clause,0,[{var,0,'Event'}],[],[{call,...}]}]}]}}]}}
The variable
AC
now holds the abstract code.Use the abstract code to print reconstructed source code for the
lager_default_tracer
module:8> io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]). -module(lager_default_tracer). -export([info/1, reset_counters/1, table/1, handle/1]). ... handle_(Event) -> gr_counter:update_counter(table(counters), filter, {2, 1}). ok
This final step and the one before it are taken from the beam_lib documentation, under "Reconstructing Source Code".
Unsurprisingly, the reconstructed source code shows calls of other goldrush
functions, so you'll need access to the goldrush sources if you want to try to understand the reconstructed code.
来源:https://stackoverflow.com/questions/45902180/where-is-code-beam-file