Created
April 13, 2010 00:50
-
-
Save msantos/364193 to your computer and use it in GitHub Desktop.
This file contains hidden or 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