[ start_link/0
, subscribe/1
, unsubscribe/1
+
+ % Force production and distribution. Blocks. Mainly for testing.
+ , force_production/0
]).
%% gen_server callbacks
%% ============================================================================
-define(SIGNAL_PRODUCTION , beam_stats_production_signal).
+-define(FORCE_PRODUCTION , beam_stats_force_production).
-record(state,
{ consumers = ordsets:new() :: ordsets:ordset(pid())
+ , stats_state :: beam_stats_state:t()
}).
+-type state() ::
+ #state{}.
+
%% ============================================================================
%% API
%% ============================================================================
unsubscribe(PID) ->
gen_server:cast(?MODULE, {unsubscribe, PID}).
+-spec force_production() ->
+ {}.
+force_production() ->
+ gen_server:call(?MODULE, ?FORCE_PRODUCTION).
+
%% ============================================================================
%% gen_server callbacks (unused)
%% ============================================================================
-handle_call(_Request, _From, State) ->
- ?METHOD_SHOULD_NOT_BE_USED(handle_call, State).
-
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
init([]) ->
ok = schedule_first_production(),
Consumers = ordsets:new(),
- {ok, #state{consumers=Consumers}}.
+ StatsState = beam_stats_state:new(),
+ {ok, #state{consumers=Consumers, stats_state=StatsState}}.
handle_cast({subscribe, PID}, #state{consumers=Consumers1}=State) ->
Consumers2 = ordsets:add_element(PID, Consumers1),
Consumers2 = ordsets:del_element(PID, Consumers1),
{noreply, State#state{consumers=Consumers2}}.
-handle_info(?SIGNAL_PRODUCTION, #state{consumers=ConsumersSet}=State) ->
- ConsumersList = ordsets:to_list(ConsumersSet),
- ok = collect_and_push_to_consumers(ConsumersList),
+handle_call(?FORCE_PRODUCTION, _From, State1) ->
+ State2 = produce(State1),
+ {reply, {}, State2}.
+
+handle_info(?SIGNAL_PRODUCTION, #state{}=State1) ->
+ State2 = produce(State1),
ok = schedule_next_production(),
- {noreply, State}.
+ {noreply, State2}.
%% ============================================================================
%% Private
%% ============================================================================
+-spec produce(state()) ->
+ state().
+produce(#state{consumers=ConsumersSet, stats_state=StatsState1}=State) ->
+ StatsState2 = beam_stats_state:update(StatsState1),
+ Stats = beam_stats_state:export(StatsState2),
+ ConsumersList = ordsets:to_list(ConsumersSet),
+ ok = push_to_consumers(Stats, ConsumersList),
+ State#state{stats_state = StatsState2}.
+
-spec schedule_first_production() ->
ok.
schedule_first_production() ->
_ = erlang:send_after(ProductionInterval, self(), ?SIGNAL_PRODUCTION),
ok.
--spec collect_and_push_to_consumers([pid()]) ->
+-spec push_to_consumers(beam_stats:t(), [pid()]) ->
ok.
-collect_and_push_to_consumers(Consumers) ->
- BEAMStats = beam_stats:collect(),
- Push = fun (Consumer) -> gen_server:cast(Consumer, BEAMStats) end,
+push_to_consumers(Stats, Consumers) ->
+ Push = fun (Consumer) -> gen_server:cast(Consumer, Stats) end,
lists:foreach(Push, Consumers).