I have an OTP application. The version of this application is found in two places: the src/application_name.src file (standard with OTP applications), and in my rebar.config.
Is there an "official" way for an application to get it's own version, or does this need to be hacked via sed/grep etc? I want to have an "info" endpoint in my application that prints it's own version. Of course I can always do something like grep the version out of my rebar.config, but it seems hacky.
According to the Erlang documentation you can use API of application module.
Example:
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2.2 (abort with ^G)
1> application:loaded_applications().
[{stdlib,"ERTS CXC 138 10","3.2"},
{kernel,"ERTS CXC 138 10","5.1.1"}]
2> GetVer =
fun(App) ->
case lists:keyfind(App, 1, application:loaded_applications()) of
{_, _, Ver} ->
Ver;
false ->
not_found
end
end.
#Fun<erl_eval.6.52032458>
3> GetVer(stdlib).
"3.2"
4> GetVer(eunit).
not_found
5> application:load(eunit).
ok
6> GetVer(eunit).
"2.3.2"
7>
If it is properly packaged as an application, you can get it using application:which_applications(). I have some sample code, but basically you'd do something like this:
vsn() -> vsn(your_application_atom_name).
vsn(Application) -> vsn(Application, application:which_applications()).
vsn(_Application, []) -> undefined;
vsn(Application, [{Application,_,Vsn}|_]) -> Vsn;
vsn(Application, [_|Rest]) -> vsn(Application, Rest).
The downside is that you do have to hardcode the name of your application (as an atom). I never found a way around this, but you might be able to cook something up.
application:get_key/1,2 can give you the version number of the application.
1> application:get_key(tfs, vsn).
{ok,"94a3d72"}
2> application:get_key(mnesia, vsn).
{ok,"4.16.1"}
Related
I have been gathering data using the functionality provided by :erlang.trace in an Elixir program. By specify an option of {:tracer, some_pid} I can have another process get traces for everything currently going on in a process. The output of this is really useful.
The issue I am running into is how to stop tracing the process without crashing the VM. The documentation for :erlang.trace is here
http://erlang.org/doc/man/erlang.html#trace-3
My presumption is that I could set How to false and set my options to [:all] to disable everything.
Here is the example program I have
defmodule Example do
def simple_tracer() do
receive do
x -> IO.inspect(x); simple_tracer()
end
end
def fancy_tracer() do
receive do
x -> IO.puts "fancy!" <> inspect(x); fancy_tracer
end
end
end
simple = spawn_link(&Example.simple_tracer/0)
fancy = spawn_link(&Example.fancy_tracer/0)
#Tell BEAM to trace everything
:erlang.trace_pattern(
{:_,:_,:_},
true,
[:local]
)
#Tell BEAM to trace this processs, but send the result to the simple tracer
:erlang.trace(self(),
true,
[:send,
:receive,
:procs,
:ports,
:garbage_collection,
:monotonic_timestamp,
:set_on_first_spawn,
:set_on_first_link,
:call,
:return_to,
{:tracer, simple},
:arity])
IO.inspect Enum.map([1,2,3,4,5], fn x -> :math.sqrt(x) end)
#Tell BEAM to stop tracing
:erlang.trace(self(), false, [:all])
#This should not show up in the trace
IO.inspect Enum.map([3,7,11,101], fn x -> :math.sqrt(x) end)
#Tell BEAM to start tracing again
:erlang.trace(self(),
true,
[:send,
:receive,
:procs,
:ports,
:garbage_collection,
:monotonic_timestamp,
:set_on_first_spawn,
:set_on_first_link,
:call,
:return_to,
{:tracer, fancy},
:arity])
IO.inspect Enum.map([10,20,30,40,50], fn x -> :math.sqrt(x) end)
The program uses two seperate processes to trace the main one. Or at least it attempts to. Here is output I get when I run it:
[ericu-destroyer-of-worlds] ~$ elixir ~/elixir_tracing.ex
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979]
{:trace_ts, #PID<0.71.0>, :call, {Enum, :map, 2}, -576460751827716034}
Segmentation fault
As best I can tell the call to :erlang.trace(self(), false, [:all]) results in a segmentation fault. All I am trying to do is disable all the tracing so that the process simple stops receiving the traces.
Update
A commenter indicated they could not reproduce the crash.
I tried the code above on the following version and it crashed.
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.3.1
I then ran it on this version and it did not crash.
Erlang/OTP 18 [erts-7.3.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Elixir 1.2.5
Why does this code crash on one version and not another?
Trying to add multicast group for ipv6, but it returns error. don't understand the problem. with ipv4 it works fine
(test_client#127.0.0.1)1> {ok, S} = gen_udp:open(3333, [binary, {active, false}, {ip, {65342,0,0,0,0,0,34048,9029}}, inet6, {multicast_loop, false}]).
{ok,#Port<0.1587>}
(test_client#127.0.0.1)4> inet:setopts(S, [{add_membership, {{65342,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}}}]).
{error,einval}
unfortunately this topic in erlang docs is badly documented
also have tried with addrreses like ff3c: , ff32:
UPDATE
i've looked into Erlang/OTP 18.2 source code, there is using function prim_inet:is_sockopt_val(add_membership, {{65280,0,0,0,0,0,34048,9029}, {0,0,0,0,0,0,0,0}})
and it always return false, because in prim_inet:type_value_2/2 we have type ip, value {_,_,_,_,_,_,_,_} and it waits only for ipv4 {_,_,_,_}.
on the one hand i know why can't add membership with ipv6 when open socket, but on other hand what to do is opened question
It doesn't look like Erlang's driver has implemented IPV6_ADD_MEMBERSHIP, but it does have raw support so you could construct it yourself. A problem with this approach is that you are hard coding things usually defined in header files, so your solution wont be very portable.
-module(unssmraw).
-export([test/0]).
test() ->
Port = 57100,
Mad = <<65340:16,0:16,0:16,0:16,0:16,0:16,34048:16,9029:16>>,
Ifindx = <<3:64/native>>,
Ip6 = 41,
Ip6am = 20,
{ok, Sock} = gen_udp:open(Port, [{reuseaddr,true}, inet6, binary]),
R3 = inet:setopts(Sock, [{raw, Ip6, Ip6am, <<Mad/binary, Ifindx/binary>> }]),
io:format("ssm ok? ~w ~n", [R3]),
receive
{udp, S, A, Pr, Pk} -> io:format("watcher sees: Socket ~p Address ~p Port ~p Packet ~p ~n", [S, A, Pr, Pk]) end.
Example test sender:
echo hi | socat - UDP6-SENDTO:\"ff3c::8500:2345\":57100
Example run:
$ erl
Erlang/OTP 19 [erts-8.0.1] [source-761e467] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0.1 (abort with ^G)
1> unssmraw:test().
ssm ok? ok
watcher sees: Socket #Port<0.453> Address {65152,0,0,0,47734,16383,65066,
19977} Port 43511 Packet <<"hi\n">>
ok
Notes on my hardcoded values
How to find the interface index used in Ifindx:
As of OTP 22 net:if_name2index is available to call. A language neutral description is here. I used a 64-bit since that is the size of an int on my system and it is an int in mreq in my in6.h.)
Ip6's value is from in.h
Ip6am is IPV6_ADD_MEMBERSHIP from in6.h.
When tried to send unmatched message to a spawned process in erlang shell, I was expecting the message should remain in the mailbox, but it seemed like the mailbox is empty, why?
Erlang R15B02 (erts-5.9.2) [smp:2:2] [async-threads:0]
Eshell V5.9.2 (abort with ^G)
1> Pid = spawn(fun()->receive stop->stop end end).
<0.33.0>
2> Pid ! msg.
msg
3> erlang:process_info(Pid, messages).
{messages,[]} %% where is the msg?
When the message can't be matched against a receive pattern it is moved from the mailbox to a save queue, see http://ndpar.blogspot.se/2010/11/erlang-explained-selective-receive.html for a detailed explanation of what happens.
The messages parameter to process_info/2 only shows the mailbox contents, AFAIK there is no way to inspect the contents of the save queue.
The message is of course there and it will be checked in subsequent receives. The fact that you can't see it with erlang:process_info(Pid, messages) is, in my opinion, weird.
(ppb2_bs6#esekilvxen245)1> self() ! a.
a
(ppb2_bs6#esekilvxen245)2> erlang:process_info(self(), messages).
{messages,[a]}
I am working on my first real project in erlang, however, this code is simplified for brevity. I want to be able to load a newer version of a file into my project remotely while it's running. I've read about using a behavior like gen_server or gen_fsm which has this for free. While that might achieve the result, I want to use this to learn how to do it, not just get it done. I've read the docs about code replacement, and LYSE's bit about Hot Code Loving, among other things, but I haven't been able to find anything that works for what I'm doing, so here is the basic idea.
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
I am simply looping with the idea that I can send the message upgrade and it will load a newer version of the code.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> c(reloading).
{ok,reloading}
2> Loop = spawn(reloading, loop, []).
<0.39.0>
3> Loop ! hello.
This is a test
hello
At this point I change 10 line to io:format("I have changed this!~n"),
4> Loop ! upgrade.
upgrade
5> Loop ! hello.
This is a test
hello
I am expecting this hello call to print I have changed this! not This is a test. I know I can simply call c(reloading). and have this work the way expected, but I'm looking to send the actual project a message rather than manually updating the code. So where is my disconnect? What am I doing wrong, that I should be doing in order to hot load this code? As mentioned before, I am looking for a non-OTP solution for the sake of education.
For the sake of having an explicit answer, I am posting this.
Using #rvirding's suggestion of using the code module, I've modified it to look like this:
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
code:purge(?MODULE),
compile:file(?MODULE),
code:load_file(?MODULE),
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
First code:purge the old ?MODULE, then compile:file the new file, and finally, code:load_file the new ?MODULE.
This works as I originally intended.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> Loop = spawn(reloading, loop, []).
<0.34.0>
2> Loop ! hello.
This is a test
hello
Change line to io:format("I have changed this!~n"),
3> Loop ! upgrade.
upgrade
4> Loop ! hello.
I have changed this!
hello
While erlang can handle two versions of a module and calling a function with mod:func(...) will always call the latest version of a module (if the function is exported) you still have to load the new version of the module into Erlang system. You can't expect it automagically detect that you happen to have a new version of the module somewhere, find it, compile it and load it.
N.B. compiling and loading are two separate things. So c(mod). both compiles and loads the module, while l(mod). just loads the object code (.beam file) of the already compiled module. The Erlang compiler is called from the module compile and it just compiles and generates a .beam file while the code loading is handled by the module code.
In addition to the above I'd like to notice that some tools that reload code automatically for you exist.
You should have a look at sync or active projects.
Compile *.beam locally, then send it to your server and reload it as mentioned in man pages:
http://erlang.org/documentation/doc-1/reference_manual/code_loading.html#id86381
-module(m).
-export([loop/0]).
loop() ->
receive
code_switch ->
m:loop();
Msg ->
...
loop()
end.
A common pattern in Erlang is the recursive loop that maintains state:
loop(State) ->
receive
Msg ->
NewState = whatever(Msg),
loop(NewState)
end.
Is there any way to query the state of a running process with a bif or tracing or something? Since crash messages say "...when state was..." and show the crashed process's state, I thought this would be easy, but I was disappointed that I haven't been able to find a bif to do this.
So, then, I figured using the dbg module's tracing would do it. Unfortunately, I believe because these loops are tail call optimized, dbg will only capture the first call to the function.
Any solution?
If your process is using OTP, it is enough to do sys:get_status(Pid).
The error message you mentions is displayed by SASL. SASL is an error reporting daemon in OTP.
The state you are referring in your example code is just an argument of tail recursive function. There is no way to extract it using anything except for tracing BIFs. I guess this would be not a proper solution in production code, since tracing is intended to be used only for debug purposes.
Proper, and industry tested, solution would be make extensive use of OTP in your project. Then you can take full advantage of SASL error reporting, rb module to collect these reports, sys - to inspect the state of the running OTP-compatible process, proc_lib - to make short-lived processes OTP-compliant, etc.
It turns out there's a better answer than all of these, if you're using OTP:
sys:get_state/1
Probably it didn't exist at the time.
It looks like you're making the problem out of nothing. erlang:process_info/1 gives enough information for debugging purposes. If your REALLY need loop function arguments, why don't you give it back to caller in response to one of the special messages that you define yourself?
UPDATE:
Just to clarify terminology. The closest thing to the 'state of the process' on the language level is process dictionary, usage of which is highly discouraged. It can be queried by erlang:process_info/1 or erlang:process/2.
What you actually need is to trace process's local functions calls along with their arguments:
-module(ping).
-export([start/0, send/1, loop/1]).
start() ->
spawn(?MODULE, loop, [0]).
send(Pid) ->
Pid ! {self(), ping},
receive
pong ->
pong
end.
loop(S) ->
receive
{Pid, ping} ->
Pid ! pong,
loop(S + 1)
end.
Console:
Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> l(ping).
{module,ping}
2> erlang:trace(all, true, [call]).
23
3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).
5
4> Pid = ping:start().
<0.36.0>
5> ping:send(Pid).
pong
6> flush().
Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}
Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}
ok
7>
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).
That's what I use to get the state of a gen_server. (Tried to add it as a comment to the reply above, but couldn't get formatting right.)
As far as I know you cant get the arguments passed to a locally called function. I would love for someone to prove me wrong.
-module(loop).
-export([start/0, loop/1]).
start() ->
spawn_link(fun () -> loop([]) end).
loop(State) ->
receive
Msg ->
loop([Msg|State])
end.
If we want to trace this module you do the following in the shell.
dbg:tracer().
dbg:p(new,[c]).
dbg:tpl(loop, []).
Using this tracing setting you get to see local calls (the 'l' in tpl means that local calls will be traced as well, not only global ones).
5> Pid = loop:start().
(<0.39.0>) call loop:'-start/0-fun-0-'/0
(<0.39.0>) call loop:loop/1
<0.39.0>
6> Pid ! foo.
(<0.39.0>) call loop:loop/1
foo
As you see, just the calls are included. No arguments in sight.
My recommendation is to base correctness in debugging and testing on the messages sent rather than state kept in processes. I.e. if you send the process a bunch of messages, assert that it does the right thing, not that it has a certain set of values.
But of course, you could also sprinkle some erlang:display(State) calls in your code temporarily. Poor man's debugging.
This is a "oneliner" That can be used in the shell.
sys:get_status(list_to_pid("<0.1012.0>")).
It helps you convert a pid string into a Pid.