0

I am running Erlang R16B03-1 (erts-5.10.4) at OS X 10.9.2. Erlang was installed by using brew.

And I am trying to run a gen_server module.

-module(logger).
-author("evangelosp").

-behaviour(gen_server).

%% API
-export([start/0, stop/0, log/2]).

%% gen_server callbacks
-export([init/1,
  handle_call/3,
  handle_cast/2,
  handle_info/2,
  terminate/2,
  code_change/3]).

-define(SERVER, ?MODULE).

%%%===================================================================
%%% API
%%%===================================================================

start() -> gen_server:start_link({global, ?SERVER}, ?MODULE, [], []).

stop() -> gen_server:call(?MODULE, stop).

log(_Level, _MSG) -> gen_server:call(?MODULE, {add, {_Level, _MSG}}).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init([]) -> {ok, ets:new(?MODULE, [])}.

handle_call(_Request, _From, Table) -> {reply, {ok, ["Mplah!", _Request, _From, Table]}, Table}.

handle_cast(_Request, State) -> {noreply, State}.

handle_info(_Info, State) -> {noreply, State}.

terminate(_Reason, _State) -> ok.

code_change(_OldVsn, State, _Extra) -> {ok, State}.

In the erlang shell I am running:

Eshell V5.10.4  (abort with ^G)
1> c(logger).
{ok,logger}
2> logger:start().
{ok,<0.40.0>}
3> logger:log(info, "Hello World").
** exception exit: {noproc,{gen_server,call,
                                       [logger,{add,{info,"Hello World"}}]}}
     in function  gen_server:call/2 (gen_server.erl, line 180)

And I can't get rid of that exception. I haven't actually found any useful resource by looking up the exception message, but this which didn't help much.

Cheers.

Evan P
  • 1,767
  • 1
  • 20
  • 37
  • By the way, you should start with underscore only variable names you not using in function's body. For instance, in `log/2` you are using both arguments. – taro Jun 08 '14 at 12:00

2 Answers2

2

In you code start() -> gen_server:start_link({global, ?SERVER}, ?MODULE, [], [])., you use {global, ?SERVER} which means that:

If ServerName={global,GlobalName} the gen_server is registered globally as GlobalName using global:register_name/2.

So when you send message to the server, you should write log(_Level, _MSG) -> gen_server:call({global, ?MODULE}, {add, {_Level, _MSG}}).. Please see the erlang doc:

call(ServerRef, Request, Timeout) -> Reply Types: ServerRef = Name | {Name,Node} | {global,GlobalName} | ServerRef can be:

Name, if the gen_server is locally registered,

{global,GlobalName}, if the gen_server is globally registered.

BlackMamba
  • 10,054
  • 7
  • 44
  • 67
  • Yes, you are right. I realise that afterwards with the hard way :) thx! – Evan P Jun 09 '14 at 09:46
  • 1
    I looked only the error report, not your code... shame on me! Global registration is useful only if you want to create (now or in futur) a cluster of erlang nodes; and explicit registration is useless, it is done automatically if you provide a name in the gen_server:start/ – Pascal Jun 09 '14 at 18:52
1

Your server is not registered, so it is accesible only by its pid. But the interface functions use the implicit macro ?MODULE (which is replaced by logger at compilation) to access it.

You need either to change your interface functions, or, to register the server in the start function:

start() ->
  {ok,Pid} = gen_server:start_link({global, ?SERVER}, ?MODULE, [], []),
  register(?MODULE,Pid).

[edit] Thanks Evalon, I made the correction in the answer :o)

Pascal
  • 13,977
  • 2
  • 24
  • 32
  • If you can fix your line to; `{ok, Pid} = gen_server:start_link({global, ?SERVER}, ?MODULE, [], []), register(?MODULE, Pid).` It does works like that, shouldn't gen_server do that by the option of `global` ?? – Evan P Jun 08 '14 at 11:18
  • Oh!! Just realised, by setting it as `global` was the issue in the first place. Thanks for helping! Cheers! – Evan P Jun 08 '14 at 11:30