Permalink
Newer
Older
100644 108 lines (92 sloc) 4.06 KB
@ferd
Feb 27, 2012
1
%%% Main worker for vmstats. This module sits in a loop fired off with
2
%%% timers with the main objective of routinely sending data to
3
%%% statsderl.
4
-module(vmstats_server).
5
-behaviour(gen_server).
6
%% Interface
7
-export([start_link/1]).
8
%% Internal Exports
9
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
10
code_change/3, terminate/2]).
11
12
-define(TIMER_MSG, '#delay').
13
14
-record(state, {key :: string(),
15
sched_time :: enabled | disabled,
16
prev_sched :: [{integer(), integer(), integer()}],
@ferd
Feb 27, 2012
17
timer_ref :: reference(),
18
delay :: integer()}). % milliseconds
19
20
%%% INTERFACE
21
%% the base key is passed from the supervisor. This function
22
%% should not be called manually.
23
start_link(BaseKey) ->
24
gen_server:start_link({local, ?MODULE}, ?MODULE, BaseKey, []).
25
26
%%% INTERNAL EXPORTS
27
init(BaseKey) ->
28
{ok, Delay} = application:get_env(vmstats, delay),
29
Ref = erlang:start_timer(Delay, self(), ?TIMER_MSG),
30
try erlang:system_flag(scheduler_wall_time, true) of
31
_ ->
32
{ok, #state{key = [BaseKey,$.],
33
timer_ref = Ref,
34
delay = Delay,
35
sched_time = enabled,
36
prev_sched = lists:sort(erlang:statistics(scheduler_wall_time))}}
37
catch
38
error:badarg ->
39
{ok, #state{key = [BaseKey,$.],
40
timer_ref = Ref,
41
delay = Delay,
42
sched_time = disabled}}
43
end.
@ferd
Feb 27, 2012
44
45
handle_call(_Msg, _From, State) ->
46
{noreply, State}.
47
48
handle_cast(_Msg, State) ->
49
{noreply, State}.
50
51
handle_info({timeout, R, ?TIMER_MSG}, S = #state{key=K, delay=D, timer_ref=R}) ->
52
%% Processes
53
statsderl:increment([K,"proc_count"], erlang:system_info(process_count), 1.00),
54
statsderl:increment([K,"proc_limit"], erlang:system_info(process_limit), 1.00),
55
56
%% Modules loaded
57
statsderl:increment([K,"modules"], length(code:all_loaded()), 1.00),
58
59
%% Queued up processes (lower is better)
60
statsderl:increment([K,"run_queue"], erlang:statistics(run_queue), 1.00),
61
62
%% Error logger backlog (lower is better)
63
{_, MQL} = process_info(whereis(error_logger), message_queue_len),
64
statsderl:increment([K,"error_logger_queue_len"], MQL, 1.00),
65
66
%% Memory usage. There are more options available, but not all were kept.
67
%% Memory usage is in bytes.
68
K2 = [K,"memory."],
69
Mem = erlang:memory(),
70
statsderl:increment([K2,"total"], proplists:get_value(total, Mem), 1.00),
71
statsderl:increment([K2,"procs_used"], proplists:get_value(processes_used,Mem), 1.00),
72
statsderl:increment([K2,"atom_used"], proplists:get_value(atom_used,Mem), 1.00),
73
statsderl:increment([K2,"binary"], proplists:get_value(binary, Mem), 1.00),
74
statsderl:increment([K2,"ets"], proplists:get_value(ets, Mem), 1.00),
75
76
%% Scheduler wall time
77
#state{sched_time=Sched, prev_sched=PrevSched} = S,
78
case Sched of
79
enabled ->
80
NewSched = lists:sort(erlang:statistics(scheduler_wall_time)),
81
[begin
82
SSid = integer_to_list(Sid),
83
statsderl:timing([K,"scheduler_wall_time.",SSid,".active"], Active, 1.00),
84
statsderl:timing([K,"scheduler_wall_time.",SSid,".total"], Total, 1.00)
85
end
86
|| {Sid, Active, Total} <- wall_time_diff(PrevSched, NewSched)],
87
{noreply, S#state{timer_ref=erlang:start_timer(D, self(), ?TIMER_MSG),
88
prev_sched=NewSched}};
89
disabled ->
90
{noreply, S#state{timer_ref=erlang:start_timer(D, self(), ?TIMER_MSG)}}
91
end;
92
handle_info(_Msg, {state, _Key, _TimerRef, _Delay}) ->
93
exit(forced_upgrade_restart);
@ferd
Feb 27, 2012
94
handle_info(_Msg, State) ->
95
{noreply, State}.
96
97
code_change(_OldVsn, State, _Extra) ->
98
{ok, State}.
99
100
terminate(_Reason, _State) ->
101
ok.
102
103
%% Returns the two timeslices as a ratio of each other,
104
%% as a percentage so that StatsD gets to print something > 1
105
wall_time_diff(T1, T2) ->
106
[{I, Active2-Active1, Total2-Total1}
107
|| {{I, Active1, Total1}, {I, Active2, Total2}} <- lists:zip(T1,T2)].