Skip to content

Instantly share code, notes, and snippets.

@msantos
Created April 13, 2010 00:50
Show Gist options
  • Save msantos/364193 to your computer and use it in GitHub Desktop.
Save msantos/364193 to your computer and use it in GitHub Desktop.
-module(health).
-behaviour(gen_server).
-export([start_link/0,
check/0, alert/0, dump/0,
threshold/1, poll/1, url/1
]).
-export([init/1, handle_call/3]).
-define(SERVER, ?MODULE).
-define(URL, "http://YOUR_HOSTNAME_HERE/nagios/cgi-bin/tac.cgi").
-define(LED, [
{critical, 1 bsl 2},
{warning, 1 bsl 3},
{unknown, 1 bsl 3},
{ok, 1 bsl 4},
{error, (1 bsl 5) - 1}
]
).
-record(threshold, {
critical = 0,
warning = 0,
unknown = 0
}).
-record(status, {
critical = 0,
warning = 0,
unknown = 0,
ok = 0
}).
-record(state, {
poll = false,
url = ?URL,
interval = 60 * 1000, % 1 minute
threshold = #threshold{},
serial,
current = ok,
status = #status{}
}).
alert() ->
gen_server:call(?SERVER, alert).
check() ->
gen_server:call(?SERVER, check).
dump() ->
gen_server:call(?SERVER, dump).
poll(true) ->
gen_server:call(?SERVER, {poll, true}),
health:check(),
health:alert();
poll(false) ->
gen_server:call(?SERVER, {poll, false}).
threshold(N) when tuple_size(N) =:= 3 ->
gen_server:call(?SERVER, #threshold{
critical = element(1,N),
warning = element(2,N),
unknown = element(3,N)
}).
url(N) when is_list(N) ->
gen_server:call(?SERVER, {url, N}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
inets:start(),
Pid = serial:start([{open, "/dev/ttyUSB0"}, {speed, 9600}]),
{ok, #state{serial = Pid, poll = true}}.
handle_call(check, _From, #state{interval = T} = State) ->
Status = try fetch(State) of
N ->
interval(State, ?SERVER, check),
N
catch
_:_ ->
interval(State#state{interval = T div 4}, ?SERVER, check),
error
end,
{reply, ok, State#state{status = Status}};
handle_call(alert, _From, State) ->
Status = alert(State),
led(Status, State),
interval(State, ?SERVER, alert),
{reply, ok, State#state{current = Status}};
handle_call(#threshold{} = N, _From, State) ->
{reply, ok, State#state{threshold = N}};
handle_call(dump, _From, State) ->
{reply, State, State};
handle_call({poll, N}, _From, State) ->
{reply, ok, State#state{poll = N}};
handle_call({url, N}, _From, State) ->
{reply, ok, State#state{url = N}}.
%%
%% Internal
%%
fetch(#state{url = URL}) ->
{ok, {{"HTTP/1.1",200,"OK"}, _Headers, Body}} = httpc:request(URL),
{match, Crit} = re:run(Body, "(\\d+)\\sCritical", [{capture, [1], binary}]),
{match, Warn} = re:run(Body, "(\\d+)\\sWarning", [{capture, [1], binary}]),
{match, Unk} = re:run(Body, "(\\d+)\\sUnknown", [{capture, [1], binary}]),
{match, Ok} = re:run(Body, "(\\d+)\\sOk", [{capture, [1], binary}]),
#status{
critical = b2i(Crit),
warning = b2i(Warn),
unknown = b2i(Unk),
ok = b2i(Ok)
}.
alert(#state{status = error}) ->
error;
alert(#state{status = S, threshold = T}) ->
Crit = S#status.critical,
Warn = S#status.warning,
Unk = S#status.unknown,
error_logger:info_report([
{crit, Crit, T#threshold.critical},
{warn, Warn, T#threshold.warning},
{unk, Unk, T#threshold.unknown}
]),
Status = try
threshold(critical, Crit, T#threshold.critical),
threshold(warning, Warn, T#threshold.warning),
threshold(unknown, Unk, T#threshold.unknown) of
_ -> ok
catch
throw:N -> N
end,
error_logger:info_report([{status, Status}]),
Status.
threshold(critical,N,T) when N > T -> throw(critical);
threshold(warning,N,T) when N > T -> throw(warning);
threshold(unknown,N,T) when N > T -> throw(unknown);
threshold(_,_,_) -> ok.
led(Status, #state{current = Status}) ->
ok;
led(Status, #state{serial = Serial}) ->
error_logger:info_report([{led, proplists:get_value(Status, ?LED)}]),
Serial ! {send, proplists:get_value(Status, ?LED)},
ok.
b2i([N]) when is_binary(N) ->
list_to_integer(binary_to_list(N)).
interval(State, M, F) ->
interval(State, M, F, []).
interval(#state{poll = true, interval = T}, M, F, A) ->
timer:apply_after(T, M, F, A);
interval(_, _, _, _) ->
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment