-
-
Save miebach/41c6ca270f280cf08306 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-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