├── erlmon-1.0 ├── build │ └── .gitignore ├── lib │ └── .gitignore ├── .gitignore ├── c_src │ ├── .gitignore │ ├── erlua.h │ ├── erlua.c │ ├── commands.h │ └── commands.c ├── include │ ├── lua.hrl │ ├── config.hrl │ ├── debug.hrl │ ├── erlmon.hrl │ └── lua_api.hrl ├── sys.config ├── wwwroot │ ├── nitrogen │ │ ├── nitrogen.css │ │ ├── gray_bl.png │ │ ├── gray_br.png │ │ ├── gray_tl.png │ │ ├── gray_tr.png │ │ ├── spinner.gif │ │ ├── black_bl.png │ │ ├── black_br.png │ │ ├── black_tl.png │ │ ├── black_tr.png │ │ ├── checkmark.png │ │ ├── flash_bg.png │ │ ├── spinner2.gif │ │ ├── white_bl.png │ │ ├── white_br.png │ │ ├── white_tl.png │ │ ├── white_tr.png │ │ ├── jquery-ui │ │ │ └── images │ │ │ │ ├── ui-icons_222222_256x240.png │ │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ │ ├── ui-icons_454545_256x240.png │ │ │ │ ├── ui-icons_888888_256x240.png │ │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ ├── reset.css │ │ ├── facebox.css │ │ ├── basic.css │ │ ├── elements.css │ │ ├── web_app_theme.css │ │ ├── facebox.js │ │ ├── livevalidation.js │ │ └── style.css │ └── template.html ├── lua │ ├── authentication.lua │ ├── monitors │ │ ├── loopback.lua │ │ ├── port.lua │ │ ├── file.lua │ │ ├── process.lua │ │ └── monitors.lua │ ├── smtp.lua │ ├── tests.lua │ ├── erlmon.lua │ ├── lunit │ └── lunit-console.lua ├── src │ ├── debug_console.erl │ ├── erlmon_helper.erl │ ├── debug_file.erl │ ├── pages │ │ ├── erlmon_index.erl │ │ ├── helper.erl │ │ ├── login.erl │ │ ├── web_index.erl │ │ ├── web_config.erl │ │ └── web_node.erl │ ├── state_mon_sup.erl │ ├── config_sup.erl │ ├── erlmon_smtp_sup.erl │ ├── disk_monitor_sup.erl │ ├── process_list_sup.erl │ ├── node_down_handler.erl │ ├── node_sup.erl │ ├── lua_driver.erl │ ├── storage_sup.erl │ ├── config_file_change_handler.erl │ ├── state_change_handler.erl │ ├── timestamp.erl │ ├── file_monitor_sup.erl │ ├── state_change_em.erl │ ├── process_monitor_sup.erl │ ├── tcp_port_monitor_sup.erl │ ├── erlmon_sup.erl │ ├── erlmon_smtp_message.erl │ ├── email_msg.erl │ ├── monitor_sup.erl │ ├── state_change_sup.erl │ ├── erlmon.erl │ ├── df.erl │ ├── file_monitor_man.erl │ ├── erlwww_app.erl │ ├── debug.erl │ ├── process_monitor_man.erl │ ├── tcp_port_monitor_man.erl │ ├── disk_monitor.erl │ ├── tcp_port_monitor.erl │ ├── ps.erl │ ├── alert_handler.erl │ ├── process_list.erl │ ├── storage.erl │ ├── state_change.erl │ ├── process_monitor.erl │ ├── config.erl │ ├── erlmon_smtp.erl │ ├── node.erl │ ├── file_monitor.erl │ └── lua.erl ├── erlmon ├── ebin │ ├── erlmon.app │ └── erlwww.app ├── Emakefile ├── Makefile ├── config.lua ├── Rakefile ├── Makefile.Linux ├── Makefile.Darwin ├── config.example.lua └── tests │ └── lua_test.erl ├── .gitignore ├── LICENSE └── README /erlmon-1.0/build/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /erlmon-1.0/lib/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /erlmon-1.0/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | -------------------------------------------------------------------------------- /erlmon-1.0/c_src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | -------------------------------------------------------------------------------- /erlmon-1.0/include/lua.hrl: -------------------------------------------------------------------------------- 1 | -record(lua, {port}). 2 | 3 | -define(STD_TIMEOUT, 100). -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.beam 2 | *.log 3 | */src/test.erl 4 | *.dump 5 | */Mnesia* 6 | *.sw? 7 | *.so 8 | -------------------------------------------------------------------------------- /erlmon-1.0/include/config.hrl: -------------------------------------------------------------------------------- 1 | %% config state 2 | -record(config_state,{status={},lua_state=none}). 3 | -------------------------------------------------------------------------------- /erlmon-1.0/sys.config: -------------------------------------------------------------------------------- 1 | [{kernel, [{inet_dist_listen_min, 9500}, {inet_dist_listen_max, 9505}]}]. 2 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/nitrogen.css: -------------------------------------------------------------------------------- 1 | @import url(reset.css); 2 | @import url(basic.css); 3 | @import url(elements.css); -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/gray_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/gray_bl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/gray_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/gray_br.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/gray_tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/gray_tl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/gray_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/gray_tr.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/spinner.gif -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/black_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/black_bl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/black_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/black_br.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/black_tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/black_tl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/black_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/black_tr.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/checkmark.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/flash_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/flash_bg.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/spinner2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/spinner2.gif -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/white_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/white_bl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/white_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/white_br.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/white_tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/white_tl.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/white_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/white_tr.png -------------------------------------------------------------------------------- /erlmon-1.0/lua/authentication.lua: -------------------------------------------------------------------------------- 1 | 2 | function authenticate(login,password) 3 | return Erlmon.http.login == login and Erlmon.http.password == password 4 | end 5 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /erlmon-1.0/src/debug_console.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(debug_console). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([log/3]). 6 | 7 | log(Format, Args, _Options) -> 8 | io:format(Format ++ "~n", Args). 9 | 10 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrikmazey/erlmon/HEAD/erlmon-1.0/wwwroot/nitrogen/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /erlmon-1.0/erlmon: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z $1 ]; then 3 | erl -pa ebin/ -config sys -name erlmon -eval "application:start(erlmon)." 4 | else 5 | erl -pa ebin/ -s erlmon -config sys -name $1 -eval "application:start(erlmon)." 6 | fi 7 | -------------------------------------------------------------------------------- /erlmon-1.0/ebin/erlmon.app: -------------------------------------------------------------------------------- 1 | {application, erlmon, 2 | [{description, "erlang monitoring system"}, 3 | {vsn, "1.0"}, 4 | {modules, [erlmon]}, 5 | {registered, []}, 6 | {applications, [kernel, stdlib]}, 7 | {env, []}, 8 | {mod, {erlmon, []}}]}. 9 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon_helper.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon_helper). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([ 6 | list_to_number/1 7 | ]). 8 | 9 | list_to_number(L) -> 10 | try list_to_float(L) of 11 | N -> N 12 | catch 13 | _:_ -> list_to_integer(L) 14 | end. 15 | -------------------------------------------------------------------------------- /erlmon-1.0/include/debug.hrl: -------------------------------------------------------------------------------- 1 | 2 | % log message 3 | -record(debug_log_msg, { sender, format, args = [] }). 4 | 5 | % add logmethod 6 | -record(debug_log_add_method, { sender, module, options }). 7 | 8 | % remove logmethod 9 | -record(debug_log_rem_method, { sender, module, options }). 10 | 11 | -------------------------------------------------------------------------------- /erlmon-1.0/ebin/erlwww.app: -------------------------------------------------------------------------------- 1 | {application, erlwww, [ 2 | {description, "Nitrogen Website"}, 3 | {mod, {erlwww_app, []}}, 4 | {env, [ 5 | {platform, mochiweb}, %% {inets|yaws|mochiweb} 6 | %%{port, 8000}, 7 | {session_timeout, 20}, 8 | {sign_key, "SIGN_KEY"}, 9 | {www_root, "./wwwroot"} 10 | ]} 11 | ]}. 12 | -------------------------------------------------------------------------------- /erlmon-1.0/Emakefile: -------------------------------------------------------------------------------- 1 | { './src/*', [ 2 | { i, "./include" }, 3 | { outdir, "./ebin" }, 4 | debug_info 5 | ]}. 6 | 7 | { './src/*/*', [ 8 | { i, "./include" }, 9 | { outdir, "./ebin" }, 10 | debug_info 11 | ]}. 12 | 13 | { './src/*/*/*', [ 14 | { i, "./include" }, 15 | { outdir, "./ebin" }, 16 | debug_info 17 | ]}. 18 | -------------------------------------------------------------------------------- /erlmon-1.0/src/debug_file.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(debug_file). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([log/3]). 6 | 7 | log(Format, Args, Options) -> 8 | {filename, Filename} = Options, 9 | {ok, WD} = file:open(Filename, [append]), 10 | io:format(WD, Format ++ "~n", Args), 11 | file:close(WD), 12 | true. 13 | 14 | 15 | -------------------------------------------------------------------------------- /erlmon-1.0/Makefile: -------------------------------------------------------------------------------- 1 | 2 | OS = $(shell uname) 3 | 4 | .PHONY: all clean test 5 | 6 | all: 7 | $(MAKE) -f Makefile.$(OS) 8 | 9 | clean: 10 | $(MAKE) -f Makefile.$(OS) clean 11 | 12 | test: 13 | $(MAKE) -f Makefile.$(OS) test 14 | 15 | runtests: 16 | erlc tests/* && erl -pa ebin -s lua_test test -noshell -s init stop 17 | 18 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/erlmon_index.erl: -------------------------------------------------------------------------------- 1 | -module (erlmon_index). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | main() -> 6 | #template { file="./wwwroot/template.html"}. 7 | 8 | title() -> 9 | "erlmon index". 10 | 11 | body() -> 12 | #label{text="web_index body."}. 13 | 14 | event(_) -> ok. 15 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/helper.erl: -------------------------------------------------------------------------------- 1 | -module (helper). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | menu(MenuItems) -> 6 | Items = lists:map(fun({_Name,Text,Url}) -> 7 | ["
  • ",wf:f("~s",[Url,Text]),"",Items,""]. 9 | 10 | flash_msg(Error) -> wf:flash( #label { text= Error } ). 11 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/monitors/loopback.lua: -------------------------------------------------------------------------------- 1 | 2 | -- "loopback" Monitor 3 | -- monitor for unit tests 4 | -- if they are functions they will be called as necessary. 5 | -- by default, restart simply calls stop, then start 6 | function monitor_loopback(name,cmd) 7 | 8 | Erlmon.monitors.add("loopback",name,cmd) 9 | 10 | end 11 | 12 | function unmonitor_loopback(name) 13 | Erlmon.monitors.remove("loopback",name) 14 | end 15 | 16 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/smtp.lua: -------------------------------------------------------------------------------- 1 | 2 | function _add_smtp(host) 3 | local smtp = {} 4 | host.smtp = smtp 5 | smtp.auth = {} 6 | 7 | smtp.address = "" 8 | smtp.host = "localhost" 9 | smtp.port = 25 10 | smtp.auth.type = 'none' 11 | smtp.auth.username = '' 12 | smtp.auth.password = '' 13 | 14 | end 15 | 16 | -- convenience function if you just want to set a 17 | -- global alert address. 18 | function alert(address) 19 | Erlmon.smtp.address = address 20 | end 21 | -------------------------------------------------------------------------------- /erlmon-1.0/src/state_mon_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(state_mon_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 12 | 13 | init(_) -> 14 | debug:log("state_mon_sup: starting state_mon"), 15 | Child = {state_mon, {state_mon, start, []}, permanent, 2000, worker, [state_mon]}, 16 | {ok, {{one_for_one, 1, 1}, [Child]}}. 17 | -------------------------------------------------------------------------------- /erlmon-1.0/config.lua: -------------------------------------------------------------------------------- 1 | -- this require isn't specifically required as it will be added 2 | -- when executed inside of erlmon, but they are necessary to 3 | -- test the file on the command line, by typing lua config.lua 4 | require "lua/erlmon" 5 | 6 | -- Global Erlmon Settings 7 | Erlmon.http.login = 'admin' 8 | Erlmon.http.password = 'admin' 9 | 10 | Erlmon.smtp.host = "mail.foo.com" 11 | 12 | -- Global SMTP Settings 13 | alert("chad@foo.com") 14 | 15 | -- Monitors 16 | monitor_port(11211) 17 | 18 | -------------------------------------------------------------------------------- /erlmon-1.0/src/config_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(config_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("config_sup: starting config"), 17 | Child = {config, {config, start_link, []}, permanent, 2000, worker, [config]}, 18 | {ok, {{one_for_one, 1, 1}, [Child]}}. 19 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon_smtp_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon_smtp_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("erlmon_smtp_sup: starting"), 17 | GChild = {erlmon_smtp, {erlmon_smtp, start_link, []}, permanent, 2000, worker, [erlmon_smtp]}, 18 | {ok, {{one_for_one, 1, 1}, [GChild]}}. 19 | -------------------------------------------------------------------------------- /erlmon-1.0/src/disk_monitor_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(disk_monitor_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("disk_monitor_sup: starting"), 17 | DMSChild = {disk_monitor, {disk_monitor, start, []}, temporary, brutal_kill, worker, [disk_monitor]}, 18 | {ok, {{simple_one_for_one, 0, 1}, [DMSChild]}}. 19 | -------------------------------------------------------------------------------- /erlmon-1.0/src/process_list_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(process_list_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("process_list_sup: starting process_list"), 17 | Child = {process_list, {process_list, start_link, []}, permanent, 2000, worker, [process_list]}, 18 | {ok, {{one_for_one, 1, 1}, [Child]}}. 19 | -------------------------------------------------------------------------------- /erlmon-1.0/src/node_down_handler.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(node_down_handler). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(gen_event). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([init/1]). 10 | -export([handle_event/2]). 11 | -export([terminate/2]). 12 | 13 | init(_) -> 14 | {ok, []}. 15 | 16 | handle_event(#state_change{objtype=node, new_state=down}=Event, State) -> 17 | debug:log("node_down_handler: ~p", [Event]), 18 | {ok, State}; 19 | handle_event(_Event, State) -> 20 | {ok, State}. 21 | 22 | terminate(_Args, _State) -> 23 | ok. 24 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/monitors/port.lua: -------------------------------------------------------------------------------- 1 | -- Port Monitoring 2 | function _add_monitor_port_function(host_monitors) 3 | host_monitors.monitor_port = function(hostorport,port,options) 4 | if port == nil then 5 | port = hostorport 6 | hostorport = 'localhost' 7 | end 8 | if options == nil then 9 | options = {} 10 | end 11 | 12 | options.host = hostorport 13 | options.port = port 14 | 15 | -- 'tcp_port' becuase must match erlang monitor name 16 | return host_monitors.add("tcp_port",nil,options) 17 | end 18 | end 19 | 20 | -------------------------------------------------------------------------------- /erlmon-1.0/src/node_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(node_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | wait_for_node(), 13 | erlmon:finished(?MODULE), 14 | R. 15 | 16 | init(_) -> 17 | debug:log("node_sup: starting node"), 18 | Child = {node, {node, start, []}, permanent, 2000, worker, [node]}, 19 | {ok, {{one_for_one, 1, 1}, [Child]}}. 20 | 21 | wait_for_node() -> 22 | node:status(). 23 | -------------------------------------------------------------------------------- /erlmon-1.0/src/lua_driver.erl: -------------------------------------------------------------------------------- 1 | -module(lua_driver). 2 | 3 | -export([open/0, close/1]). 4 | 5 | -include("lua.hrl"). 6 | 7 | open() -> 8 | {ok, L} = load_driver(), 9 | #lua{port=L}. 10 | 11 | close(#lua{port=Port}) -> 12 | port_close(Port). 13 | 14 | 15 | %% Private functions 16 | load_driver() -> 17 | SearchDir = filename:join([filename:dirname(code:which(lua_driver)), "..", "lib"]), 18 | case erl_ddll:load(SearchDir, liberlua) of 19 | ok -> 20 | {ok, open_port({spawn, 'liberlua'}, [binary])}; 21 | Error -> 22 | Error 23 | end. 24 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/monitors/file.lua: -------------------------------------------------------------------------------- 1 | -- File Monitor 2 | -- To write a monitor, you must implement the monitor_X method, 3 | -- where X is the name of the monitor. 4 | 5 | function monitor_file(name,startcmd,stopcmd,restartcmd) 6 | 7 | -- we need a table with the commands, so build from parameters 8 | -- if needed 9 | if not (type(startcmd) == "table") then 10 | startcmd = { start = startcmd, 11 | stop = stopcmd, 12 | restart = restartcmd } 13 | end 14 | 15 | Erlmon.monitors.add("file",name,startcmd) 16 | 17 | end 18 | 19 | 20 | -------------------------------------------------------------------------------- /erlmon-1.0/src/storage_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(storage_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | wait_for_storage(), 13 | erlmon:finished(?MODULE), 14 | R. 15 | 16 | init(_) -> 17 | debug:log("storage_sup: starting storage"), 18 | Child = {storage, {storage, start, []}, permanent, 2000, worker, [storage]}, 19 | {ok, {{one_for_one, 1, 1}, [Child]}}. 20 | 21 | wait_for_storage() -> 22 | storage:status(). 23 | -------------------------------------------------------------------------------- /erlmon-1.0/src/config_file_change_handler.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(config_file_change_handler). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(gen_event). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([init/1]). 10 | -export([handle_event/2]). 11 | -export([terminate/2]). 12 | 13 | init(_) -> 14 | {ok, []}. 15 | 16 | handle_event(#state_change{objtype=file, obj="config.lua", new_state=file_ctime_changed}=Event, State) -> 17 | debug:log("CONFIG FILE CHANGED: ~p", [Event]), 18 | config:reload(), 19 | {ok, State}; 20 | handle_event(_Event, State) -> 21 | {ok, State}. 22 | 23 | terminate(_Args, _State) -> 24 | ok. 25 | -------------------------------------------------------------------------------- /erlmon-1.0/src/state_change_handler.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(state_change_handler). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(gen_event). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([init/1]). 10 | -export([handle_event/2]). 11 | -export([terminate/2]). 12 | 13 | init(_) -> 14 | {ok, []}. 15 | 16 | handle_event(#state_change{}=Event, State) -> 17 | debug:log("state_change_handler:state_change: ~p", [Event]), 18 | storage:state_change(Event), 19 | {ok, State}; 20 | handle_event(Event, State) -> 21 | debug:log("state_change_handler:UNKNOWN_EVENT: ~p", [Event]), 22 | {ok, State}. 23 | 24 | terminate(_Args, _State) -> 25 | ok. 26 | -------------------------------------------------------------------------------- /erlmon-1.0/src/timestamp.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(timestamp). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([now/0]). 6 | -export([now_i/0]). 7 | 8 | now() -> 9 | {Date, Time} = calendar:local_time(), 10 | {Y, M, D} = Date, 11 | {Hours, Mins, Secs} = Time, 12 | lists:flatten(io_lib:format("~4.4.0s~s~2.1.0s~s~2.1.0s~s~2.1.0s~s~2.1.0s~s~2.1.0s", 13 | [ integer_to_list(Y), 14 | ".", 15 | integer_to_list(M), 16 | ".", 17 | integer_to_list(D), 18 | " ", 19 | integer_to_list(Hours), 20 | ":", 21 | integer_to_list(Mins), 22 | ":", 23 | integer_to_list(Secs) ])). 24 | 25 | now_i() -> 26 | {_, T, _} = erlang:now(), 27 | T. 28 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/tests.lua: -------------------------------------------------------------------------------- 1 | require "lunit" 2 | require "erlmon" 3 | 4 | module( "erlmon_tests", lunit.testcase, package.seeall) 5 | 6 | -- monitor infrastructure basics 7 | function test_monitors() 8 | assert(not (Erlmon.monitors == nil)) 9 | assert(type(Erlmon.monitors.list) == "table") 10 | assert(type(Erlmon.monitors.add) == "function") 11 | assert(type(Erlmon.monitors.remove) == "function") 12 | end 13 | 14 | function test_http_config() 15 | assert(Erlmon.http.enabled) 16 | assert(Erlmon.http.port == 9494) 17 | end 18 | 19 | function test_port_monitor() 20 | monitor_port(22) 21 | monitor_port("localhost",22) 22 | print(Erlmon.monitors.list) 23 | assert(#Erlmon.monitors.list == 2,#Erlmon.monitors.list) 24 | end 25 | 26 | 27 | -------------------------------------------------------------------------------- /erlmon-1.0/Rakefile: -------------------------------------------------------------------------------- 1 | task :default => [:make_c, :make_erl] 2 | 3 | task :test => [:default, :make_tests] do 4 | sh "erl -pa ebin -noshell -s lua_test test -s init stop" 5 | sh "cd lua && ./lunit tests.lua" 6 | end 7 | 8 | task :clean do 9 | print "Cleaning..." 10 | sh "make clean" 11 | sh "rm priv/*.so" 12 | print " done\n" 13 | end 14 | 15 | task :make_c do 16 | sh "(cd c_src; rake compile)" 17 | end 18 | 19 | task :make_erl do 20 | print "Compiling Erlang sources..." 21 | sh "make" 22 | print "... done\n" 23 | end 24 | 25 | task :make_tests => :default do 26 | print "Compiling Erlang test sources..." 27 | sh "erlc -Iinclude/ -o ebin/ tests/*.erl" 28 | print "... done\n" 29 | end 30 | 31 | task :run do 32 | sh "erl -pa ebin" 33 | end 34 | -------------------------------------------------------------------------------- /erlmon-1.0/src/file_monitor_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(file_monitor_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | -export([monitor/1]). 10 | -export([unmonitor/1]). 11 | 12 | monitor(Path) -> 13 | supervisor:start_child(file_monitor_sup, [Path]). 14 | 15 | unmonitor(Path) -> 16 | supervisor:terminate_child(file_monitor_sup, [Path]). 17 | 18 | start_link() -> 19 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 20 | erlmon:finished(?MODULE), 21 | R. 22 | 23 | init(_) -> 24 | debug:log("file_monitor_sup: starting"), 25 | FMSChild = {file_monitor, {file_monitor, start, []}, temporary, brutal_kill, worker, [file_monitor]}, 26 | {ok, {{simple_one_for_one, 0, 1}, [FMSChild]}}. 27 | -------------------------------------------------------------------------------- /erlmon-1.0/src/state_change_em.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(state_change_em). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start_link/0]). 6 | -export([add_handler/1]). 7 | -export([add_handler/2]). 8 | -export([notify/1]). 9 | -export([stop/0]). 10 | 11 | -define(SERVER, ?MODULE). 12 | 13 | start_link() -> 14 | debug:log("state_change_em: starting"), 15 | R = gen_event:start_link({local, ?SERVER}), 16 | erlmon:finished(?MODULE), 17 | R. 18 | 19 | add_handler(Module) -> 20 | gen_event:add_handler(?SERVER, Module, []). 21 | 22 | add_handler(Module, State) -> 23 | gen_event:add_handler(?SERVER, Module, State). 24 | 25 | notify(Event) -> 26 | gen_event:notify(?SERVER, Event). 27 | 28 | stop() -> 29 | debug:log("state_change_em: stopping"), 30 | gen_event:stop(?SERVER). 31 | 32 | -------------------------------------------------------------------------------- /erlmon-1.0/Makefile.Linux: -------------------------------------------------------------------------------- 1 | ERL_LIB=/usr/lib/erlang/lib/erl_interface-3.6.3 2 | CFLAGS=-Wall -I/usr/local/include -I$(ERL_LIB)/include -I/usr/lib/erlang/usr/include 3 | LDFLAGS=-shared -L. -L$(ERL_LIB)/lib 4 | LDLIBS=-llua 5 | STATICLIBS=$(ERL_LIB)/lib/libei.a $(ERL_LIB)/lib/liberl_interface.a 6 | GCC=/usr/bin/gcc 7 | ERL=/usr/bin/erl 8 | 9 | LIB=lib/liberlua.so 10 | 11 | ERLMODS=$(patsubst src/%.erl,ebin/%.beam,$(wildcard src/*.erl)) 12 | OBJECTS=$(patsubst c_src/%.c,build/%.o,$(wildcard c_src/*.c)) 13 | 14 | all: $(LIB) $(ERLMODS) 15 | 16 | build/%.o: c_src/%.c 17 | $(GCC) $(CFLAGS) -o $@ -c $< 18 | 19 | ebin/%.beam: src/%.erl 20 | $(ERL) -make 21 | 22 | $(LIB): $(OBJECTS) 23 | $(GCC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $(LIB) $(OBJECTS) $(STATICLIBS) 24 | 25 | clean: 26 | rm -f ebin/*.beam 27 | rm -f build/*.o 28 | rm -f lib/liberlua.so 29 | -------------------------------------------------------------------------------- /erlmon-1.0/src/process_monitor_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(process_monitor_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | -export([monitor/1]). 10 | -export([unmonitor/1]). 11 | 12 | monitor(ProcessName) -> 13 | debug:log("process_monitor_sup:monitor(~p)", [ProcessName]), 14 | supervisor:start_child(process_monitor_sup, [ProcessName]). 15 | 16 | unmonitor(ProcessName) -> 17 | supervisor:terminate_child(tcp_port_monitor_sup, [ProcessName]). 18 | 19 | start_link() -> 20 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 21 | erlmon:finished(?MODULE), 22 | R. 23 | 24 | init(_) -> 25 | debug:log("process_monitor_sup: starting"), 26 | TPMChild = {process_monitor, {process_monitor, start, []}, temporary, brutal_kill, worker, [process_monitor]}, 27 | {ok, {{simple_one_for_one, 0, 1}, [TPMChild]}}. 28 | -------------------------------------------------------------------------------- /erlmon-1.0/src/tcp_port_monitor_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(tcp_port_monitor_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | -export([monitor/2]). 10 | -export([unmonitor/2]). 11 | 12 | monitor(Host, Port) -> 13 | debug:log("tcp_port_monitor_sup:monitor(~p, ~p)", [Host, Port]), 14 | supervisor:start_child(tcp_port_monitor_sup, [Host, Port]). 15 | 16 | unmonitor(Host, Port) -> 17 | supervisor:terminate_child(tcp_port_monitor_sup, [Host, Port]). 18 | 19 | start_link() -> 20 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 21 | erlmon:finished(?MODULE), 22 | R. 23 | 24 | init(_) -> 25 | debug:log("tcp_port_monitor_sup: starting"), 26 | TPMChild = {tcp_port_monitor, {tcp_port_monitor, start, []}, temporary, brutal_kill, worker, [tcp_port_monitor]}, 27 | {ok, {{simple_one_for_one, 0, 1}, [TPMChild]}}. 28 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/monitors/process.lua: -------------------------------------------------------------------------------- 1 | 2 | -- Monitors 3 | -- To write a monitor, you must implement the monitor_X method, 4 | -- where X is the name of the monitor. 5 | 6 | -- $TODO should this be a macro? 7 | start = "start" 8 | stop = "stop" 9 | restart = "restart" 10 | 11 | -- Process Monitoring 12 | -- if start/stop/restart are strings, they will be executed as system commands 13 | -- if they are functions they will be called as necessary. 14 | -- by default, restart simply calls stop, then start 15 | function monitor_process(name,startcmd,stopcmd,restartcmd) 16 | 17 | -- we need a table with the commands, so build from parameters 18 | -- if needed 19 | if not (type(startcmd) == "table") then 20 | startcmd = { start = startcmd, 21 | stop = stopcmd, 22 | restart = restartcmd } 23 | end 24 | 25 | Erlmon.monitors.add("process",name,startcmd) 26 | 27 | end 28 | 29 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/login.erl: -------------------------------------------------------------------------------- 1 | -module (login). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | main() -> 6 | #template { file="./wwwroot/template.html"}. 7 | 8 | title() -> 9 | "erlmon login.". 10 | 11 | body() -> 12 | [#h1{text = "Login to erlmon." }, 13 | #label { text="Login:"}, 14 | #textbox { id=login, text="", next=password }, 15 | #label { text="Password:"}, 16 | #password { id=password}, 17 | #p{}, 18 | #button { text="Login", postback={click, login_button} } 19 | ]. 20 | 21 | event(_) -> 22 | [Login] = wf:q(login), 23 | [Password] = wf:q(password), 24 | case config:authenticate(Login,Password) of 25 | true -> wf:user(admin), 26 | wf:redirect_from_login("/"); 27 | false -> helper:flash_msg("Invalid login or password.") 28 | end. 29 | 30 | 31 | menu_items() -> helper:menu([{login,"login","/web/login"}]). 32 | 33 | -------------------------------------------------------------------------------- /erlmon-1.0/Makefile.Darwin: -------------------------------------------------------------------------------- 1 | ERL_LIB=/opt/local/lib/erlang/lib/erl_interface-3.6.4 2 | CFLAGS=-Wall -I/opt/local/include -I$(ERL_LIB)/include -I/opt/local/lib/erlang/usr/include -I /LuaLibrary/src 3 | LDFLAGS=-dynamic -bundle -undefined suppress -flat_namespace -L. -L$(ERL_LIB)/lib 4 | LDLIBS= 5 | STATICLIBS=$(ERL_LIB)/lib/libei.a $(ERL_LIB)/lib/liberl_interface.a /usr/local/lib/liblua.a 6 | GCC=/usr/bin/gcc 7 | ERL=/opt/local/bin/erl 8 | 9 | LIB=lib/liberlua.so 10 | 11 | ERLMODS=$(patsubst src/%.erl,ebin/%.beam,$(wildcard src/*.erl)) 12 | OBJECTS=$(patsubst c_src/%.c,build/%.o,$(wildcard c_src/*.c)) 13 | 14 | all: $(LIB) $(ERLMODS) 15 | 16 | build/%.o: c_src/%.c 17 | $(GCC) $(CFLAGS) -o $@ -c $< 18 | 19 | ebin/%.beam: src/%.erl 20 | $(ERL) +debug_info -make 21 | 22 | $(LIB): $(OBJECTS) 23 | $(GCC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $(LIB) $(OBJECTS) $(STATICLIBS) 24 | 25 | clean: 26 | rm -f ebin/*.beam 27 | rm -f build/*.o 28 | rm -f lib/liberlua.so 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2010 DarmaSoft, LLC. 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/erlmon.lua: -------------------------------------------------------------------------------- 1 | 2 | -- helper functions for monitors 3 | 4 | -- load monitors 5 | require "lua/monitors/monitors" 6 | require "lua/smtp" 7 | 8 | function _add_host(name) 9 | local host = {} 10 | local mt = {} 11 | mt.__index = function (table, key) 12 | return Erlmon[key] 13 | end 14 | mt.__newindex = function (table, key) 15 | return Erlmon[key] 16 | end 17 | setmetatable(host,mt) 18 | Erlmon.hosts[name] = host 19 | return host 20 | end 21 | 22 | function _erlmon() 23 | 24 | -- HTTP Console defaults 25 | local http = {} 26 | http.enabled=true 27 | http.port = 9494 28 | 29 | -- Monitors 30 | local monitors = {} 31 | _add_monitors(monitors) 32 | 33 | 34 | -- Globals 35 | local erlmon = {} 36 | erlmon.http = http 37 | erlmon.monitors = monitors 38 | erlmon.alert = alert 39 | erlmon.add_host = _add_host 40 | erlmon.hosts = {} 41 | 42 | -- Simple SMTP Alerting 43 | _add_smtp(erlmon) 44 | 45 | return erlmon 46 | 47 | end 48 | 49 | Erlmon = _erlmon() 50 | 51 | _add_convenience_monitor_functions() 52 | 53 | -- redefine the method in your config file if you want 54 | -- to have your own authentication 55 | require "lua/authentication" 56 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/monitors/monitors.lua: -------------------------------------------------------------------------------- 1 | -- if LuaFileSystem is OK as a dependency, we wouldn't have 2 | -- to specify the modules here 3 | --require "lua/monitors/file" 4 | --require "lua/monitors/process" 5 | --require "lua/monitors/loopback" 6 | require "lua/monitors/port" 7 | 8 | function _add_monitors(host_monitors) 9 | 10 | mlist = {} 11 | host_monitors.list = mlist 12 | 13 | host_monitors.add = function(mtype,name,init) 14 | -- create table if this is the first monitor of this type 15 | if mlist[mtype] == nil then mlist[mtype] = {} end 16 | 17 | -- you don't have to name your monitors 18 | -- but we should probably hash them 19 | if name == nil then 20 | table.insert(mlist[mtype],init) 21 | else 22 | mlist[mtype][name] = init 23 | end 24 | 25 | return init 26 | end 27 | 28 | host_monitors.remove = function(mtype,name) 29 | if mlist[mtype] == nil then mlist[mtype] = {} end 30 | mlist[mtype][name] = nil 31 | end 32 | 33 | _add_monitor_port_function(host_monitors) 34 | end 35 | 36 | -- allows monitor_x instead of Erlmon.monitors 37 | function _add_convenience_monitor_functions() 38 | monitor_port = Erlmon.monitors.monitor_port 39 | end 40 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("erlmon_sup: starting"), 17 | SMChild = { state_change_sup, {state_change_sup, start_link, []}, permanent, 2000, supervisor, [state_change_sup]}, 18 | SChild = { storage_sup, {storage_sup, start_link, []}, permanent, 2000, supervisor, [storage_sup]}, 19 | NChild = { node_sup, {node_sup, start_link, []}, permanent, 2000, supervisor, [node_sup]}, 20 | PLChild = { process_list_sup, {process_list_sup, start_link, []}, permanent, 2000, supervisor, [process_list_sup]}, 21 | MSChild = { monitor_sup, {monitor_sup, start_link, []}, permanent, 2000, supervisor, [monitor_sup]}, 22 | CChild = { config_sup, {config_sup, start_link, []}, permanent, 2000, worker, [config_sup]}, 23 | SGChild = { erlmon_smtp_sup, {erlmon_smtp_sup, start_link, []}, permanent, 2000, supervisor, [erlmon_smtp_sup]}, 24 | {ok, {{one_for_one, 1, 1}, [SMChild, SChild, NChild, PLChild, MSChild, CChild, SGChild]}}. 25 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/reset.css: -------------------------------------------------------------------------------- 1 | /* v1.0 | 20080212 */ 2 | 3 | html, body, div, span, applet, object, iframe, 4 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 5 | a, abbr, acronym, address, big, cite, code, 6 | del, dfn, em, font, img, ins, kbd, q, s, samp, 7 | small, strike, strong, sub, sup, tt, var, 8 | b, u, i, center, 9 | dl, dt, dd, ol, ul, li, 10 | fieldset, form, label, legend, 11 | table, caption, tbody, tfoot, thead, tr, th, td { 12 | margin: 0; 13 | padding: 0; 14 | border: 0; 15 | outline: 0; 16 | font-size: 100%; 17 | vertical-align: baseline; 18 | background: transparent; 19 | } 20 | body { 21 | line-height: 1; 22 | } 23 | ol, ul { 24 | list-style: none; 25 | } 26 | blockquote, q { 27 | quotes: none; 28 | } 29 | blockquote:before, blockquote:after, 30 | q:before, q:after { 31 | content: ''; 32 | content: none; 33 | } 34 | 35 | /* remember to define focus styles! */ 36 | :focus { 37 | outline: 0; 38 | } 39 | 40 | /* remember to highlight inserts somehow! */ 41 | ins { 42 | text-decoration: none; 43 | } 44 | del { 45 | text-decoration: line-through; 46 | } 47 | 48 | /* tables still need 'cellspacing="0"' in the markup */ 49 | table { 50 | border-collapse: collapse; 51 | border-spacing: 0; 52 | } 53 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | erlmon is a network and host monitoring suite, written in erlang. 3 | 4 | 5 | Copyright (c) 2010 DarmaSoft, LLC. 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation 9 | files (the "Software"), to deal in the Software without 10 | restriction, including without limitation the rights to use, 11 | copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the 13 | Software is furnished to do so, subject to the following 14 | conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | -------------------------------------------------------------------------------- /erlmon-1.0/include/erlmon.hrl: -------------------------------------------------------------------------------- 1 | 2 | %% announce 3 | -record(node_announce, {sender, pid, node, state}). 4 | %% ack announce 5 | -record(node_ack_announce, {sender, pid, node, state}). 6 | 7 | 8 | %% state change 9 | -record(state_change, {sender, node, objtype, obj, prev_state, new_state, data=none, ts}). 10 | 11 | %% sent alerts 12 | -record(sent_alert, {node, to, objtype, obj, prev_state, new_state, ets, ats}). 13 | 14 | %% state change filter 15 | -record(state_change_filter, {state_change, fields=[]}). 16 | 17 | %% alert filter 18 | -record(alert_filter, {scf, to}). 19 | 20 | %% announce 21 | -record(storage_announce, {sender, node}). 22 | %% ack announce 23 | -record(storage_ack_announce, {sender, node}). 24 | 25 | %% test_row 26 | -record(test, {key, value}). 27 | 28 | %% smtp_config 29 | -record(smtp_config, {authtype, port, host, address, login, pass}). 30 | 31 | %% --- monitor records --- %% 32 | 33 | %% tcp port monitor 34 | -record(tcp_port_monitor, {host, port, pid}). 35 | 36 | %% process monitor 37 | -record(process_monitor, {name, pid}). 38 | 39 | %% filesystem 40 | -record(filesystem, {path, size, used, avail, percent, mount}). 41 | 42 | %% process 43 | -record(process, {user, pid, cpu, mem, vsz, rss, tty, stat, start, time, cmd}). 44 | 45 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon_smtp_message.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon_smtp_message). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([create/3]). 6 | -export([test/0]). 7 | 8 | -include("include/erlmon.hrl"). 9 | 10 | create(Config, SC, To) -> 11 | From = Config#smtp_config.address, 12 | Subject = create_subject(SC), 13 | Body = create_body(SC), 14 | email_msg:simp_msg(From, To, Subject, Body). 15 | 16 | create_subject(#state_change{}=SC) -> 17 | Node = to_list(SC#state_change.node), 18 | Obj = to_list(SC#state_change.obj), 19 | ObjType = to_list(SC#state_change.objtype), 20 | PrevState = to_list(SC#state_change.prev_state), 21 | NewState = to_list(SC#state_change.new_state), 22 | lists:flatten(io_lib:format("~s:~s.~s (~s -> ~s)", [Node, ObjType, Obj, PrevState, NewState])). 23 | 24 | create_body(#state_change{}=_SC) -> 25 | "test body". 26 | 27 | to_list(Arg) when is_atom(Arg) -> 28 | atom_to_list(Arg); 29 | to_list(Arg) when is_list(Arg) -> 30 | Arg. 31 | 32 | test() -> 33 | C = #smtp_config{host="mail.darmasoft.com", address="darrik@darmasoft.com", pass="testpass"}, 34 | SC = #state_change{sender=self(), node=node(), objtype=tcp_port, obj="localhost:22", prev_state=up, new_state=down, ts=timestamp:now_i()}, 35 | To = "darrik@darmasoft.com", 36 | create(C, SC, To). 37 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/web_index.erl: -------------------------------------------------------------------------------- 1 | -module (web_index). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | main() -> 6 | #template { file="./wwwroot/template.html"}. 7 | 8 | title() -> 9 | "erlmon home.". 10 | 11 | body() -> 12 | [ 13 | #h1{text="Node Status"}, 14 | get_node_status() 15 | ]. 16 | 17 | 18 | menu_items() -> helper:menu([{home,"dashboard","/"},{config,"configuration","/web/config"}]). 19 | 20 | event(_) -> ok. 21 | 22 | get_node_status() -> 23 | Nodes = node:status(), 24 | #table { rows=[ 25 | #tablerow { cells = [ 26 | #tableheader { text="Node" }, 27 | #tableheader { text="Status" } 28 | ]}, 29 | node_status_to_html(Nodes) 30 | ]}. 31 | 32 | node_status_to_html([{Node, Status}|T]) -> 33 | {Text, Class, Cell} = case Status of 34 | up -> 35 | {"UP", "node_status_up", #tablecell { body=#link{ text=atom_to_list(Node), url=lists:flatten(io_lib:format("/web/node/~s", [atom_to_list(Node)]))}}}; 36 | down -> 37 | {"DOWN", "node_status_down", #tablecell { text=atom_to_list(Node) }}; 38 | _ -> 39 | {"UNKNOWN", "node_status_unknown", #tablecell { text=atom_to_list(Node) }} 40 | end, 41 | [ 42 | #tablerow { cells = [ 43 | Cell, 44 | #tablecell { text=Text, class=Class } 45 | ]} 46 | | node_status_to_html(T)]; 47 | node_status_to_html([]) -> 48 | []. 49 | -------------------------------------------------------------------------------- /erlmon-1.0/src/email_msg.erl: -------------------------------------------------------------------------------- 1 | %% 2 | %% file: email_msg.erl 3 | %% author: Michael Bradford 4 | %% description: a very simple module that creates a non-multipart 5 | %% email message. 6 | %% Doesn't support MIME or non-ascii characters 7 | %% 8 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9 | %% Usage Example 10 | %% 11 | %% 2> c(email_msg). 12 | %% {ok,email_msg} 13 | %% 3> From = "michael.bradford@t-mobile.uk.net". 14 | %% "michael.bradford@t-mobile.uk.net" 15 | %% 4> To = "test@test.co.uk". 16 | %% "test@test.co.uk" 17 | %% 5> Subject = "Testing !!!!". 18 | %% "Testing !!!!" 19 | %% 6> Content = "Hi Mike, this is a test, bye". 20 | %% "Hi Mike, this is a test, bye" 21 | %% 7> Msg = email_msg:simp_msg(From,To,Subject,Content). 22 | %% "from: michael.bradford@t-mobile.uk.net\r\nto: test@test.co.uk\r\n 23 | %% subject: Testi ng !!!!\r\n\r\nHi Mike, this is a test, bye\r\n" 24 | %% 8> 25 | %% 26 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27 | %% 28 | -module(email_msg). 29 | -vsn('v1.0'). 30 | 31 | -export([simp_msg/4]). 32 | 33 | simp_msg(From, To, Subject, Message) -> 34 | FromStr = ["from: ", From, "\r\n"], 35 | ToStr = ["to: ", To, "\r\n"], 36 | SubjStr = ["subject: ", Subject, "\r\n"], 37 | MsgStr = ["\r\n", Message], 38 | lists:concat(lists:concat([FromStr, ToStr, SubjStr, MsgStr, ["\r\n"]])). 39 | -------------------------------------------------------------------------------- /erlmon-1.0/src/monitor_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(monitor_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -export([start_link/0]). 8 | -export([init/1]). 9 | 10 | start_link() -> 11 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 12 | erlmon:finished(?MODULE), 13 | R. 14 | 15 | init(_) -> 16 | debug:log("monitor_sup: starting disk_monitor_sup"), 17 | DMSChild = {disk_monitor_sup, {disk_monitor_sup, start_link, []}, permanent, 2000, supervisor, [disk_monitor_sup]}, 18 | FMSChild = {file_monitor_sup, {file_monitor_sup, start_link, []}, permanent, 2000, supervisor, [file_monitor_sup]}, 19 | FMMChild = {file_monitor_man, {file_monitor_man, start_link, []}, permanent, 2000, worker, [file_monitor_man]}, 20 | TPMSChild = {tcp_port_monitor_sup, {tcp_port_monitor_sup, start_link, []}, permanent, 2000, supervisor, [tcp_port_monitor_sup]}, 21 | TPMMChild = {tcp_port_monitor_man, {tcp_port_monitor_man, start_link, []}, permanent, 2000, worker, [tcp_port_monitor_man]}, 22 | PMSChild = {process_monitor_sup, {process_monitor_sup, start_link, []}, permanent, 2000, supervisor, [process_monitor_sup]}, 23 | PMMChild = {process_monitor_man, {process_monitor_man, start_link, []}, permanent, 2000, worker, [process_monitor_man]}, 24 | {ok, {{one_for_one, 1, 1}, [DMSChild, FMSChild, FMMChild, TPMSChild, TPMMChild, PMSChild, PMMChild]}}. 25 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/web_config.erl: -------------------------------------------------------------------------------- 1 | -module (web_config). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | main() -> 6 | #template { file="./wwwroot/template.html"}. 7 | 8 | title() -> 9 | "erlmon configuration". 10 | 11 | alert_status() -> 12 | Address = config:setting([smtp,address]), 13 | case length(Address) of 14 | 0 -> "no alert address set!"; 15 | _ -> ["alerts sent to " ++ Address] 16 | end. 17 | 18 | body() -> 19 | case file:read_file("config.lua") of 20 | {ok, Config} -> 21 | [ 22 | #h1{text="Configuration"}, 23 | #p{}, 24 | #label{text="Edit the configuration file for this node. Updates are applied immediately to all nodes."}, 25 | #textarea {id=config, text=binary_to_list(Config), html_encode=false }, 26 | #p{}, 27 | #button { text="Save Config", postback={click, save_button} } 28 | 29 | ]; 30 | {error, _Reason} -> 31 | [ 32 | #h1{text="Configuration"}, 33 | #p{}, 34 | #label{text="config.lua is either missing or inaccessible. Check the file and try again, please."} 35 | ] 36 | end. 37 | 38 | menu_items() -> helper:menu([{home,"dashboard","/"},{nodes,"configuration","/web/config"}]). 39 | 40 | event(_) -> 41 | [Config] = wf:q(config), 42 | config:update_file(Config), 43 | helper:flash_msg("Config reloaded."), 44 | wf:redirect("/web/config"), 45 | ok. 46 | 47 | -------------------------------------------------------------------------------- /erlmon-1.0/config.example.lua: -------------------------------------------------------------------------------- 1 | -- this require isn't specifically required as it will be added 2 | -- when executed inside of erlmon, but they are necessary to 3 | -- test the file on the command line, by typing lua config.lua 4 | require "lua/erlmon" 5 | 6 | 7 | -- Quick lua tutorial: 8 | -- A table can be created like this: mytable = { a = 1, b = 2 } 9 | -- then i can say mytable.a, or mytable['a']... you'll see this syntax 10 | -- all over the file. Also, tables can have 'metatables'. erlmon 11 | -- uses this extensively to lookup global properties if they're not 12 | -- overridden on a sub object. details below... 13 | 14 | -- This is where globals go. 15 | 16 | Erlmon.http.login = 'admin' 17 | Erlmon.http.password = 'admin' 18 | Erlmon.alert.email = 'me@myemail.com' 19 | 20 | -- Specific config differences can go here 21 | 22 | -- sigmund - memcached 23 | sigmund = Erlmon.add_host("sigmund.mydomain.com") 24 | 25 | -- In this example, sigmund is a lua table. if you access a property 26 | -- of sigmund that doesn't exist, the equivalent property will be accessed 27 | -- on the global Erlmon object. 28 | 29 | sigmund.http.password = "superego" 30 | sigmund.alert.email = "sigmundalerts@myemail.com" 31 | 32 | sigmund.monitor_process("memcached", 33 | { start = "/etc/init.d/memcached start", 34 | stop = "/etc/init.d/memcached stop" 35 | } 36 | ) 37 | 38 | sigmund.monitor_port(11211) -- memcached 39 | 40 | -------------------------------------------------------------------------------- /erlmon-1.0/src/state_change_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(state_change_sup). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(supervisor). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([start_link/0]). 10 | -export([init/1]). 11 | 12 | start_link() -> 13 | R = supervisor:start_link({local, ?MODULE}, ?MODULE, []), 14 | wait_for_state_change_em(), 15 | erlmon:finished(?MODULE), 16 | R. 17 | 18 | 19 | init(_) -> 20 | debug:log("state_change_sup: starting state_change_em"), 21 | Child = {state_change_em, {state_change_em, start_link, []}, permanent, 2000, worker, [state_change_em]}, 22 | {ok, {{one_for_one, 1, 1}, [Child]}}. 23 | 24 | wait_for_state_change_em() -> 25 | case whereis(state_change_em) of 26 | undefined -> 27 | wait_for_state_change_em(); 28 | _ -> 29 | add_default_handlers(), 30 | add_default_filters() 31 | end. 32 | 33 | add_default_handlers() -> 34 | state_change_em:add_handler(state_change_handler), 35 | state_change_em:add_handler(config_file_change_handler), 36 | state_change_em:add_handler(node_down_handler), 37 | state_change_em:add_handler(alert_handler). 38 | 39 | add_default_filters() -> 40 | SC = #state_change{sender=nil, node=nil, objtype=file, obj="config.lua", prev_state=unchanged, new_state=file_ctime_changed, ts=nil}, 41 | SCF = #state_change_filter{state_change=SC, fields=[objtype, obj, prev_state, new_state]}, 42 | AF = #alert_filter{scf=SCF, to="darrik@darmasoft.com"}, 43 | alert_handler:register_alert_filter(AF). 44 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(application). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([start/0, start/2, stop/1, finished/1]). 10 | 11 | -define(SUPERVISORS, [ 12 | erlmon_sup, 13 | state_change_sup, 14 | state_change_em, 15 | storage_sup, 16 | storage, 17 | node_sup, 18 | node, 19 | monitor_sup, 20 | disk_monitor_sup, 21 | tcp_port_monitor_sup, 22 | tcp_port_monitor_man, 23 | file_monitor_sup, 24 | file_monitor_man, 25 | process_list_sup, 26 | process_monitor_sup, 27 | process_monitor_man, 28 | config_sup, 29 | config, 30 | erlmon_smtp_sup 31 | ]). 32 | 33 | start() -> 34 | application:start(erlmon). 35 | 36 | start(_Type, _StartArgs) -> 37 | debug:log_to(file, {filename, "erlmon.log"}), 38 | debug:log_to(console, {}), 39 | debug:log("erlmon: initializing"), 40 | register(erlmon, self()), 41 | R = erlmon_sup:start_link(), 42 | wait_for_finished(?SUPERVISORS), 43 | load(), 44 | R. 45 | 46 | load() -> 47 | file_monitor:monitor("config.lua"), 48 | config:reload(), 49 | erlmon_smtp:config(), 50 | application:set_env(erlwww, port, 8000), 51 | application:start(erlwww), 52 | ok. 53 | 54 | 55 | stop(_State) -> 56 | debug:log("erlmon: stopping"), 57 | ok. 58 | 59 | wait_for_finished([]) -> 60 | debug:log("erlmon: startup complete"), 61 | ok; 62 | wait_for_finished([S|T]) -> 63 | debug:log("erlmon: waiting for ~p", [S]), 64 | receive 65 | {S, started} -> 66 | debug:log("erlmon: ~p finished", [S]), 67 | ok 68 | end, 69 | wait_for_finished(T). 70 | 71 | finished(S) -> 72 | erlmon ! {S, started}. 73 | -------------------------------------------------------------------------------- /erlmon-1.0/src/df.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(df). 3 | -author(darrik@darmsoft.com). 4 | 5 | -export([list/0]). 6 | -export([list/1]). 7 | -export([find_path/1]). 8 | 9 | -include("include/erlmon.hrl"). 10 | 11 | list() -> 12 | list([]). 13 | 14 | list([]) -> 15 | Output = os:cmd("df"), 16 | process(Output). 17 | 18 | process(Output) when is_list(Output) -> 19 | Lines = re:split(Output, "\n", [{return, list}]), 20 | [_Header|T] = Lines, 21 | lists:flatten(create_records(T)). 22 | 23 | create_records([H|[]]) -> 24 | [create_record(H)]; 25 | create_records([H|T]) -> 26 | [create_record(H) | create_records(T)]; 27 | create_records([]) -> 28 | []. 29 | 30 | create_record([Head|[]]) -> create_record(Head); 31 | create_record([]) -> []; 32 | create_record(Line) -> 33 | Fields = re:split(Line, "\s+", [{return, list}]), 34 | [Path, Size, Used, Avail, Percent, Mount] = Fields, 35 | [NewPercent|_] = lists:flatten(re:replace(Percent, "%", "")), 36 | IntPercent = binary_to_integer(NewPercent), 37 | case re:run(Path, "/dev") of 38 | {match, _} -> 39 | Rec = #filesystem{path=Path, size=Size, used=Used, avail=Avail, percent=IntPercent, mount=Mount}, 40 | Rec; 41 | nomatch -> [] 42 | end. 43 | 44 | binary_to_integer(Bin) -> 45 | case erl_scan:string(binary_to_list(Bin)) of 46 | {ok, Tokens, _} -> 47 | first_integer(Tokens); 48 | _ -> 0 49 | end. 50 | 51 | first_integer([{integer, _V, I}|_T]) -> I; 52 | first_integer([_H|T]) -> first_integer(T); 53 | first_integer([]) -> 0. 54 | 55 | find_path(Path) -> 56 | find_path(Path, list()). 57 | 58 | find_path(Path, [H=#filesystem{path=Path}|_T]) -> 59 | H; 60 | find_path(Path, [_H|T]) -> 61 | find_path(Path, T); 62 | find_path(_Path, []) -> 63 | not_found. 64 | -------------------------------------------------------------------------------- /erlmon-1.0/src/file_monitor_man.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(file_monitor_man). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start_link/0]). 6 | -export([init/0]). 7 | -export([monitor/1]). 8 | -export([unmonitor/1]). 9 | 10 | 11 | start_link() -> 12 | debug:log("file_monitor_man: starting"), 13 | register(?MODULE, Pid = spawn_link(?MODULE, init, [])), 14 | erlmon:finished(?MODULE), 15 | {ok, Pid}. 16 | 17 | init() -> 18 | loop([]). 19 | 20 | loop(State) -> 21 | receive 22 | {start, Path} -> 23 | NewState = start_conditionally(Path, State), 24 | loop(NewState); 25 | {stop, Path} -> 26 | NewState = stop_conditionally(Path, State), 27 | loop(NewState); 28 | M -> 29 | debug:log("file_monitor_man: UNKNOWN: ~p", [M]), 30 | loop(State) 31 | end. 32 | 33 | monitor(Path) -> 34 | wait_for_manager(), 35 | ?MODULE ! {start, Path}, 36 | ok. 37 | 38 | unmonitor(Path) -> 39 | ?MODULE ! {stop, Path}, 40 | ok. 41 | 42 | start_conditionally(Path, []) -> 43 | debug:log("file_monitor_man: monitoring ~p", [Path]), 44 | file_monitor_sup:monitor(Path), 45 | [Path]; 46 | start_conditionally(Path, [Path|T]) -> 47 | debug:log("file_monitor_man: ~p already monitored", [Path]), 48 | [Path|T]; 49 | start_conditionally(Path, [H|T]) -> 50 | [H | start_conditionally(Path, T)]. 51 | 52 | stop_conditionally(Path, []) -> 53 | debug:log("file_monitor_man: not monitoring ~p", [Path]), 54 | []; 55 | stop_conditionally(Path, [Path|T]) -> 56 | debug:log("file_monitor_man: no longer monitoring ~p", [Path]), 57 | file_monitor_sup:unmonitor(Path), 58 | T; 59 | stop_conditionally(Path, [H|T]) -> 60 | [H | stop_conditionally(Path, T)]. 61 | 62 | wait_for_manager() -> 63 | case whereis(file_monitor_man) of 64 | undefined -> 65 | wait_for_manager(); 66 | _ -> 67 | ok 68 | end. 69 | 70 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlwww_app.erl: -------------------------------------------------------------------------------- 1 | -module (erlwww_app). 2 | -export ([start/2, stop/1, route/1, request/1]). 3 | -behavior(application). 4 | 5 | start(_, _) -> nitrogen:start(erlwww). 6 | stop(_) -> nitrogen:stop(). 7 | 8 | %% route/1 lets you define new URL routes to your web pages, 9 | %% or completely create a new routing scheme. 10 | %% The 'Path' argument specifies the request path. Your 11 | %% function should return either an atom which is the page module 12 | %% to run, or a tuple containing {Module, PathInfo}. PathInfo 13 | %% can be accessed using wf:get_path_info(). 14 | %% 15 | %% Uncomment the line below to direct requests 16 | %% from "/web/newroute" to the web_index module: 17 | %% 18 | %% route("/web/newroute") -> web_index; 19 | %% 20 | %% Uncomment the line below to direct requests 21 | %% from "/web/newroute" to the web_index module, 22 | %% with trailing PathInfo included: 23 | %% 24 | %% route("/web/newroute/" ++ PathInfo) -> {web_index, PathInfo}; 25 | 26 | route("/web/login") -> login; 27 | route("/web/config") -> web_config; 28 | route("/web/node/" ++ PathInfo) -> {web_node, PathInfo}; 29 | route(Path) -> nitrogen:route(Path). 30 | 31 | 32 | %% request/1 is executed before every Nitrogen page, and lets 33 | %% you add authentication and authorization. The 'Module' argument 34 | %% is the name of the page module. 35 | %% This function should return either 'ok' if processing can proceed, 36 | %% or it can return a full-fledged page by treating it just like the main function 37 | %% of a page. Alternatively, you can use the wf:redirect* functions to 38 | %% issue a client-side redirect to a new page. 39 | 40 | request(Module) -> 41 | case Module of 42 | login -> 43 | ok; 44 | _ -> 45 | User = wf:user(), 46 | case User of 47 | undefined -> wf:redirect_to_login("/web/login"); 48 | _ -> ok 49 | end 50 | end. 51 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/facebox.css: -------------------------------------------------------------------------------- 1 | #facebox .b { 2 | background:url(/images/facebox/b.png); 3 | } 4 | 5 | #facebox .tl { 6 | background:url(/images/facebox/tl.png); 7 | } 8 | 9 | #facebox .tr { 10 | background:url(/images/facebox/tr.png); 11 | } 12 | 13 | #facebox .bl { 14 | background:url(/images/facebox/bl.png); 15 | } 16 | 17 | #facebox .br { 18 | background:url(/images/facebox/br.png); 19 | } 20 | 21 | #facebox { 22 | position: absolute; 23 | top: 0; 24 | left: 0; 25 | z-index: 100; 26 | text-align: left; 27 | } 28 | 29 | #facebox .popup { 30 | position: relative; 31 | } 32 | 33 | #facebox table { 34 | border-collapse: collapse; 35 | } 36 | 37 | #facebox td { 38 | border-bottom: 0; 39 | padding: 0; 40 | } 41 | 42 | #facebox .body { 43 | padding: 10px; 44 | background: #fff; 45 | width: 370px; 46 | } 47 | 48 | #facebox .loading { 49 | text-align: center; 50 | } 51 | 52 | #facebox .image { 53 | text-align: center; 54 | } 55 | 56 | #facebox img { 57 | border: 0; 58 | margin: 0; 59 | } 60 | 61 | #facebox .footer { 62 | border-top: 1px solid #DDDDDD; 63 | padding-top: 5px; 64 | margin-top: 10px; 65 | text-align: right; 66 | } 67 | 68 | #facebox .tl, #facebox .tr, #facebox .bl, #facebox .br { 69 | height: 10px; 70 | width: 10px; 71 | overflow: hidden; 72 | padding: 0; 73 | } 74 | 75 | #facebox_overlay { 76 | position: fixed; 77 | top: 0px; 78 | left: 0px; 79 | height:100%; 80 | width:100%; 81 | background:url(/images/facebox/overlay.png); 82 | z-index:99; 83 | } 84 | 85 | .facebox_hide { 86 | z-index:-100; 87 | } 88 | 89 | .facebox_overlayBG { 90 | background-color: #000; 91 | z-index: 99; 92 | } 93 | 94 | * html #facebox_overlay { /* ie6 hack */ 95 | position: absolute; 96 | height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); 97 | } 98 | -------------------------------------------------------------------------------- /erlmon-1.0/c_src/erlua.h: -------------------------------------------------------------------------------- 1 | typedef struct _lua_drv_t { 2 | ErlDrvPort port; 3 | lua_State *L; 4 | } lua_drv_t; 5 | 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /* Fix a silly Lua warning */ 12 | 13 | void luaL_openlibs (lua_State *L); 14 | 15 | /* Commands */ 16 | 17 | void erl_lua_call(lua_drv_t *driver_data, char *buf, int index); 18 | void erl_lua_concat(lua_drv_t *driver_data, char *buf, int index); 19 | void erl_lua_getfield (lua_drv_t *driver_data, char *buf, int index); 20 | void erl_lua_getglobal(lua_drv_t *driver_data, char *buf, int index); 21 | void erl_lua_gettop(lua_drv_t *driver_data, char *buf, int index); 22 | void erl_lua_next(lua_drv_t *driver_data, char *buf, int index); 23 | void erl_lua_pushboolean(lua_drv_t *driver_data, char *buf, int index); 24 | void erl_lua_pushinteger(lua_drv_t *driver_data, char *buf, int index); 25 | void erl_lua_pushstring(lua_drv_t *driver_data, char *buf, int index); 26 | void erl_lua_pushnil(lua_drv_t *driver_data, char *buf, int index); 27 | void erl_lua_pushnumber(lua_drv_t *driver_data, char *buf, int index); 28 | void erl_lua_remove(lua_drv_t *driver_data, char *buf, int index); 29 | void erl_lua_setfield(lua_drv_t *driver_data, char *buf, int index); 30 | void erl_lua_setglobal(lua_drv_t *driver_data, char *buf, int index); 31 | void erl_lua_toboolean(lua_drv_t *driver_data, char *buf, int index); 32 | void erl_lua_tointeger(lua_drv_t *driver_data, char *buf, int index); 33 | void erl_lua_tolstring(lua_drv_t *driver_data, char *buf, int index); 34 | void erl_lua_tonumber(lua_drv_t *driver_data, char *buf, int index); 35 | void erl_lua_type(lua_drv_t *driver_data, char *buf, int index); 36 | 37 | void erl_lual_dostring (lua_drv_t *driver_data, char *buf, int index); 38 | void erl_lual_dofile (lua_drv_t *driver_data, char *buf, int index); 39 | 40 | void erl_lua_no_command (lua_drv_t *driver_data); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif /* __cplusplus */ 45 | -------------------------------------------------------------------------------- /erlmon-1.0/src/debug.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(debug). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([log/1]). 6 | -export([log/2]). 7 | 8 | -export([log_to/2]). 9 | -export([no_log_to/2]). 10 | 11 | -export([init/0]). 12 | 13 | -include_lib("include/debug.hrl"). 14 | 15 | log(Format) -> 16 | log(Format, []). 17 | 18 | log(Format, Args) -> 19 | start(), 20 | debug_srv ! #debug_log_msg{sender=self(), format=Format, args=Args}, 21 | true. 22 | 23 | log_to(Mod, Options) -> 24 | start(), 25 | ModString = atom_to_list(Mod), 26 | NewModString = lists:flatten(["debug_"|ModString]), 27 | NewMod = list_to_atom(NewModString), 28 | debug_srv ! #debug_log_add_method{sender=self(), module=NewMod, options=Options}, 29 | true. 30 | 31 | no_log_to(Mod, Options) -> 32 | start(), 33 | debug_srv ! #debug_log_rem_method{sender=self(), module=Mod, options=Options}, 34 | true. 35 | 36 | start() -> 37 | case whereis(debug_srv) of 38 | undefined -> 39 | register(debug_srv, spawn(debug, init, [])); 40 | _Pid -> true 41 | end, 42 | true. 43 | 44 | init() -> 45 | loop([]). 46 | 47 | loop(State) -> 48 | receive 49 | #debug_log_msg{sender=_Sender, format=Format, args=Args} -> 50 | dispatch("[~s] " ++ Format, [timestamp:now()|Args], State), 51 | loop(State); 52 | #debug_log_add_method{sender=_Sender, module=Mod, options=Options} -> 53 | NewState = add_to_state({Mod, Options}, State), 54 | loop(NewState); 55 | #debug_log_rem_method{sender=_Sender, module=Mod, options=Options} -> 56 | NewState = remove_from_state({Mod, Options}, State), 57 | loop(NewState) 58 | end. 59 | 60 | add_to_state(Tuple, [Tuple|T]) -> [Tuple|T]; 61 | add_to_state(Tuple, [H|T]) -> [H|add_to_state(Tuple, T)]; 62 | add_to_state(Tuple, []) -> [Tuple|[]]. 63 | 64 | remove_from_state(Tuple, [Tuple|T]) -> T; 65 | remove_from_state(Tuple, [H|T]) -> [H|remove_from_state(Tuple, T)]; 66 | remove_from_state(_Tuple, []) -> []. 67 | 68 | dispatch(Format, Args, [{Mod, Options}|T]) -> 69 | apply(Mod, log, [Format, Args, Options]), 70 | dispatch(Format, Args, T); 71 | dispatch(_Format, _Args, []) -> true. 72 | 73 | -------------------------------------------------------------------------------- /erlmon-1.0/src/process_monitor_man.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(process_monitor_man). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start_link/0]). 6 | -export([init/0]). 7 | -export([monitor/1]). 8 | -export([unmonitor/1]). 9 | -export([status/0]). 10 | 11 | -include("include/erlmon.hrl"). 12 | 13 | start_link() -> 14 | debug:log("process_monitor_man: starting"), 15 | register(?MODULE, Pid = spawn_link(?MODULE, init, [])), 16 | erlmon:finished(?MODULE), 17 | {ok, Pid}. 18 | 19 | init() -> 20 | loop([]). 21 | 22 | loop(State) -> 23 | receive 24 | {Sender, status} -> 25 | Sender ! {ok, State}, 26 | loop(State); 27 | {start, ProcessName} -> 28 | NewState = start_conditionally(ProcessName, State), 29 | loop(NewState); 30 | {stop, ProcessName} -> 31 | NewState = stop_conditionally(ProcessName, State), 32 | loop(NewState); 33 | M -> 34 | debug:log("process_monitor_man: UNKNOWN: ~p", [M]), 35 | loop(State) 36 | end. 37 | 38 | status() -> 39 | ?MODULE ! {self(), status}, 40 | receive 41 | {ok, Status} -> ok 42 | end, 43 | Status. 44 | 45 | monitor(ProcessName) -> 46 | ?MODULE ! {start, ProcessName}, 47 | ok. 48 | 49 | unmonitor(ProcessName) -> 50 | ?MODULE ! {stop, ProcessName}, 51 | ok. 52 | 53 | start_conditionally(ProcessName, []) -> 54 | debug:log("process_monitor_man: monitoring ~p", [ProcessName]), 55 | {ok, Pid} = process_monitor_sup:monitor(ProcessName), 56 | [#process_monitor{name=ProcessName, pid=Pid}]; 57 | start_conditionally(ProcessName, [H=#process_monitor{name=ProcessName, pid=Pid}|T]) -> 58 | debug:log("process_monitor_man: ~p already monitored (~p)", [ProcessName, Pid]), 59 | [H|T]; 60 | start_conditionally(ProcessName, [H|T]) -> 61 | [H | start_conditionally(ProcessName, T)]. 62 | 63 | stop_conditionally(ProcessName, []) -> 64 | debug:log("process_monitor_man: not monitoring ~p", [ProcessName]), 65 | []; 66 | stop_conditionally(ProcessName, [#process_monitor{name=ProcessName, pid=Pid}|T]) -> 67 | debug:log("process_monitor_man: no longer monitoring ~p (~p)", [ProcessName, Pid]), 68 | process_monitor_sup:unmonitor(ProcessName), 69 | Pid ! stop, 70 | T; 71 | stop_conditionally(ProcessName, [H|T]) -> 72 | [H | stop_conditionally(ProcessName, T)]. 73 | -------------------------------------------------------------------------------- /erlmon-1.0/src/tcp_port_monitor_man.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(tcp_port_monitor_man). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start_link/0]). 6 | -export([init/0]). 7 | -export([monitor/2]). 8 | -export([unmonitor/2]). 9 | -export([status/0]). 10 | 11 | -include("include/erlmon.hrl"). 12 | 13 | start_link() -> 14 | debug:log("tcp_port_monitor_man: starting"), 15 | register(?MODULE, Pid = spawn_link(?MODULE, init, [])), 16 | erlmon:finished(?MODULE), 17 | {ok, Pid}. 18 | 19 | init() -> 20 | loop([]). 21 | 22 | loop(State) -> 23 | receive 24 | {Sender, status} -> 25 | Sender ! {ok, State}, 26 | loop(State); 27 | {start, Host, Port} -> 28 | NewState = start_conditionally(Host, Port, State), 29 | loop(NewState); 30 | {stop, Host, Port} -> 31 | NewState = stop_conditionally(Host, Port, State), 32 | loop(NewState); 33 | M -> 34 | debug:log("tcp_port_monitor_man: UNKNOWN: ~p", [M]), 35 | loop(State) 36 | end. 37 | 38 | monitor(Host, Port) -> 39 | ?MODULE ! {start, Host, Port}, 40 | ok. 41 | 42 | unmonitor(Host, Port) -> 43 | ?MODULE ! {stop, Host, Port}, 44 | ok. 45 | 46 | status() -> 47 | ?MODULE ! {self(), status}, 48 | receive 49 | {ok, Status} -> ok 50 | end, 51 | Status. 52 | 53 | start_conditionally(Host, Port, []) -> 54 | debug:log("tcp_port_monitor_man: monitoring ~p:~p", [Host, Port]), 55 | {ok, Pid} = tcp_port_monitor_sup:monitor(Host, Port), 56 | [#tcp_port_monitor{host=Host, port=Port, pid=Pid}]; 57 | start_conditionally(Host, Port, [#tcp_port_monitor{host=Host, port=Port}|_T]=State) -> 58 | debug:log("tcp_port_monitor_man: ~p:~p already monitored", [Host, Port]), 59 | State; 60 | start_conditionally(Host, Port, [H|T]) -> 61 | [H | start_conditionally(Host, Port, T)]. 62 | 63 | stop_conditionally(Host, Port, []) -> 64 | debug:log("tcp_port_monitor_man: not monitoring ~p:~p", [Host, Port]), 65 | []; 66 | stop_conditionally(Host, Port, [#tcp_port_monitor{host=Host, port=Port, pid=Pid}|T]) -> 67 | debug:log("tcp_port_monitor_man: no longer monitoring ~p:~p (~p)", [Host, Port, Pid]), 68 | tcp_port_monitor_sup:unmonitor(Host, Port), 69 | Pid ! stop, 70 | T; 71 | stop_conditionally(Host, Port, [H|T]) -> 72 | [H | stop_conditionally(Host, Port, T)]. 73 | -------------------------------------------------------------------------------- /erlmon-1.0/src/disk_monitor.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(disk_monitor). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/1]). 6 | -export([start_all/0]). 7 | -export([init/1]). 8 | -export([monitor/1]). 9 | 10 | -include("include/erlmon.hrl"). 11 | 12 | monitor(Path) -> 13 | disk_monitor_sup:monitor(Path). 14 | 15 | start_all() -> 16 | start_each(df:list()). 17 | 18 | start_each([#filesystem{path=Path}|T]) -> 19 | start(Path), 20 | start_each(T); 21 | start_each([]) -> ok. 22 | 23 | start(Path) -> 24 | {ok, spawn_link(?MODULE, init, [Path])}. 25 | 26 | init(Path) -> 27 | debug:log("disk_monitor:init(~p)", [Path]), 28 | Filesystem = df:find_path(Path), 29 | case Filesystem of 30 | not_found -> 31 | null; 32 | #filesystem{} -> 33 | loop(first, Filesystem) 34 | end. 35 | 36 | loop(OldState, Filesystem) -> 37 | receive 38 | stop -> 39 | stopped 40 | after 41 | 3000 -> 42 | #filesystem{path=Path, percent=_Percent} = Filesystem, 43 | NewFilesystem = df:find_path(Path), 44 | #filesystem{path=Path, percent=NewPercent, mount=Mount} = NewFilesystem, 45 | ObjName = lists:flatten([Path, ":"| Mount]), 46 | case NewPercent > 90 of 47 | false -> 48 | case OldState of 49 | alert -> 50 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=disk, obj=ObjName, prev_state=alert, new_state=ok, data=NewPercent, ts=timestamp:now_i()}), 51 | loop(ok, NewFilesystem); 52 | first -> 53 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=disk, obj=ObjName, prev_state=none, new_state=ok, data=NewPercent, ts=timestamp:now_i()}), 54 | loop(ok, NewFilesystem); 55 | _ -> 56 | loop(ok, NewFilesystem) 57 | end; 58 | true -> 59 | case OldState of 60 | ok -> 61 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=disk, obj=ObjName, prev_state=ok, new_state=alert, data=NewPercent, ts=timestamp:now_i()}), 62 | loop(alert, NewFilesystem); 63 | first -> 64 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=disk, obj=ObjName, prev_state=none, new_state=alert, data=NewPercent, ts=timestamp:now_i()}), 65 | loop(alert, NewFilesystem); 66 | _ -> 67 | loop(alert, NewFilesystem) 68 | end 69 | end 70 | end. 71 | -------------------------------------------------------------------------------- /erlmon-1.0/tests/lua_test.erl: -------------------------------------------------------------------------------- 1 | -module(lua_test). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | small_integer_test() -> 6 | push_to_helper(1, pushinteger, tointeger). 7 | 8 | zero_integer_test() -> 9 | push_to_helper(0, pushinteger, tointeger). 10 | 11 | small_negative_integer_test() -> 12 | push_to_helper(-2, pushinteger, tointeger). 13 | 14 | 15 | small_number_test() -> 16 | push_to_helper(2, pushnumber, tonumber). 17 | 18 | small_negative_number_test() -> 19 | push_to_helper(-2, pushnumber, tonumber). 20 | 21 | zero_number_test() -> 22 | push_to_helper(0, pushnumber, tonumber). 23 | 24 | big_number_test() -> 25 | push_to_helper(5000000000, pushnumber, tonumber). 26 | 27 | big_floating_number_test() -> 28 | push_to_helper(5000000000.234, pushnumber, tonumber). 29 | 30 | big_negative_number_test() -> 31 | push_to_helper(-5000000000, pushnumber, tonumber). 32 | 33 | big_negative_float_number_test() -> 34 | push_to_helper(-5000000000.234, pushnumber, tonumber). 35 | 36 | 37 | string_test() -> 38 | push_to_helper("testing", pushstring, tolstring). 39 | 40 | 41 | call_test() -> 42 | {ok, L} = lua:new_state(), 43 | ?assertMatch(ok, lua:getfield(L, global, "type")), 44 | ?assertMatch(ok, lua:pushnumber(L, 1)), 45 | ?assertMatch(ok, lua:call(L, 1, 1)), 46 | ?assertMatch({ok, "number"}, lua:tolstring(L, 1)). 47 | 48 | set_get_global_test() -> 49 | {ok, L} = lua:new_state(), 50 | ?assertMatch(ok, lua:pushnumber(L, 23)), 51 | ?assertMatch(ok, lua:setfield(L, global, "foo")), 52 | ?assertMatch(ok, lua:getfield(L, global, "foo")), 53 | ?assertMatch({ok, 23}, lua:tonumber(L, 1)). 54 | 55 | 56 | push_to_helper(Val, Push, To) -> 57 | {ok, L} = lua:new_state(), 58 | ?assertMatch(ok, lua:Push(L, Val)), 59 | ?assertMatch({ok, Val}, lua:To(L, 1)). 60 | 61 | gettable_test() -> 62 | {ok, L} = lua:new_state(), 63 | ?assertMatch(ok, lua:dostring(L, "t={a=1}")), 64 | ?assertMatch([{"a",1}], lua:gettable(L, global,"t")). 65 | 66 | gettable_int_key_test() -> 67 | {ok, L} = lua:new_state(), 68 | ?assertMatch(ok,lua:dostring(L, "t={};table.insert(t,'foo')")), 69 | ?assertMatch([{1,"foo"}], lua:gettable(L, global,"t")). 70 | 71 | gettable_int_key_table_test() -> 72 | {ok, L} = lua:new_state(), 73 | ?assertMatch(ok,lua:dostring(L, "t={};table.insert(t,{bar=1})")), 74 | ?assertMatch([{1,[{"bar",1}]}], lua:gettable(L, global,"t")). 75 | 76 | -------------------------------------------------------------------------------- /erlmon-1.0/src/pages/web_node.erl: -------------------------------------------------------------------------------- 1 | -module (web_node). 2 | -include_lib ("nitrogen/include/wf.inc"). 3 | -compile(export_all). 4 | 5 | main() -> 6 | #template { file="./wwwroot/template.html"}. 7 | 8 | title() -> 9 | "node info". 10 | 11 | body() -> 12 | Node = wf:get_path_info(), 13 | [ 14 | #h1{text=lists:flatten(io_lib:format("Node Info : ~s", [Node]))}, 15 | monitor_status_table(Node) 16 | ]. 17 | 18 | 19 | menu_items() -> helper:menu([{home,"dashboard","/"},{config,"configuration","/web/config"}]). 20 | 21 | event(_) -> ok. 22 | 23 | monitor_status_table(Node) -> 24 | NodeAtom = list_to_atom(Node), 25 | HeaderRow = #tablerow { cells=[ 26 | #tableheader { text="Object Type" }, 27 | #tableheader { text="Object" }, 28 | #tableheader { text="Status" } 29 | ]}, 30 | Rows = lists:flatten([ 31 | HeaderRow, 32 | tcp_port_monitor_status_table(NodeAtom), 33 | process_monitor_status_table(NodeAtom) 34 | ]), 35 | #table { rows=Rows }. 36 | 37 | tcp_port_monitor_status_table(Node) -> 38 | case {node(), Node} of 39 | {Node, Node} -> 40 | Status = tcp_port_monitor:status(); 41 | {_, Node} -> 42 | Status = rpc:call(Node, tcp_port_monitor, status, []) 43 | end, 44 | tcp_port_monitor_status_rows(Status). 45 | 46 | tcp_port_monitor_status_rows([{ObjType,Host,Port,Pid}|T]) -> 47 | {ok, Status} = tcp_port_monitor:status(Pid), 48 | {Text, Class} = case Status of 49 | up -> {"UP", "monitor_status_up"}; 50 | down -> {"DOWN", "monitor_status_down"}; 51 | _ -> {Status, "monitor_status_unknown"} 52 | end, 53 | [ #tablerow { cells=[ 54 | #tablecell { text=ObjType }, 55 | #tablecell { text=lists:flatten(io_lib:format("~s:~p", [Host, Port])) }, 56 | #tablecell { text=Text, class=Class } 57 | ]} | tcp_port_monitor_status_rows(T) ]; 58 | tcp_port_monitor_status_rows([]) -> 59 | []. 60 | 61 | process_monitor_status_table(Node) -> 62 | case {node(), Node} of 63 | {Node, Node} -> 64 | Status = process_monitor:status(); 65 | {_, Node} -> 66 | Status = rpc:call(Node, process_monitor, status, []) 67 | end, 68 | process_monitor_status_rows(Status). 69 | 70 | process_monitor_status_rows([{ObjType,ObjName,Pid}|T]) -> 71 | {ok, Status} = process_monitor:status(Pid), 72 | {Text, Class} = case Status of 73 | up -> {"UP", "monitor_status_up"}; 74 | down -> {"DOWN", "monitor_status_down"}; 75 | _ -> {Status, "monitor_status_unknown"} 76 | end, 77 | [ 78 | #tablerow { cells=[ 79 | #tablecell { text=ObjType }, 80 | #tablecell { text=ObjName }, 81 | #tablecell { text=Text, class=Class } 82 | ]} | process_monitor_status_rows(T) ]; 83 | process_monitor_status_rows([]) -> 84 | []. 85 | -------------------------------------------------------------------------------- /erlmon-1.0/src/tcp_port_monitor.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(tcp_port_monitor). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/2]). 6 | -export([init/1]). 7 | -export([monitor/1,monitor/2]). 8 | -export([unmonitor/2]). 9 | -export([status/0]). 10 | -export([status/1]). 11 | 12 | -include("include/erlmon.hrl"). 13 | 14 | status() -> 15 | tcp_port_monitor_man:status(). 16 | 17 | status(Pid) -> 18 | Pid ! {self(), status}, 19 | receive 20 | {ok, Status} -> ok 21 | end, 22 | {ok, Status}. 23 | 24 | %% Config sends us, from Lua, something like: 25 | %% monitor([{"memcached",[{"host","localhost"},{"port",11211}]}]}) 26 | monitor([]) -> 27 | []; 28 | monitor([Description|T]) -> 29 | {_Name,Args} = Description, 30 | {"host",Host} = lists:keyfind("host",1,Args), 31 | {"port",Port} = lists:keyfind("port",1,Args), 32 | monitor(Host,Port), 33 | monitor(T). 34 | 35 | monitor(Host, Port) -> 36 | tcp_port_monitor_man:monitor(Host, Port). 37 | 38 | unmonitor(Host, Port) -> 39 | tcp_port_monitor_man:unmonitor(Host, Port). 40 | 41 | start(Host, Port) -> 42 | debug:log("tcp_port_monitor:start([~p, ~p])", [Host, Port]), 43 | {ok, spawn_link(?MODULE, init, [[Host, Port]])}. 44 | 45 | init([Host, Port]) -> 46 | debug:log("tcp_port_monitor: initializing monitor for ~p:~p", [Host, Port]), 47 | loop([Host, Port], unmonitored). 48 | 49 | loop([Host, Port], State) -> 50 | ObjName = lists:concat(io_lib:format("~s~s~p", [Host, ":",Port])), 51 | receive 52 | stop -> 53 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=tcp_port, obj=ObjName, prev_state=State, new_state=unmonitored, ts=timestamp:now_i()}); 54 | {Sender, status} -> 55 | Sender ! {ok, State}, 56 | loop([Host, Port], State); 57 | M -> 58 | debug:log("tcp_port_monitor: ~p: UNKNOWN: ~p", [self(), M]) 59 | after 60 | 3000 -> 61 | case gen_tcp:connect(Host, Port, [binary, {packet, 0}]) of 62 | {ok, Sock} -> 63 | gen_tcp:close(Sock), 64 | case State of 65 | up -> 66 | NewState = up, 67 | loop([Host, Port], NewState); 68 | OldState -> 69 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=tcp_port, obj=ObjName, prev_state=OldState, new_state=up, ts=timestamp:now_i()}), 70 | NewState = up, 71 | loop([Host, Port], NewState) 72 | end; 73 | {error, _Reason} -> 74 | case State of 75 | down -> 76 | NewState = down, 77 | loop([Host, Port], NewState); 78 | OldState -> 79 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=tcp_port, obj=ObjName, prev_state=OldState, new_state=down, ts=timestamp:now_i()}), 80 | NewState = down, 81 | loop([Host, Port], NewState) 82 | end 83 | end 84 | end. 85 | 86 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/basic.css: -------------------------------------------------------------------------------- 1 | /*** FONTS ***/ 2 | 3 | body, table, table td { font-size: 1em; font-family: "Lucida Grande", "Segoe UI", Tahoma, Helvetica, Arial, sans-serif; line-height: 1.7em; } 4 | 5 | h1 { font-family: 'Arial'; font-size: 2.2em; font-weight: bold; } 6 | h2 { font-family: 'Arial', Georgia; font-size: 1.7em; font-weight: bold; } 7 | h3 { font-family: 'Arial', Georgia; font-size: 1.2em; font-weight: bold; } 8 | h4 { font-family: 'Arial', Georgia; font-size: 0.9em; text-transform: uppercase; } 9 | 10 | a, a:visited { text-decoration: none; } 11 | a:hover, a:active { text-decoration: underline; } 12 | 13 | input[type=text], input[type=password], textarea { 14 | font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; font-weight: bold; font-size: 1.1em; line-height: 1.1em; 15 | } 16 | 17 | input[type=submit], input[type=button] { 18 | font-family: "Lucida Grande", "Segoe UI", Tahoma, Helvetica, Arial, sans-serif; font-size: 1em; 19 | } 20 | 21 | .big { font-size: 120%; line-height: 180%; } 22 | .small { font-size: 90%; } 23 | .error { font-size: 10px; } 24 | 25 | 26 | /*** COLORS ***/ 27 | 28 | body, table, table td { color: #525252; } 29 | 30 | a, a:visited, a:active, a:hover { color: #4488FF; } 31 | 32 | h1 { color: #000000; } 33 | h2 { color: #84B712; } 34 | h3 { color: #84B712; } 35 | h4 { color: #000000; } 36 | 37 | input[type=text], input[type=password], textarea { border: solid 1px #99AACC; } 38 | input[type=submit], input[type=button] { color: #333333; } 39 | input[type=submit]:HOVER, input[type=button]:HOVER { color: #3333FF; } 40 | 41 | .error { color: #ffff00; } 42 | 43 | hr { background-color: #E0E0E0; } 44 | 45 | /*** POSITIONING ***/ 46 | 47 | body, img, table, form { border: 0px; margin: 0px; padding: 0px} 48 | table td { vertical-align: top; padding: 4px 7px 4px 7px; } 49 | 50 | img { vertical-align: middle; } 51 | 52 | table { border-collapse:collapse; } 53 | 54 | p { clear: both; margin: 0px 0px 0px 0px; padding: 1em 0px 0px 0px; } 55 | 56 | h1 { margin: 0px 0px 0px 0px; padding: 0em 0px 0.75em 0px; } 57 | h2 { margin: 0px 0px 0px 0px; padding: 0em 0px 0.5em 0px; } 58 | h3 { margin: 0px 0px 0px 0px; padding: 0em 0px 0.5em 0px; } 59 | h4 { margin: 0px 0px 0px 0px; padding: 0.2em 0px 0.1em 0px; } 60 | 61 | input[type=text], input[type=password], textarea { padding: 5px 5px 5px 5px; margin: 0px 7px 0px 0px; } 62 | input[type=submit], input[type=button] { margin-right: 7px; } 63 | input[type=checkbox] { vertical-align: middle; margin-right: 10px; } 64 | label { vertical-align: middle; } 65 | hr { margin: 12px 0px 12px 0px; padding: 0px 0px 0px 0px; height: 1px; border: 0px; } 66 | .error { margin-top: 2px; } 67 | 68 | /*** EXTRAS ***/ 69 | :focus { outline: 0; } 70 | 71 | ul { 72 | list-style-type: disc; 73 | padding-left: 20px; 74 | padding-top: 7px; 75 | } 76 | 77 | 78 | 79 | .description { 80 | font-size: 0.8em; 81 | color: #000000; 82 | } 83 | -------------------------------------------------------------------------------- /erlmon-1.0/src/ps.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(ps). 3 | -author(darrik@darmsoft.com). 4 | 5 | -export([list/0]). 6 | -export([list/1]). 7 | -export([dump/1]). 8 | -export([find/1]). 9 | -export([pid_for_process/1]). 10 | -export([name_for_pid/1]). 11 | 12 | -include("include/erlmon.hrl"). 13 | 14 | list() -> 15 | list([]). 16 | 17 | list([]) -> 18 | Output = os:cmd("ps aux"), 19 | process(Output). 20 | 21 | process(Output) when is_list(Output) -> 22 | Lines = re:split(Output, "\n", [{return, list}]), 23 | [_Header|T] = Lines, 24 | create_records(T). 25 | 26 | create_records([H|T]) -> 27 | [create_record(H) | create_records(T)]; 28 | create_records([]) -> 29 | []. 30 | 31 | create_record([Head|[]]) -> create_record(Head); 32 | create_record([]) -> []; 33 | create_record(Line) -> 34 | Fields = re:split(Line, "\s+", [{return, list}]), 35 | [User, Pid, Cpu, Mem, Vsz, Rss, Tty, Stat, Start, Time | Cmd] = Fields, 36 | Rec = #process{user=User, pid=erlmon_helper:list_to_number(Pid), cpu=erlmon_helper:list_to_number(Cpu), mem=erlmon_helper:list_to_number(Mem), vsz=erlmon_helper:list_to_number(Vsz), rss=erlmon_helper:list_to_number(Rss), tty=Tty, stat=Stat, start=Start, time=Time, cmd=collapse(Cmd)}, 37 | Rec. 38 | 39 | dump([Process|T]) -> 40 | debug:log("~p", [Process]), 41 | dump(T). 42 | 43 | collapse([]) -> ""; 44 | collapse([I]) -> I; 45 | collapse([H|T]) -> 46 | H ++ " " ++ collapse(T). 47 | 48 | find(Pname) -> 49 | find(Pname, list()). 50 | 51 | find(Pname, [H = #process{cmd=Pname}|_T]) -> H; 52 | find(Pname, [_H|T]) -> 53 | find(Pname, T); 54 | find(_Pname, []) -> 55 | not_found. 56 | 57 | find_regex(Pregex) -> 58 | find_regex(Pregex, list()). 59 | 60 | find_regex(Pregex, [H|T]) -> 61 | #process{cmd=Pname} = H, 62 | REReturn = re:run(Pname, Pregex), 63 | case REReturn of 64 | {match, _} -> H; 65 | nomatch -> find_regex(Pregex, T) 66 | end; 67 | find_regex(_Pregex, []) -> 68 | not_found. 69 | 70 | find_pid(Pid) -> 71 | find_pid(Pid, list()). 72 | 73 | find_pid(Pid, [H = #process{pid=Pid}|_T]) -> H; 74 | find_pid(Pid, [_H|T]) -> find_pid(Pid, T); 75 | find_pid(_Pid, []) -> not_found. 76 | 77 | pid_for_process(Pname) -> 78 | Process = find(Pname), 79 | case Process of 80 | not_found -> pid_for_process_regex(Pname); 81 | P -> 82 | #process{pid=Pid} = P, 83 | Pid 84 | end. 85 | 86 | pid_for_process_regex(Pregex) -> 87 | Process = find_regex(Pregex), 88 | case Process of 89 | not_found -> null; 90 | P -> 91 | #process{pid=Pid} = P, 92 | Pid 93 | end. 94 | 95 | name_for_pid(Pid) when is_integer(Pid) -> 96 | Process = find_pid(lists:flatten(io_lib:format("~p", [Pid]))), 97 | case Process of 98 | not_found -> null; 99 | P -> 100 | #process{cmd=Cmd} = P, 101 | Cmd 102 | end; 103 | name_for_pid(Pid) -> 104 | Process = find_pid(Pid), 105 | case Process of 106 | not_found -> null; 107 | P -> 108 | #process{cmd=Cmd} = P, 109 | Cmd 110 | end. 111 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/elements.css: -------------------------------------------------------------------------------- 1 | .label { 2 | display: block; 3 | font-weight: bold; 4 | font-size: 0.9em; 5 | margin-top: 7px; 6 | } 7 | 8 | .value { 9 | display: block; 10 | font-weight: bold; 11 | padding: 0px 0px 0px 0px; 12 | margin-top: 2px; 13 | margin-bottom: 10px; 14 | color: #000000; 15 | } 16 | 17 | /*** ROUNDED PANEL ***/ 18 | table.rounded_panel.black td { background: #000000; } 19 | table.rounded_panel.gray td { background: #F1F1F1; } 20 | table.rounded_panel.black td { background: #000000; } 21 | table.rounded_panel.white td { background: #FFFFFF; } 22 | table.rounded_panel tr.chrome td { font-size: 1px; line-height: 1px; padding: 0 0 0 0; margin: 0 0 0 0; border: 0; } 23 | table.rounded_panel tr.chrome img { padding: 0 0 0 0; margin: 0 0 0 0; border: 0; } 24 | 25 | 26 | table.rounded_panel { margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px; border: 0px; } 27 | table.rounded_panel td { padding: 0px 0px 0px 0px; } 28 | table.rounded_panel td.content { padding: 4px 20px 4px 20px; } 29 | 30 | table.rounded_panel { margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px; border: 0px; } 31 | table.rounded_panel td { padding: 0px 0px 0px 0px; } 32 | table.rounded_panel td.content { padding: 4px 20px 4px 20px; } 33 | 34 | 35 | /*** INPLACE EDITING ***/ 36 | 37 | div.inplace_textbox div.view { 38 | cursor: pointer; 39 | } 40 | 41 | div.inplace_textbox .label { 42 | display: inline; 43 | } 44 | 45 | div.inplace_textbox .instructions { 46 | padding-left: 12px; 47 | font-size: 0.8em; 48 | } 49 | 50 | div.inplace_textbox .LV_invalid { 51 | position: relative; 52 | margin-right: 7px; 53 | color:#CC0000; 54 | background-color: #FFFF99; 55 | border: solid 2px #D0D0C0; 56 | } 57 | 58 | .flash_container { 59 | } 60 | 61 | .flash { 62 | color: #303030; 63 | background-color: #FAEC7F; 64 | border: #FFE800 solid 2px; 65 | padding: 3px 5px 3px 5px; 66 | margin-bottom: 7px; 67 | } 68 | 69 | .flash .flash_content { 70 | margin-right: 50px; 71 | } 72 | 73 | .flash .flash_close_button { 74 | float: right; 75 | font-size: 90%; 76 | } 77 | 78 | .wizard { 79 | } 80 | 81 | .wizard .wizard_title { 82 | font-family: 'Arial', Georgia; font-size: 1.2em; font-weight: bold; 83 | } 84 | 85 | .wizard .wizard_body { 86 | margin-top: 20px; 87 | margin-bottom: 20px; 88 | } 89 | 90 | .wizard .wizard_buttons { 91 | padding-right: 40px; 92 | text-align:right; 93 | } 94 | 95 | .wizard .wizard_buttons input { 96 | margin-right: 20px; 97 | } 98 | 99 | /*** VALIDATION ***/ 100 | 101 | .LV_validation_message { 102 | vertical-align: middle; 103 | display: inline; 104 | line-height: 100%; 105 | position: absolute; 106 | font-weight:bold; 107 | margin: 0px 0px 0px 7px; 108 | padding: 5px 7px 5px 7px; 109 | opacity: 0.8; 110 | -moz-opacity: 0.8; 111 | filter:alpha(opacity=80); 112 | } 113 | 114 | /* 115 | .LV_valid { 116 | background-image: url(/nitrogen/checkmark.png); 117 | margin: 2px 0px 5px 0px; 118 | padding: 0px 20px 20px 0px; 119 | color:#00CC00; 120 | } 121 | */ 122 | 123 | .LV_invalid { 124 | color:#CC0000; 125 | background-color: #FFFF99; 126 | border: solid 2px #D0D0C0; 127 | } 128 | 129 | /*.LV_valid_field, 130 | input.LV_valid_field:hover, 131 | input.LV_valid_field:active, 132 | textarea.LV_valid_field:hover, 133 | textarea.LV_valid_field:active { 134 | border: 1px solid #00CC00; 135 | } 136 | 137 | .LV_invalid_field, 138 | input.LV_invalid_field:hover, 139 | input.LV_invalid_field:active, 140 | textarea.LV_invalid_field:hover, 141 | textarea.LV_invalid_field:active { 142 | border: 1px solid #CC0000; 143 | }*/ -------------------------------------------------------------------------------- /erlmon-1.0/src/alert_handler.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(alert_handler). 3 | -author(darrik@darmasoft.com). 4 | 5 | -behaviour(gen_event). 6 | 7 | -include("include/erlmon.hrl"). 8 | 9 | -export([init/1]). 10 | -export([code_change/3]). 11 | -export([handle_state_change/2]). 12 | -export([handle_event/2]). 13 | -export([handle_call/3]). 14 | -export([handle_cast/2]). 15 | -export([handle_info/2]). 16 | -export([terminate/2]). 17 | -export([test/0]). 18 | -export([register_alert_filter/1]). 19 | -export([unregister_alert_filter/1]). 20 | -export([match_all_filter/1]). 21 | 22 | init(_) -> 23 | {ok, []}. 24 | 25 | handle_event(#state_change{}=Event, State) -> 26 | debug:log("alert_handler:state_change: ~p", [Event]), 27 | dispatch_state_change(Event, State), 28 | {ok, State}; 29 | handle_event({add_alert_filter, #alert_filter{}=AF}, State) -> 30 | debug:log("alert_handler:add_alert_filter: ~p", [AF]), 31 | NewState = add_filter(AF, State), 32 | {ok, NewState}; 33 | handle_event({remove_alert_filter, #alert_filter{}=AF}, State) -> 34 | debug:log("alert_handler:remove_alert_filter: ~p", [AF]), 35 | NewState = remove_filter(AF, State), 36 | {ok, NewState}; 37 | handle_event(_Event, State) -> 38 | {ok, State}. 39 | 40 | handle_call(_Request, _From, State) -> 41 | Reply = ok, 42 | {reply, Reply, State}. 43 | 44 | handle_cast(_Msg, State) -> 45 | {noreply, State}. 46 | 47 | handle_info(_Info, State) -> 48 | {noreply, State}. 49 | 50 | terminate(_Args, _State) -> 51 | ok. 52 | 53 | add_filter(AF, [AF|_T]=State) -> 54 | debug:log("alert_handler: alert_filter already exists"), 55 | State; 56 | add_filter(AF, [H|T]) -> 57 | [H|add_filter(AF, T)]; 58 | add_filter(AF, []) -> 59 | debug:log("alert_handler: alert_filter added"), 60 | [AF]. 61 | 62 | remove_filter(AF, [AF|T]) -> 63 | debug:log("alert_handler: alert_filter removed"), 64 | T; 65 | remove_filter(AF, [H|T]) -> 66 | [H|remove_filter(AF, T)]; 67 | remove_filter(_AF, []) -> 68 | debug:log("alert_handler: alert_filter does not exist"), 69 | []. 70 | 71 | register_alert_filter(#alert_filter{}=AF) -> 72 | state_change_em:notify({add_alert_filter, AF}). 73 | 74 | unregister_alert_filter(#alert_filter{}=AF) -> 75 | state_change_em:notify({remove_alert_filter, AF}). 76 | 77 | test() -> 78 | SC = #state_change{sender=nil, node=nil, objtype=file, obj=nil, prev_state=nil, new_state=file_ctime_changed, ts=nil}, 79 | SF = #state_change_filter{state_change=SC, fields=[objtype, new_state]}, 80 | #alert_filter{scf=SF, to="darrik@darmasoft.com"}. 81 | 82 | code_change(_OldVsn, State, _Extra) -> 83 | {ok, State}. 84 | 85 | dispatch_state_change(#state_change{}=SC, State) -> 86 | debug:log("alert_handler: handling state_change for ~p:~p", [SC#state_change.objtype, SC#state_change.obj]), 87 | spawn(?MODULE, handle_state_change, [SC, State]), 88 | ok. 89 | 90 | handle_state_change(SC, [#alert_filter{scf=#state_change_filter{}=SCF, to=ToAddress}|T]) -> 91 | case state_change:match(SC, SCF) of 92 | true -> 93 | debug:log("alert_handler: ~p:~p (~p -> ~p) matched filter!", [SC#state_change.objtype, SC#state_change.obj, SC#state_change.prev_state, SC#state_change.new_state]), 94 | erlmon_smtp:alert(SC, ToAddress), 95 | alert_sent; 96 | false -> 97 | handle_state_change(SC, T) 98 | end; 99 | handle_state_change(SC, [_H|T]) -> 100 | handle_state_change(SC, T); 101 | handle_state_change(SC, []) -> 102 | debug:log("alert_handler: ~p:~p (~p -> ~p) did not match any filters", [SC#state_change.objtype, SC#state_change.obj, SC#state_change.prev_state, SC#state_change.new_state]), 103 | no_alert. 104 | 105 | match_all_filter(ToAddress) -> 106 | SC = #state_change{sender=nil, node=nil, objtype=nil, obj=nil, prev_state=nil, new_state=nil, ts=nil}, 107 | SCF = #state_change_filter{state_change=SC, fields=[]}, 108 | #alert_filter{scf=SCF, to=ToAddress}. 109 | 110 | -------------------------------------------------------------------------------- /erlmon-1.0/src/process_list.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(process_list). 3 | -author(darrik@darmasoft.com). 4 | 5 | -include("include/erlmon.hrl"). 6 | 7 | -define(TIMEOUT, 5000). 8 | 9 | -export([ 10 | start_link/0, 11 | init/1, 12 | handle_call/3, 13 | handle_cast/2, 14 | handle_info/2, 15 | terminate/2, 16 | code_change/3 17 | ]). 18 | 19 | -export([ 20 | count/0, 21 | get_by_regexp/1, 22 | get_by_cmd/1, 23 | get_by_user/1, 24 | get_by_pid/1, 25 | list/0, 26 | refresh/0, 27 | refresh_timer/1 28 | ]). 29 | 30 | start_link() -> 31 | R = gen_server:start_link({local, ?MODULE}, ?MODULE, [], []), 32 | spawn(process_list, refresh_timer, [?TIMEOUT]), 33 | R. 34 | 35 | init([]) -> 36 | {ok, []}. 37 | 38 | handle_call({count}, _From, State) -> 39 | Response = length(State), 40 | {reply, Response, State}; 41 | handle_call({get, regexp, CmdRe}, _From, State) -> 42 | Response = get_processes_by_cmd_re(CmdRe, State), 43 | {reply, Response, State}; 44 | handle_call({get, pid, Pid}, _From, State) -> 45 | Response = get_processes_by_pid(Pid, State), 46 | {reply, Response, State}; 47 | handle_call({get, user, User}, _From, State) -> 48 | Response = get_processes_by_user(User, State), 49 | {reply, Response, State}; 50 | handle_call({get, cmd, Cmd}, _From, State) -> 51 | Response = get_processes_by_cmd(Cmd, State), 52 | {reply, Response, State}; 53 | handle_call({list}, _From, State) -> 54 | Response = {ok, State}, 55 | {reply, Response, State}; 56 | handle_call(_Msg, _From, State) -> 57 | Response = {error, unknown_call}, 58 | {reply, Response, State}. 59 | 60 | handle_cast({refresh}, _State) -> 61 | NewState = ps:list(), 62 | {noreply, NewState}; 63 | handle_cast(_Msg, State) -> 64 | {noreply, State}. 65 | 66 | handle_info(_Msg, State) -> 67 | {noreply, State}. 68 | 69 | terminate(_Reason, _State) -> 70 | ok. 71 | 72 | code_change(_OldVersion, State, _Extra) -> 73 | {ok, State}. 74 | 75 | list() -> 76 | gen_server:call(?MODULE, {list}). 77 | 78 | refresh() -> 79 | R = gen_server:cast(?MODULE, {refresh}), 80 | spawn(process_list, refresh_timer, [?TIMEOUT]), 81 | R. 82 | 83 | count() -> 84 | gen_server:call(?MODULE, {count}). 85 | 86 | get_by_pid(Pid) -> 87 | gen_server:call(?MODULE, {get, pid, Pid}). 88 | 89 | get_by_user(User) -> 90 | gen_server:call(?MODULE, {get, user, User}). 91 | 92 | get_by_cmd(Cmd) -> 93 | gen_server:call(?MODULE, {get, cmd, Cmd}). 94 | 95 | get_by_regexp(CmdRe) -> 96 | gen_server:call(?MODULE, {get, regexp, CmdRe}). 97 | 98 | 99 | get_processes_by_pid(Pid, State) when is_list(Pid) -> 100 | PidInt = list_to_integer(Pid), 101 | get_processes_by_pid(PidInt, State); 102 | get_processes_by_pid(Pid, [#process{pid=Pid}=Process|T]) -> 103 | [Process|get_processes_by_pid(Pid, T)]; 104 | get_processes_by_pid(Pid, [_H|T]) -> 105 | get_processes_by_pid(Pid, T); 106 | get_processes_by_pid(_Pid, []) -> 107 | []. 108 | 109 | get_processes_by_user(User, [#process{user=User}=Process|T]) -> 110 | [Process|get_processes_by_user(User, T)]; 111 | get_processes_by_user(User, [_H|T]) -> 112 | get_processes_by_user(User, T); 113 | get_processes_by_user(_User, []) -> 114 | []. 115 | 116 | get_processes_by_cmd(Cmd, [#process{cmd=Cmd}=Process|T]) -> 117 | [Process|get_processes_by_cmd(Cmd, T)]; 118 | get_processes_by_cmd(Cmd, [_H|T]) -> 119 | get_processes_by_cmd(Cmd, T); 120 | get_processes_by_cmd(_Cmd, []) -> 121 | []. 122 | 123 | get_processes_by_cmd_re(CmdRe, [#process{cmd=Cmd}=Process|T]) -> 124 | ReRet = re:run(Cmd, CmdRe), 125 | case ReRet of 126 | {match, _} -> [Process|get_processes_by_cmd_re(CmdRe, T)]; 127 | nomatch -> get_processes_by_cmd_re(CmdRe, T) 128 | end; 129 | get_processes_by_cmd_re(CmdRe, [_H|T]) -> 130 | get_processes_by_cmd_re(CmdRe, T); 131 | get_processes_by_cmd_re(_CmdRe, []) -> 132 | []. 133 | 134 | refresh_timer(T) -> 135 | receive 136 | after 137 | T -> 138 | refresh() 139 | end. 140 | 141 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/lunit: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # This file is part of lunit 0.5. 4 | # 5 | # For Details about lunit look at: http://www.mroth.net/lunit/ 6 | # 7 | # Author: Michael Roth 8 | # 9 | # Copyright (c) 2004-2009 Michael Roth 10 | # 11 | # Permission is hereby granted, free of charge, to any person 12 | # obtaining a copy of this software and associated documentation 13 | # files (the "Software"), to deal in the Software without restriction, 14 | # including without limitation the rights to use, copy, modify, merge, 15 | # publish, distribute, sublicense, and/or sell copies of the Software, 16 | # and to permit persons to whom the Software is furnished to do so, 17 | # subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be 20 | # included in all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 27 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | 31 | if test $# = 0 ; then 32 | echo "$0: Usage Error. Try $0 --help" >&2 33 | exit 1 34 | fi 35 | 36 | if [ `uname` = "Darwin" ]; then 37 | scriptname="$(readlink -n "$0")" 38 | else 39 | scriptname="$(readlink -n -f "$0")" 40 | fi 41 | interpreter="lua" 42 | options="" 43 | 44 | while true ; do 45 | case "$1" in 46 | -h|--help) 47 | cat < 50 | This program comes WITHOUT WARRANTY OF ANY KIND. 51 | 52 | Usage: lunit [OPTIONS] [--] scripts 53 | 54 | Options: 55 | 56 | -i, --interpreter LUA Complete path of the lua binary to use. 57 | -p, --path PATH Sets the LUA_PATH environment for the tests. 58 | --cpath CPATH Sets the LUA_CPATH environment for the tests. 59 | -r, --runner RUNNER Testrunner to use, defaults to 'lunit-console'. 60 | -t, --test PATTERN Which tests to run, may contain * or ? wildcards. 61 | --loadonly Only load the tests. 62 | --dontforce Do not force to load $scriptname*.lua. 63 | -h, --help Print this help screen. 64 | --version Print lunit version. 65 | 66 | Please report bugs to . 67 | EOT 68 | exit ;; 69 | 70 | --version) 71 | echo "lunit 0.5 Copyright 2004-2009 Michael Roth " 72 | exit ;; 73 | 74 | -i|--interpreter) 75 | interpreter="$2" 76 | shift 2 ;; 77 | 78 | -p|--path) 79 | LUA_PATH="$2" 80 | export LUA_PATH 81 | shift 2 ;; 82 | 83 | --cpath) 84 | LUA_CPATH="$2" 85 | export LUA_CPATH 86 | shift 2 ;; 87 | 88 | --loadonly) 89 | options="$options $1" 90 | shift 1 ;; 91 | 92 | --dontforce) 93 | scriptname="" 94 | shift 1 ;; 95 | 96 | -r|--runner|-t|--test) 97 | options="$options $1 $2" 98 | shift 2 ;; 99 | 100 | --) 101 | break ;; 102 | 103 | -*) 104 | echo "$0: Invalid option: $1" >&2 105 | exit 1 ;; 106 | 107 | *) 108 | break ;; 109 | esac 110 | done 111 | 112 | 113 | exec "$interpreter" - "$scriptname" $options "$@" < 0 or stats.failed > 0 then 126 | os.exit(1) 127 | end 128 | EOT 129 | -------------------------------------------------------------------------------- /erlmon-1.0/lua/lunit-console.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[-------------------------------------------------------------------------- 3 | 4 | This file is part of lunit 0.5. 5 | 6 | For Details about lunit look at: http://www.mroth.net/lunit/ 7 | 8 | Author: Michael Roth 9 | 10 | Copyright (c) 2006-2008 Michael Roth 11 | 12 | Permission is hereby granted, free of charge, to any person 13 | obtaining a copy of this software and associated documentation 14 | files (the "Software"), to deal in the Software without restriction, 15 | including without limitation the rights to use, copy, modify, merge, 16 | publish, distribute, sublicense, and/or sell copies of the Software, 17 | and to permit persons to whom the Software is furnished to do so, 18 | subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 27 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 28 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 29 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | --]]-------------------------------------------------------------------------- 32 | 33 | 34 | 35 | --[[ 36 | 37 | begin() 38 | run(testcasename, testname) 39 | err(fullname, message, traceback) 40 | fail(fullname, where, message, usermessage) 41 | pass(testcasename, testname) 42 | done() 43 | 44 | Fullname: 45 | testcase.testname 46 | testcase.testname:setupname 47 | testcase.testname:teardownname 48 | 49 | --]] 50 | 51 | 52 | require "lunit" 53 | 54 | module( "lunit-console", package.seeall ) 55 | 56 | 57 | local function printformat(format, ...) 58 | io.write( string.format(format, ...) ) 59 | end 60 | 61 | 62 | local columns_printed = 0 63 | 64 | local function writestatus(char) 65 | if columns_printed == 0 then 66 | io.write(" ") 67 | end 68 | if columns_printed == 60 then 69 | io.write("\n ") 70 | columns_printed = 0 71 | end 72 | io.write(char) 73 | io.flush() 74 | columns_printed = columns_printed + 1 75 | end 76 | 77 | 78 | local msgs = {} 79 | 80 | 81 | function begin() 82 | local total_tc = 0 83 | local total_tests = 0 84 | 85 | for tcname in lunit.testcases() do 86 | total_tc = total_tc + 1 87 | for testname, test in lunit.tests(tcname) do 88 | total_tests = total_tests + 1 89 | end 90 | end 91 | 92 | printformat("Loaded testsuite with %d tests in %d testcases.\n\n", total_tests, total_tc) 93 | end 94 | 95 | 96 | function run(testcasename, testname) 97 | -- NOP 98 | end 99 | 100 | 101 | function err(fullname, message, traceback) 102 | writestatus("E") 103 | msgs[#msgs+1] = "Error! ("..fullname.."):\n"..message.."\n\t"..table.concat(traceback, "\n\t") .. "\n" 104 | end 105 | 106 | 107 | function fail(fullname, where, message, usermessage) 108 | writestatus("F") 109 | local text = "Failure ("..fullname.."):\n".. 110 | where..": "..message.."\n" 111 | 112 | if usermessage then 113 | text = text .. where..": "..usermessage.."\n" 114 | end 115 | 116 | msgs[#msgs+1] = text 117 | end 118 | 119 | 120 | function pass(testcasename, testname) 121 | writestatus(".") 122 | end 123 | 124 | 125 | 126 | function done() 127 | printformat("\n\n%d Assertions checked.\n", lunit.stats.assertions ) 128 | print() 129 | 130 | for i, msg in ipairs(msgs) do 131 | printformat( "%3d) %s\n", i, msg ) 132 | end 133 | 134 | printformat("Testsuite finished (%d passed, %d failed, %d errors).\n", 135 | lunit.stats.passed, lunit.stats.failed, lunit.stats.errors ) 136 | end 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/template.html: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 | [[[page:title()]]] 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
    32 | 49 |
    50 |
    51 | [[[page:body()]]] 52 |
    53 | 56 |
    57 | 62 |
    63 |
    64 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /erlmon-1.0/src/storage.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(storage). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/0]). 6 | -export([init/0]). 7 | 8 | -export([announce/2]). 9 | 10 | -export([state_change/1]). 11 | -export([alert_sent/1]). 12 | 13 | -export([test/2]). 14 | -export([status/0]). 15 | 16 | -include("include/erlmon.hrl"). 17 | 18 | start() -> 19 | debug:log_to(console, {}), 20 | register(?MODULE, Pid=spawn_link(?MODULE, init, [])), 21 | {ok, Pid}. 22 | 23 | init() -> 24 | debug:log("storage: initializing"), 25 | debug:log("storage: touching world"), 26 | Nodes = net_adm:world(), 27 | debug:log("storage: found ~p", [Nodes]), 28 | NodeCount = length(Nodes), 29 | case NodeCount > 1 of 30 | true -> 31 | debug:log("storage: we are not the first; announcing"), 32 | init_storage(false), 33 | announce_storage_to_nodes(Nodes); 34 | false -> 35 | debug:log("storage: we are first; initializing"), 36 | init_storage(true) 37 | end, 38 | erlmon:finished(?MODULE), 39 | loop([]). 40 | 41 | loop(State) -> 42 | receive 43 | {Sender, status} -> 44 | debug:log("storage: received status request"), 45 | Sender ! {ok, ok}, 46 | loop(State); 47 | Msg = #state_change{} -> 48 | debug:log("storage: received state_change"), 49 | store(Msg), 50 | loop(State); 51 | #sent_alert{}=Alert -> 52 | debug:log("storage: received sent_alert"), 53 | store(Alert), 54 | loop(State); 55 | #storage_ack_announce{sender=Sender, node=Node} -> 56 | debug:log("storage: received ACK announce from ~p on ~p", [Sender, Node]), 57 | loop(State); 58 | #storage_announce{sender=Sender, node=Node} -> 59 | debug:log("storage: received announce from ~p on ~p", [Sender, Node]), 60 | copy_storage_to_node(Node), 61 | Sender ! #storage_ack_announce{sender=self(), node=node()}, 62 | loop(State); 63 | M -> 64 | debug:log("storage: UNKNOWN: ~p", [M]), 65 | loop(State) 66 | end. 67 | 68 | announce(Sender, Node) -> 69 | storage ! #storage_announce{sender=Sender, node=Node}, 70 | ok. 71 | 72 | announce_storage_to_nodes([Node|T]) when Node =:= node() -> 73 | debug:log("storage: not announcing to self"), 74 | announce_storage_to_nodes(T); 75 | announce_storage_to_nodes([Node|T]) -> 76 | debug:log("storage: announcing to ~p", [Node]), 77 | Pid = rpc:call(Node, erlang, whereis, [storage]), 78 | debug:log("storage: found storage at ~p on ~p", [Pid, Node]), 79 | Pid ! #storage_announce{sender=self(), node=node()}, 80 | announce_storage_to_nodes(T); 81 | announce_storage_to_nodes([]) -> ok. 82 | 83 | init_storage(false) -> 84 | debug:log("storage: initializing storage"), 85 | mnesia:start(); 86 | init_storage(true) -> 87 | init_storage(false), 88 | debug:log("storage: initializing schema"), 89 | mnesia:change_table_copy_type(schema, node(), ram_copies), 90 | create_tables(), 91 | wait_for_tables(). 92 | 93 | create_tables() -> 94 | mnesia:create_table(test, [{attributes, record_info(fields, test)}, {type, bag}, {ram_copies, [node()]}]), 95 | mnesia:create_table(state_change, [{attributes, record_info(fields, state_change)}, {type, bag}, {ram_copies, [node()]}]), 96 | mnesia:create_table(sent_alert, [{attributes, record_info(fields, sent_alert)}, {type, bag}, {ram_copies, [node()]}]). 97 | 98 | copy_tables(Node) -> 99 | _R1 = mnesia:add_table_copy(test, Node, ram_copies), 100 | _R2 = mnesia:add_table_copy(state_change, Node, ram_copies), 101 | _R3 = mnesia:add_table_copy(sent_alert, Node, ram_copies). 102 | 103 | wait_for_tables() -> 104 | mnesia:wait_for_tables([test, state_change, sent_alert], 10000). 105 | 106 | copy_storage_to_node(Node) -> 107 | debug:log("storage: copying storage to ~p", [Node]), 108 | _R1 = mnesia:change_config(extra_db_nodes, [Node]), 109 | _R2 = mnesia:change_table_copy_type(schema, Node, ram_copies), 110 | copy_tables(Node). 111 | 112 | test(K, V) -> 113 | Row = #test{key=K, value=V}, 114 | F = fun() -> 115 | mnesia:write(Row) 116 | end, 117 | mnesia:transaction(F). 118 | 119 | state_change(Msg) -> 120 | storage ! Msg. 121 | 122 | alert_sent(Msg) -> 123 | storage ! Msg. 124 | 125 | store(Msg) -> 126 | F = fun() -> mnesia:write(Msg) end, 127 | mnesia:transaction(F). 128 | 129 | status() -> 130 | storage ! {self(), status}, 131 | receive 132 | {ok, Status} -> ok 133 | end, 134 | Status. 135 | -------------------------------------------------------------------------------- /erlmon-1.0/src/state_change.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(state_change). 3 | -author(darrik@darmasoft.com). 4 | 5 | -include("include/erlmon.hrl"). 6 | 7 | -export([match/3]). 8 | -export([match/2]). 9 | -export([collect_booleans/1]). 10 | -export([and_booleans/1]). 11 | -export([match_field/3]). 12 | -export([test_same/0, test_diff/0, test_filter/0]). 13 | 14 | match(#state_change{}=SCA, #state_change_filter{state_change=SCB, fields=Fields}) -> 15 | match(SCA, SCB, Fields). 16 | 17 | match(#state_change{}=SCA, #state_change{}=SCB, Fields) when is_list(Fields) -> 18 | and_booleans(match_fields(SCA, SCB, Fields)). 19 | 20 | match_fields(#state_change{}=SCA, #state_change{}=SCB, [Field|T]=Fields) when is_list(Fields) -> 21 | [match_field(SCA, SCB, Field)|match(SCA, SCB, T)]; 22 | match_fields(#state_change{}, #state_change{}, []) -> 23 | []. 24 | 25 | 26 | match_field(#state_change{}=SCA, #state_change{}=SCB, sender) -> 27 | case {SCA#state_change.sender, SCB#state_change.sender} of 28 | {_A, _A} -> 29 | true; 30 | {_A, _B} -> 31 | false 32 | end; 33 | match_field(#state_change{}=SCA, #state_change{}=SCB, node) -> 34 | case {SCA#state_change.node, SCB#state_change.node} of 35 | {_A, _A} -> 36 | true; 37 | {_A, _B} -> 38 | false 39 | end; 40 | match_field(#state_change{}=SCA, #state_change{}=SCB, objtype) -> 41 | case {SCA#state_change.objtype, SCB#state_change.objtype} of 42 | {_A, _A} -> 43 | true; 44 | {_A, _B} -> 45 | false 46 | end; 47 | match_field(#state_change{}=SCA, #state_change{}=SCB, obj) -> 48 | case {SCA#state_change.obj, SCB#state_change.obj} of 49 | {_A, _A} -> 50 | true; 51 | {_A, _B} -> 52 | false 53 | end; 54 | match_field(#state_change{}=SCA, #state_change{}=SCB, prev_state) -> 55 | case {SCA#state_change.prev_state, SCB#state_change.prev_state} of 56 | {_A, _A} -> 57 | true; 58 | {_A, _B} -> 59 | false 60 | end; 61 | match_field(#state_change{}=SCA, #state_change{}=SCB, new_state) -> 62 | case {SCA#state_change.new_state, SCB#state_change.new_state} of 63 | {_A, _A} -> 64 | true; 65 | {_A, _B} -> 66 | false 67 | end; 68 | match_field(#state_change{}=SCA, #state_change{}=SCB, data) -> 69 | case {SCA#state_change.data, SCB#state_change.data} of 70 | {_A, _A} -> 71 | true; 72 | {_A, _B} -> 73 | false 74 | end; 75 | match_field(#state_change{}=SCA, #state_change{}=SCB, ts) -> 76 | case {SCA#state_change.ts, SCB#state_change.ts} of 77 | {_A, _A} -> 78 | true; 79 | {_A, _B} -> 80 | false 81 | end; 82 | match_field(#state_change{}, #state_change{}, _Field) -> 83 | true. 84 | 85 | 86 | collect_booleans([true, true|T]) -> 87 | collect_booleans([true|T]); 88 | collect_booleans([false, false|T]) -> 89 | collect_booleans([false|T]); 90 | collect_booleans([true, false|T]) -> 91 | [true|collect_booleans([false|T])]; 92 | collect_booleans([false, true|T]) -> 93 | [false|collect_booleans([true|T])]; 94 | collect_booleans([true]) -> 95 | [true]; 96 | collect_booleans([false]) -> 97 | [false]; 98 | collect_booleans([]) -> 99 | []. 100 | 101 | and_booleans([true|T]) -> 102 | and_booleans(T); 103 | and_booleans([false|_T]) -> 104 | false; 105 | and_booleans(true) -> 106 | true; 107 | and_booleans(false) -> 108 | false; 109 | and_booleans([]) -> 110 | true. 111 | 112 | test_same() -> 113 | SCA = #state_change{sender=self(), node=node(), objtype=file, obj="config.lua", prev_state=unchanged, new_state=file_ctime_changed, ts=timestamp:now_i()}, 114 | SCB = #state_change{sender=self(), node=node(), objtype=file, obj="config.lua", prev_state=unchanged, new_state=file_ctime_changed, ts=timestamp:now_i()}, 115 | [SCA, SCB]. 116 | 117 | test_diff() -> 118 | SCA = #state_change{sender=self(), node=node(), objtype=tcp_port, obj="localhost:22", prev_state=down, new_state=up, ts=timestamp:now_i()}, 119 | SCB = #state_change{sender=self(), node=node(), objtype=tcp_port, obj="localhost:22", prev_state=up, new_state=down, ts=timestamp:now_i()}, 120 | [SCA, SCB]. 121 | 122 | test_filter() -> 123 | SCA = #state_change{sender=self(), node=node(), objtype=tcp_port, obj="localhost:22", prev_state=down, new_state=up, ts=timestamp:now_i()}, 124 | SCB = #state_change{sender=self(), node=node(), objtype=tcp_port, obj="localhost:22", prev_state=up, new_state=down, ts=timestamp:now_i()}, 125 | Fields = [objtype, obj], 126 | SCF = #state_change_filter{state_change=SCB, fields=Fields}, 127 | [SCA, SCF]. 128 | -------------------------------------------------------------------------------- /erlmon-1.0/src/process_monitor.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(process_monitor). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/1]). 6 | -export([init/1]). 7 | -export([monitor/1]). 8 | -export([unmonitor/1]). 9 | -export([status/0]). 10 | -export([status/1]). 11 | 12 | -include("include/erlmon.hrl"). 13 | 14 | status() -> 15 | process_monitor_man:status(). 16 | 17 | status(_Pid) -> 18 | {ok, running}. 19 | 20 | monitor(ProcessName) -> 21 | process_monitor_man:monitor(ProcessName). 22 | 23 | unmonitor(ProcessName) -> 24 | process_monitor_man:unmonitor(ProcessName). 25 | 26 | start(ProcessName) -> 27 | {ok, spawn_link(?MODULE, init, [ProcessName])}. 28 | 29 | init(Pid) when is_integer(Pid) -> 30 | debug:log("process_monitor: starting for ~p", [Pid]), 31 | Name = ps:name_for_pid(Pid), 32 | case Name of 33 | null -> 34 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=Pid, prev_state=unknown, new_state=not_running, ts=timestamp:now_i()}); 35 | P -> 36 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=P, prev_state=unknown, new_state=running, ts=timestamp:now_i()}), 37 | loop(lists:flatten(io_lib:format("~p", [Pid])), P, running) 38 | end; 39 | init(ProcessName) -> 40 | debug:log("process_monitor: starting for ~p", [ProcessName]), 41 | Pid = ps:pid_for_process(ProcessName), 42 | case Pid of 43 | null -> 44 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=unknown, new_state=not_running, ts=timestamp:now_i()}), 45 | loop(null, ProcessName, not_running); 46 | P -> 47 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=unknown, new_state=running, ts=timestamp:now_i()}), 48 | loop(P, ProcessName, running) 49 | end. 50 | 51 | loop(Pid, ProcessName, running) -> 52 | receive 53 | stop -> 54 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=running, new_state=unmonitored, ts=timestamp:now_i()}) 55 | after 56 | 3000 -> 57 | Cpid = ps:pid_for_process(ProcessName), 58 | case Cpid of 59 | null -> 60 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=running, new_state=not_running, ts=timestamp:now_i()}), 61 | loop(null, ProcessName, not_running); 62 | Pid -> 63 | loop(Pid, ProcessName, running); 64 | NewPid -> 65 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=running, new_state=restarted, ts=timestamp:now_i()}), 66 | loop(NewPid, ProcessName, restarted) 67 | end 68 | end; 69 | loop(null, ProcessName, not_running) -> 70 | receive 71 | stop -> 72 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=not_running, new_state=unmonitored, ts=timestamp:now_i()}) 73 | after 74 | 3000 -> 75 | Cpid = ps:pid_for_process(ProcessName), 76 | case Cpid of 77 | null -> 78 | loop(null, ProcessName, not_running); 79 | Pid -> 80 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=not_running, new_state=running, ts=timestamp:now_i()}), 81 | loop(Pid, ProcessName, running) 82 | end 83 | end; 84 | loop(Pid, ProcessName, restarted) -> 85 | receive 86 | stop -> 87 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=restarted, new_state=unmonitored, ts=timestamp:now_i()}) 88 | after 89 | 3000 -> 90 | Cpid = ps:pid_for_process(ProcessName), 91 | case Cpid of 92 | null -> 93 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=restarted, new_state=not_running, ts=timestamp:now_i()}), 94 | loop(null, ProcessName, not_running); 95 | Pid -> 96 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=restarted, new_state=running, ts=timestamp:now_i()}), 97 | loop(Pid, ProcessName, running); 98 | NewPid -> 99 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=process, obj=ProcessName, prev_state=restarted, new_state=restarted, ts=timestamp:now_i()}), 100 | loop(NewPid, ProcessName, restarted) 101 | end 102 | end. 103 | -------------------------------------------------------------------------------- /erlmon-1.0/src/config.erl: -------------------------------------------------------------------------------- 1 | -module(config). 2 | -behaviour(gen_server). 3 | -author(chad@inakanetworks.com). 4 | -include("include/erlmon.hrl"). 5 | -include("include/config.hrl"). 6 | -include_lib("eunit/include/eunit.hrl"). 7 | -define(SERVER, {global, ?MODULE}). 8 | -define(CONFIG_FILE, "config.lua"). 9 | 10 | -export([ 11 | authenticate/2, 12 | reload/0, 13 | setting/1, 14 | settings/0, 15 | start_link/0, 16 | update_file/1 ]). 17 | 18 | %% gen_server callbacks 19 | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, 20 | terminate/2, code_change/3]). 21 | 22 | %% The config system is the glue between the lua configuration 23 | %% code and the Erlang system. The goal of the system is for 24 | %% each piece to do as little as possible. In this case, the config 25 | %% system simply starts a special case file_monitor that watches the 26 | %% erlmon config file. When a change is detected the file is reloaded. 27 | 28 | reload() -> 29 | debug:log("CONFIG:reload"), 30 | gen_server:call(config, {reload,event}). 31 | 32 | update_file(Content) -> 33 | file:write_file(?CONFIG_FILE,Content). 34 | 35 | authenticate(Login,Password) -> 36 | debug:log("CONFIG:authenticating"), 37 | gen_server:call(config, {authenticate, Login, Password}). 38 | 39 | %% config settings can be accessed as: 40 | %% config:setting([smtp,auth,username]) => "bob" 41 | 42 | settings() -> 43 | gen_server:call(config,erlmon). 44 | 45 | setting(Type) when is_atom(Type) -> 46 | setting([Type]); 47 | 48 | setting(Types) -> 49 | Settings = gen_server:call(config,erlmon), 50 | find_setting(Settings,Types). 51 | 52 | find_setting(Settings,[Type|Types]) -> 53 | Result = lists:keyfind(atom_to_list(Type),1,Settings), 54 | case Result of 55 | false -> 56 | Result; 57 | {_Name,NewSettings} -> find_setting(NewSettings,Types) 58 | end; 59 | 60 | find_setting(Settings,[]) -> 61 | Settings. 62 | 63 | start_link() -> 64 | gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 65 | 66 | init([]) -> 67 | debug:log("CONFIG: init~n"), 68 | {ok,State} = lua:new_state(), 69 | debug:log("CONFIG: lua state initialized. ~n"), 70 | erlmon:finished(?MODULE), 71 | {ok, #config_state{lua_state=State}}. 72 | 73 | %% reload config 74 | handle_call({reload,_ReloadType}, _From, _State) -> 75 | debug:log("CONFIG: loading lua file"), 76 | {ok, L} = lua:new_state(), 77 | NewState = #config_state{lua_state=L}, 78 | Reply = lua:dofile(L,?CONFIG_FILE), 79 | case Reply of 80 | {error,_} -> 81 | debug:log("CONFIG: error in configuration file, NOT reloading.",[]), 82 | {reply, Reply, _State}; 83 | _ -> 84 | Config = lua:gettable(L,global,"Erlmon"), 85 | 86 | {"monitors",Methods} = lists:keyfind("monitors",1,Config), 87 | {"list",Monitors} = lists:keyfind("list",1,Methods), 88 | apply_config_list(Monitors), 89 | debug:log("CONFIG: reloaded"), 90 | {reply, Reply, NewState} 91 | end; 92 | 93 | handle_call(lua_state, _From, State) -> 94 | {reply,State#config_state.lua_state,State}; 95 | 96 | handle_call(erlmon, _From, State) -> 97 | L = State#config_state.lua_state, 98 | Reply = lua:gettable(L,global,"Erlmon"), 99 | {reply,Reply,State}; 100 | 101 | %% call lua authenticate method 102 | handle_call({authenticate, Login, Password}, _From, State) -> 103 | L = State#config_state.lua_state, 104 | lua:getfield(L, global, "authenticate"), 105 | lua:pushstring(L, Login), 106 | lua:pushstring(L, Password), 107 | lua:call(L, 2, 1), 108 | {ok,boolean,Reply} = lua:pop(L), 109 | debug:log("CONFIG: Authenticate: Lua returned: ~p",[Reply]), 110 | {reply, Reply, State}; 111 | 112 | handle_call(_Request, _From, State) -> 113 | Reply = ok, 114 | {reply, Reply, State}. 115 | 116 | handle_cast(_Msg, State) -> 117 | {noreply, State}. 118 | 119 | handle_info(_Info, State) -> 120 | {noreply, State}. 121 | 122 | terminate(_Reason, _State) -> 123 | ok. 124 | 125 | code_change(_OldVsn, State, _Extra) -> 126 | {ok, State}. 127 | 128 | apply_config_list(List) -> 129 | lists:map(fun({Monitor,MonitorList}) -> apply_monitors(Monitor,MonitorList) end,List), 130 | ok. 131 | 132 | apply_monitors(Monitor,MonitorList) -> 133 | debug:log("CONFIG: Telling monitor ~p to start the following monitors: ~p ",[Monitor,MonitorList]), 134 | Mod = list_to_atom(Monitor ++ "_monitor"), 135 | erlang:apply(Mod, monitor, [MonitorList]), 136 | ok. 137 | 138 | %% testcases 139 | config_test() -> ok. 140 | -------------------------------------------------------------------------------- /erlmon-1.0/src/erlmon_smtp.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erlmon_smtp). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start_link/0]). 6 | -export([init/0]). 7 | -export([status/0]). 8 | -export([get_config/0]). 9 | -export([config/0]). 10 | -export([config/1]). 11 | -export([alert/2]). 12 | 13 | -include("include/erlmon.hrl"). 14 | 15 | start_link() -> 16 | register(?MODULE, Pid=spawn_link(?MODULE, init, [])), 17 | {ok, Pid}. 18 | 19 | init() -> 20 | debug:log("erlmon_smtp: initializing"), 21 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=smtp, obj=self(), prev_state=down, new_state=disabled, ts=timestamp:now_i()}), 22 | loop({disabled, nil}). 23 | 24 | loop({OldStatus, OldConfig}=State) -> 25 | receive 26 | {Sender, get_config} -> 27 | Sender ! {ok, OldConfig}, 28 | loop({OldStatus, OldConfig}); 29 | {alert, SC, To} -> 30 | debug:log("erlmon_smtp: state_change alert: ~p", [SC]), 31 | Msg = create_msg(OldConfig, SC, To), 32 | send_msg(OldConfig, Msg, To), 33 | storage:alert_sent(#sent_alert{node=node(), to=To, objtype=SC#state_change.objtype, obj=SC#state_change.obj, prev_state=SC#state_change.prev_state, new_state=SC#state_change.new_state, ets=SC#state_change.ts, ats=timestamp:now_i()}), 34 | loop(State); 35 | {Sender, status} -> 36 | {Status, _Config} = State, 37 | Sender ! {status, Status}, 38 | loop(State); 39 | {Sender, config, #smtp_config{}=C} -> 40 | debug:log("erlmon_smtp:config: ~p", [C]), 41 | {NewStatus, NewConfig} = set_config(State, C), 42 | Sender ! {ok, NewStatus}, 43 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=smtp, obj=self(), prev_state=OldStatus, new_state=NewStatus, ts=timestamp:now_i()}), 44 | loop({NewStatus, NewConfig}); 45 | {'DOWN', _Ref, _Type, _Pid, _Reason} -> 46 | debug:log("erlmon_smtp: lost primary gateway"), 47 | {ok, NewStatus} = find_primary_smtp(), 48 | loop({NewStatus, OldConfig}); 49 | M -> 50 | debug:log("erlmon_smtp:UNKNOWN: ~p", [M]), 51 | loop(State) 52 | end. 53 | 54 | create_msg(Config, SC, To) -> 55 | erlmon_smtp_message:create(Config, SC, To). 56 | 57 | send_msg(Config, Msg, To) -> 58 | debug:log("erlmon_smtp: sending message: ~p", [Msg]), 59 | {ok, Pid} = smtp_fsm:start(Config#smtp_config.host), 60 | smtp_fsm:ehlo(Pid), 61 | if length(Config#smtp_config.login) > 0 -> 62 | smtp_fsm:login_login(Pid, Config#smtp_config.login, Config#smtp_config.pass); 63 | true -> ok 64 | end, 65 | smtp_fsm:sendemail(Pid, Config#smtp_config.address, To, Msg), 66 | smtp_fsm:close(Pid). 67 | 68 | get_config() -> 69 | erlmon_smtp ! {self(), get_config}, 70 | receive 71 | {ok, Config} -> Config 72 | end. 73 | 74 | config() -> 75 | Host = config:setting([smtp,host]), 76 | Address = config:setting([smtp,address]), 77 | Port = config:setting([smtp,port]), 78 | Authtype = config:setting([smtp,auth,type]), 79 | Login = config:setting([smtp,auth,login]), 80 | Password = config:setting([smtp,auth,password]), 81 | SC = #smtp_config{host=Host,port=Port,authtype=Authtype,address=Address,login=Login,pass=Password}, 82 | config(SC). 83 | 84 | config(Config) -> 85 | erlmon_smtp ! {self(), config, Config}, 86 | receive 87 | {ok, Reply} -> ok 88 | end, 89 | Reply. 90 | 91 | set_config(State, Config) -> 92 | case State of 93 | {_Status, Config} -> 94 | debug:log("erlmon_smtp: config already set"), 95 | State; 96 | _ -> 97 | debug:log("erlmon_smtp: setting config: ~p", [Config]), 98 | {ok, NewStatus} = find_primary_smtp(), 99 | {NewStatus, Config} 100 | end. 101 | 102 | status() -> 103 | erlmon_smtp ! {self(), status}, 104 | receive 105 | {status, Reply} -> ok 106 | end, 107 | Reply. 108 | 109 | find_primary_smtp() -> 110 | case global:whereis_name(erlmon_smtp) of 111 | undefined -> 112 | debug:log("erlmon_smtp: no primary smtp gateway. becoming primary."), 113 | case global:register_name(erlmon_smtp, whereis(erlmon_smtp)) of 114 | yes -> 115 | debug:log("erlmon_smtp: primary smtp gateway"), 116 | {ok, primary}; 117 | no -> 118 | debug:log("erlmon_smtp: failed to become primary gateway"), 119 | erlang:monitor(process, global:whereis_name(erlmon_smtp)), 120 | {ok, enabled} 121 | end; 122 | Pid -> 123 | debug:log("erlmon_smtp: primary smtp gateway found: ~p", [Pid]), 124 | debug:log("erlmon_smtp: becoming secondary"), 125 | erlang:monitor(process, Pid), 126 | {ok, secondary} 127 | end. 128 | 129 | alert(#state_change{}=SC, To) -> 130 | debug:log("erlmon_smtp: raising alert"), 131 | case global:whereis_name(erlmon_smtp) of 132 | undefined -> 133 | {error, no_primary_smtp}; 134 | Pid -> 135 | Pid ! {alert, SC, To}, 136 | ok 137 | end. 138 | -------------------------------------------------------------------------------- /erlmon-1.0/c_src/erlua.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "erlua.h" 9 | #include "commands.h" 10 | 11 | static ErlDrvData start (ErlDrvPort port, char* cmd); 12 | static void stop (ErlDrvData handle); 13 | static void process (ErlDrvData handle, ErlIOVec *ev); 14 | 15 | static ErlDrvEntry lua_driver_entry = { 16 | NULL, /* init */ 17 | start, /* startup */ 18 | stop, /* shutdown */ 19 | NULL, /* output */ 20 | NULL, /* ready_input */ 21 | NULL, /* ready_output */ 22 | "liberlua", /* the name of the driver */ 23 | NULL, /* finish */ 24 | NULL, /* handle */ 25 | NULL, /* control */ 26 | NULL, /* timeout */ 27 | process, /* process */ 28 | NULL, /* ready_async */ 29 | NULL, /* flush */ 30 | NULL, /* call */ 31 | NULL, /* event */ 32 | ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */ 33 | ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */ 34 | ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */ 35 | ERL_DRV_FLAG_USE_PORT_LOCKING /* ERL_DRV_FLAGs */ 36 | }; 37 | 38 | DRIVER_INIT(lua_driver) { 39 | return &lua_driver_entry; 40 | } 41 | 42 | static ErlDrvData 43 | start(ErlDrvPort port, char *cmd) 44 | { 45 | lua_State *L; 46 | L = luaL_newstate(); 47 | luaL_openlibs(L); 48 | 49 | lua_drv_t* retval = (lua_drv_t*) driver_alloc(sizeof(lua_drv_t)); 50 | retval->port = port; 51 | retval->L = L; 52 | 53 | return (ErlDrvData) retval; 54 | } 55 | 56 | static void 57 | stop(ErlDrvData handle) 58 | { 59 | lua_drv_t* driver_data = (lua_drv_t*) handle; 60 | lua_close(driver_data->L); 61 | driver_free(driver_data); 62 | } 63 | 64 | static void 65 | process(ErlDrvData handle, ErlIOVec *ev) 66 | { 67 | lua_drv_t *driver_data = (lua_drv_t*) handle; 68 | char *buf = ev->binv[1]->orig_bytes; 69 | int index = 0; 70 | int arty, version; 71 | long command; 72 | 73 | ei_decode_version(buf, &index, &version); 74 | ei_decode_tuple_header(buf, &index, &arty); 75 | ei_decode_long(buf, &index, &command); 76 | 77 | // printf("Command: %ld\n", command); 78 | // printf("sizeof: int: %ld, long: %ld, long long: %ld\n", sizeof(int), sizeof(long), sizeof(long long)); 79 | 80 | switch(command) { 81 | case ERL_LUA_CALL: 82 | erl_lua_call(driver_data, buf, index); 83 | break; 84 | case ERL_LUA_CONCAT: 85 | erl_lua_concat(driver_data, buf, index); 86 | break; 87 | case ERL_LUA_GETFIELD: 88 | erl_lua_getfield(driver_data, buf, index); 89 | break; 90 | case ERL_LUA_GETGLOBAL: 91 | erl_lua_getglobal(driver_data, buf, index); 92 | break; 93 | case ERL_LUA_GETTOP: 94 | erl_lua_gettop(driver_data, buf, index); 95 | break; 96 | case ERL_LUA_NEXT: 97 | erl_lua_next(driver_data, buf, index); 98 | break; 99 | 100 | case ERL_LUA_PUSHBOOLEAN: 101 | erl_lua_pushboolean(driver_data, buf, index); 102 | break; 103 | case ERL_LUA_PUSHINTEGER: 104 | erl_lua_pushinteger(driver_data, buf, index); 105 | break; 106 | case ERL_LUA_PUSHSTRING: 107 | erl_lua_pushstring(driver_data, buf, index); 108 | break; 109 | case ERL_LUA_PUSHNIL: 110 | erl_lua_pushnil(driver_data, buf, index); 111 | break; 112 | case ERL_LUA_PUSHNUMBER: 113 | erl_lua_pushnumber(driver_data, buf, index); 114 | break; 115 | case ERL_LUA_REMOVE: 116 | erl_lua_remove(driver_data, buf, index); 117 | break; 118 | case ERL_LUA_SETFIELD: 119 | erl_lua_setfield(driver_data, buf, index); 120 | break; 121 | case ERL_LUA_SETGLOBAL: 122 | erl_lua_setglobal(driver_data, buf, index); 123 | break; 124 | case ERL_LUA_TOBOOLEAN: 125 | erl_lua_toboolean(driver_data, buf, index); 126 | break; 127 | case ERL_LUA_TOINTEGER: 128 | erl_lua_tointeger(driver_data, buf, index); 129 | break; 130 | case ERL_LUA_TOLSTRING: 131 | erl_lua_tolstring(driver_data, buf, index); 132 | break; 133 | case ERL_LUA_TONUMBER: 134 | erl_lua_tonumber(driver_data, buf, index); 135 | break; 136 | case ERL_LUA_TYPE: 137 | erl_lua_type(driver_data, buf, index); 138 | break; 139 | 140 | case ERL_LUAL_DOSTRING: 141 | erl_lual_dostring(driver_data, buf, index); 142 | break; 143 | 144 | case ERL_LUAL_DOFILE: 145 | erl_lual_dofile(driver_data, buf, index); 146 | break; 147 | 148 | default: 149 | erl_lua_no_command(driver_data); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /erlmon-1.0/src/node.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(node). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/0]). 6 | -export([init/0]). 7 | -export([monitor_node/1]). 8 | -export([status/0]). 9 | 10 | -include("include/erlmon.hrl"). 11 | 12 | start() -> 13 | register(?MODULE, Pid=spawn_link(?MODULE, init, [])), 14 | {ok, Pid}. 15 | 16 | init() -> 17 | debug:log("node: initializing"), 18 | State = net_adm:world(), 19 | debug:log("node: initial state: ~p", [State]), 20 | NewState = start_monitoring_nodes(State), 21 | debug:log("node: final state: ~p", [NewState]), 22 | announce(NewState, NewState), 23 | erlmon:finished(?MODULE), 24 | loop(NewState). 25 | 26 | loop(State) -> 27 | receive 28 | {Sender, _Status} -> 29 | debug:log("node: received status request"), 30 | Sender ! {ok, State}, 31 | loop(State); 32 | {node_status, Node, Status} -> 33 | debug:log("node: received node_status: ~p:~p", [Node, Status]), 34 | NewState = set_node_status(Node, Status, State), 35 | loop(NewState); 36 | _Msg = #node_ack_announce{sender=_Sender, pid=Pid, node=Node, state=TheirState} -> 37 | debug:log("node: received ack_announce for ~p on ~p~n~p", [Pid, Node, TheirState]), 38 | case node_monitored(Node, State) of 39 | true -> 40 | NewState = State; 41 | false -> 42 | start_monitoring_node(Node), 43 | NewState = set_node_status(Node, up, State) 44 | end, 45 | loop(NewState); 46 | _Msg = #node_announce{sender=_Sender, pid=Pid, node=Node, state=TheirState} -> 47 | debug:log("node: received announce for ~p on ~p~n~p", [Pid, Node, TheirState]), 48 | case node_monitored(Node, State) of 49 | true -> 50 | NewState = State; 51 | false -> 52 | start_monitoring_node(Node), 53 | NewState = set_node_status(Node, up, State), 54 | Pid ! #node_ack_announce{sender=self(), pid=self(), node=node(), state=State} 55 | end, 56 | loop(NewState); 57 | M -> 58 | debug:log("node:UNKNOWN: ~p", [M]), 59 | loop(State) 60 | end. 61 | 62 | start_monitoring_nodes([Node|T]) -> 63 | [start_monitoring_node(Node)|start_monitoring_nodes(T)]; 64 | start_monitoring_nodes([]) -> []. 65 | 66 | start_monitoring_node(Node) -> 67 | case Node == node() of 68 | false -> 69 | %erlang:monitor_node(Node, true), 70 | %debug:log("monitoring node: ~p", [Node]), 71 | spawn(node, monitor_node, [Node]), 72 | {Node, up}; 73 | true -> 74 | {Node, up} 75 | end. 76 | 77 | announce([{Node, up}|T], State) -> 78 | debug:log("node: announce(~p)", [Node]), 79 | case Node == node() of 80 | false -> 81 | Pid = find_node_pid(Node), 82 | case Pid of 83 | undefined -> 84 | debug:log("can not announce to node ~p: undefined Pid", [Node]); 85 | _ -> 86 | debug:log("node: announcing to ~p on ~p", [Pid, Node]), 87 | Pid ! #node_announce{sender=self(), pid=self(), node=node(), state=State} 88 | end, 89 | announce(T, State); 90 | true -> 91 | debug:log("node: not announcing to self"), 92 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=?MODULE, obj=node(), prev_state=down, new_state=up, ts=timestamp:now_i()}), 93 | announce(T, State) 94 | end; 95 | announce([], _State) -> 96 | []. 97 | 98 | find_node_pid(Node) when is_atom(Node) -> 99 | rpc:call(Node, erlang, whereis, [node]). 100 | 101 | monitor_node(Node) -> 102 | debug:log("node: monitoring ~p (~p)", [Node, self()]), 103 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=?MODULE, obj=Node, prev_state=down, new_state=up, ts=timestamp:now_i()}), 104 | erlang:monitor_node(Node, true), 105 | receive 106 | {nodedown, Node} -> 107 | debug:log("node: received nodedown for ~p (~p)", [Node, self()]), 108 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=?MODULE, obj=Node, prev_state=up, new_state=down, ts=timestamp:now_i()}), 109 | node ! {node_status, Node, down}; 110 | M -> 111 | debug:log("node:UNKNOWN: ~p (~p)", [M, self()]) 112 | end. 113 | 114 | %add_node_to_state(Node, [Node|_T]=State) -> 115 | % State; 116 | %add_node_to_state(Node, [H|T]) -> 117 | % [H|add_node_to_state(Node, T)]; 118 | %add_node_to_state(Node, []) -> 119 | % [Node]. 120 | % 121 | %remove_node_from_state(Node, [Node|T]) -> 122 | % T; 123 | %remove_node_from_state(Node, [H|T]) -> 124 | % [H|remove_node_from_state(Node, T)]; 125 | %remove_node_from_state(Node, []) -> 126 | % []. 127 | 128 | node_monitored(Node, [{Node, up}|_T]) -> 129 | debug:log("node: node (~p) already monitored!", [Node]), 130 | true; 131 | node_monitored(Node, [_H|T]) -> 132 | node_monitored(Node, T); 133 | node_monitored(Node, []) -> 134 | debug:log("node: node (~p) not monitored yet", [Node]), 135 | false. 136 | 137 | set_node_status(Node, Status, [{Node, _}|T]) -> 138 | [{Node, Status}|T]; 139 | set_node_status(Node, Status, [H|T]) -> 140 | [H|set_node_status(Node, Status, T)]; 141 | set_node_status(Node, Status, []) -> 142 | [{Node, Status}]. 143 | 144 | status() -> 145 | node ! {self(), status}, 146 | receive 147 | {ok, Status} -> ok 148 | end, 149 | Status. 150 | -------------------------------------------------------------------------------- /erlmon-1.0/c_src/commands.h: -------------------------------------------------------------------------------- 1 | /* General Lua API */ 2 | 3 | #define ERL_LUA_ALLOC 1 4 | #define ERL_LUA_ATPANIC 2 5 | #define ERL_LUA_CALL 3 6 | #define ERL_LUA_CFUNCTION 4 7 | #define ERL_LUA_CHECKSTACK 5 8 | #define ERL_LUA_CLOSE 6 9 | #define ERL_LUA_CONCAT 7 10 | #define ERL_LUA_CPCALL 8 11 | #define ERL_LUA_CREATETABLE 9 12 | #define ERL_LUA_DUMP 10 13 | #define ERL_LUA_EQUAL 11 14 | #define ERL_LUA_ERROR 12 15 | #define ERL_LUA_GC 13 16 | #define ERL_LUA_GETALLOCF 14 17 | #define ERL_LUA_GETFENV 15 18 | #define ERL_LUA_GETFIELD 16 19 | #define ERL_LUA_GETGLOBAL 17 20 | #define ERL_LUA_GETMETATABLE 18 21 | #define ERL_LUA_GETTABLE 19 22 | #define ERL_LUA_GETTOP 20 23 | #define ERL_LUA_INSERT 21 24 | #define ERL_LUA_ISBOOLEAN 22 25 | #define ERL_LUA_ISCFUNCTION 23 26 | #define ERL_LUA_ISFUNCTION 24 27 | #define ERL_LUA_ISLIGHTUSERDATA 25 28 | #define ERL_LUA_ISNIL 26 29 | #define ERL_LUA_ISNONE 27 30 | #define ERL_LUA_ISNONEORNIL 28 31 | #define ERL_LUA_ISNUMBER 29 32 | #define ERL_LUA_ISSTRING 30 33 | #define ERL_LUA_ISTABLE 31 34 | #define ERL_LUA_ISTHREAD 32 35 | #define ERL_LUA_ISUSERDATA 33 36 | #define ERL_LUA_LESSTHAN 34 37 | #define ERL_LUA_LOAD 35 38 | #define ERL_LUA_NEWSTATE 36 39 | #define ERL_LUA_NEWTABLE 37 40 | #define ERL_LUA_NEWTHREAD 38 41 | #define ERL_LUA_NEWUSERDATA 39 42 | #define ERL_LUA_NEXT 40 43 | #define ERL_LUA_OBJLEN 41 44 | #define ERL_LUA_PCALL 42 45 | #define ERL_LUA_POP 43 46 | #define ERL_LUA_PUSHBOOLEAN 44 47 | #define ERL_LUA_PUSHCCLOSURE 45 48 | #define ERL_LUA_PUSHCFUNCTION 46 49 | #define ERL_LUA_PUSHFSTRING 47 50 | #define ERL_LUA_PUSHINTEGER 48 51 | #define ERL_LUA_PUSHLIGHTUSERDATA 49 52 | #define ERL_LUA_PUSHLITERAL 50 53 | #define ERL_LUA_PUSHLSTRING 51 54 | #define ERL_LUA_PUSHNIL 52 55 | #define ERL_LUA_PUSHNUMBER 53 56 | #define ERL_LUA_PUSHSTRING 54 57 | #define ERL_LUA_PUSHTHREAD 55 58 | #define ERL_LUA_PUSHVALUE 56 59 | #define ERL_LUA_PUSHVFSTRING 57 60 | #define ERL_LUA_RAWEQUAL 58 61 | #define ERL_LUA_RAWGET 59 62 | #define ERL_LUA_RAWGETI 60 63 | #define ERL_LUA_RAWSET 61 64 | #define ERL_LUA_RAWSETI 62 65 | #define ERL_LUA_REGISTER 63 66 | #define ERL_LUA_REMOVE 64 67 | #define ERL_LUA_REPLACE 65 68 | #define ERL_LUA_RESUME 66 69 | #define ERL_LUA_SETALLOCF 67 70 | #define ERL_LUA_SETFENV 68 71 | #define ERL_LUA_SETFIELD 69 72 | #define ERL_LUA_SETGLOBAL 70 73 | #define ERL_LUA_SETMETATABLE 71 74 | #define ERL_LUA_SETTABLE 72 75 | #define ERL_LUA_SETTOP 73 76 | #define ERL_LUA_STATUS 74 77 | #define ERL_LUA_TOBOOLEAN 75 78 | #define ERL_LUA_TOCFUNCTION 76 79 | #define ERL_LUA_TOINTEGER 77 80 | #define ERL_LUA_TOLSTRING 78 81 | #define ERL_LUA_TONUMBER 79 82 | #define ERL_LUA_TOPOINTER 80 83 | #define ERL_LUA_TOSTRING 81 84 | #define ERL_LUA_TOTHREAD 82 85 | #define ERL_LUA_TOUSERDATA 83 86 | #define ERL_LUA_TYPE 84 87 | #define ERL_LUA_TYPENAME 85 88 | #define ERL_LUA_XMOVE 86 89 | #define ERL_LUA_YIELD 87 90 | 91 | 92 | /* Lua Auxiliary Library */ 93 | 94 | #define ERL_LUAL_ADDCHAR 88 95 | #define ERL_LUAL_ADDLSTRING 89 96 | #define ERL_LUAL_ADDSIZE 90 97 | #define ERL_LUAL_ADDSTRING 91 98 | #define ERL_LUAL_ADDVALUE 92 99 | #define ERL_LUAL_ARGCHECK 93 100 | #define ERL_LUAL_ARGERROR 94 101 | #define ERL_LUAL_BUFFINIT 95 102 | #define ERL_LUAL_CALLMETA 96 103 | #define ERL_LUAL_CHECKANY 97 104 | #define ERL_LUAL_CHECKINT 98 105 | #define ERL_LUAL_CHECKINTEGER 99 106 | #define ERL_LUAL_CHECKLONG 100 107 | #define ERL_LUAL_CHECKLSTRING 101 108 | #define ERL_LUAL_CHECKNUMBER 102 109 | #define ERL_LUAL_CHECKOPTION 103 110 | #define ERL_LUAL_CHECKSTACK 104 111 | #define ERL_LUAL_CHECKSTRING 105 112 | #define ERL_LUAL_CHECKTYPE 106 113 | #define ERL_LUAL_CHECKUDATA 107 114 | #define ERL_LUAL_DOFILE 108 115 | #define ERL_LUAL_DOSTRING 109 116 | #define ERL_LUAL_ERROR 110 117 | #define ERL_LUAL_GETMETAFIELD 111 118 | #define ERL_LUAL_GETMETATABLE 112 119 | #define ERL_LUAL_GSUB 113 120 | #define ERL_LUAL_LOADBUFFER 114 121 | #define ERL_LUAL_LOADFILE 115 122 | #define ERL_LUAL_LOADSTRING 116 123 | #define ERL_LUAL_NEWMETATABLE 117 124 | #define ERL_LUAL_NEWSTATE 118 125 | #define ERL_LUAL_OPENLIBS 119 126 | #define ERL_LUAL_OPTINT 120 127 | #define ERL_LUAL_OPTINTEGER 121 128 | #define ERL_LUAL_OPTLONG 122 129 | #define ERL_LUAL_OPTLSTRING 123 130 | #define ERL_LUAL_OPTNUMBER 124 131 | #define ERL_LUAL_OPTSTRING 125 132 | #define ERL_LUAL_PREPBUFFER 126 133 | #define ERL_LUAL_PUSHRESULT 127 134 | #define ERL_LUAL_REF 128 135 | #define ERL_LUAL_REGISTER 129 136 | #define ERL_LUAL_TYPENAME 130 137 | #define ERL_LUAL_TYPERROR 131 138 | #define ERL_LUAL_UNREF 132 139 | #define ERL_LUAL_WHERE 133 140 | 141 | #define ATOM_OK driver_mk_atom("ok") 142 | #define ATOM_ERROR driver_mk_atom("error") 143 | -------------------------------------------------------------------------------- /erlmon-1.0/src/file_monitor.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(file_monitor). 3 | -author(darrik@darmasoft.com). 4 | 5 | -export([start/1]). 6 | -export([init/1]). 7 | -export([monitor/1]). 8 | 9 | -include_lib("kernel/include/file.hrl"). 10 | -include("include/erlmon.hrl"). 11 | 12 | monitor(Path) -> 13 | file_monitor_man:monitor(Path). 14 | 15 | start(FileName) -> 16 | {ok, spawn_link(?MODULE, init, [FileName])}. 17 | 18 | init(FileName) -> 19 | case file:read_file_info(FileName) of 20 | {ok, FileInfo} -> 21 | debug:log("fileinfo: ~p", [FileInfo]), 22 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unmonitored, new_state=unchanged, ts=timestamp:now_i()}), 23 | loop(FileName, FileInfo); 24 | {error, Reason} -> 25 | debug:log("error: ~p", [Reason]) 26 | end. 27 | 28 | loop(FileName, State) -> 29 | receive 30 | M -> 31 | debug:log("file_monitor: ~p: UNKNOWN: ~p", [self(), M]) 32 | after 33 | 3000 -> 34 | case file:read_file_info(FileName) of 35 | {ok, State} -> 36 | NewState = State, 37 | loop(FileName, NewState); 38 | State -> 39 | NewState = State, 40 | loop(FileName, NewState); 41 | {ok, FileInfo} -> 42 | diff(FileName, State, FileInfo), 43 | NewState = FileInfo, 44 | loop(FileName, NewState); 45 | {error, Reason} -> 46 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=nonexistent, ts=timestamp:now_i()}), 47 | NewState = {error, Reason}, 48 | loop(FileName, NewState) 49 | end 50 | end. 51 | 52 | diff(FileName, {error, _Reason}, _NewFileInfo) -> 53 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=nonexistent, new_state=unchanged, ts=timestamp:now_i()}), 54 | ok; 55 | diff(FileName, OldFileInfo, NewFileInfo) -> 56 | case {OldFileInfo#file_info.size, NewFileInfo#file_info.size} of 57 | {_SA, _SA} -> 58 | same; 59 | {SA, SB} -> 60 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_size_changed, data={SA, SB}, ts=timestamp:now_i()}) 61 | end, 62 | case {OldFileInfo#file_info.type, NewFileInfo#file_info.type} of 63 | {_TA, _TA} -> 64 | same; 65 | {TA, TB} -> 66 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_type_changed, data={TA, TB}, ts=timestamp:now_i()}) 67 | end, 68 | case {OldFileInfo#file_info.access, NewFileInfo#file_info.access} of 69 | {_AA, _AA} -> 70 | same; 71 | {AA, AB} -> 72 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_access_changed, data={AA, AB}, ts=timestamp:now_i()}) 73 | end, 74 | case {OldFileInfo#file_info.atime, NewFileInfo#file_info.atime} of 75 | {_ATA, _ATA} -> 76 | same; 77 | {ATA, ATB} -> 78 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_atime_changed, data={ATA, ATB}, ts=timestamp:now_i()}) 79 | end, 80 | case {OldFileInfo#file_info.mtime, NewFileInfo#file_info.mtime} of 81 | {_MTA, _MTA} -> 82 | same; 83 | {MTA, MTB} -> 84 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_mtime_changed, data={MTA, MTB}, ts=timestamp:now_i()}) 85 | end, 86 | case {OldFileInfo#file_info.ctime, NewFileInfo#file_info.ctime} of 87 | {_CTA, _CTA} -> 88 | same; 89 | {CTA, CTB} -> 90 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_ctime_changed, data={CTA, CTB}, ts=timestamp:now_i()}) 91 | end, 92 | case {OldFileInfo#file_info.mode, NewFileInfo#file_info.mode} of 93 | {_MA, _MA} -> 94 | same; 95 | {MA, MB} -> 96 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_mode_changed, data={MA, MB}, ts=timestamp:now_i()}) 97 | end, 98 | case {OldFileInfo#file_info.links, NewFileInfo#file_info.links} of 99 | {_LA, _LA} -> 100 | same; 101 | {LA, LB} -> 102 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_links_changed, data={LA, LB}, ts=timestamp:now_i()}) 103 | end, 104 | case {OldFileInfo#file_info.major_device, NewFileInfo#file_info.major_device} of 105 | {_MDA, _MDA} -> 106 | same; 107 | {MDA, MDB} -> 108 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_major_device_changed, data={MDA, MDB}, ts=timestamp:now_i()}) 109 | end, 110 | case {OldFileInfo#file_info.minor_device, NewFileInfo#file_info.minor_device} of 111 | {_MIDA, _MIDA} -> 112 | same; 113 | {MIDA, MIDB} -> 114 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_minor_device_changed, data={MIDA, MIDB}, ts=timestamp:now_i()}) 115 | end, 116 | case {OldFileInfo#file_info.inode, NewFileInfo#file_info.inode} of 117 | {_IA, _IA} -> 118 | same; 119 | {IA, IB} -> 120 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_inode_changed, data={IA, IB}, ts=timestamp:now_i()}) 121 | end, 122 | case {OldFileInfo#file_info.uid, NewFileInfo#file_info.uid} of 123 | {_UIDA, _UIDA} -> 124 | same; 125 | {UIDA, UIDB} -> 126 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_uid_changed, data={UIDA, UIDB}, ts=timestamp:now_i()}) 127 | end, 128 | case {OldFileInfo#file_info.gid, NewFileInfo#file_info.gid} of 129 | {_GIDA, _GIDA} -> 130 | same; 131 | {GIDA, GIDB} -> 132 | state_change_em:notify(#state_change{sender=self(), node=node(), objtype=file, obj=FileName, prev_state=unchanged, new_state=file_gid_changed, data={GIDA, GIDB}, ts=timestamp:now_i()}) 133 | end. 134 | -------------------------------------------------------------------------------- /erlmon-1.0/include/lua_api.hrl: -------------------------------------------------------------------------------- 1 | % Lua Type Defs 2 | 3 | -define(LUA_TNIL, 0 ). 4 | -define(LUA_TBOOLEAN, 1 ). 5 | -define(LUA_TLIGHTUSERDATA, 2 ). 6 | -define(LUA_TNUMBER, 3 ). 7 | -define(LUA_TSTRING, 4 ). 8 | -define(LUA_TTABLE, 5 ). 9 | -define(LUA_TFUNCTION, 6 ). 10 | -define(LUA_TUSERDATA, 7 ). 11 | -define(LUA_TTHREAD, 8 ). 12 | 13 | % General Lua API 14 | 15 | -define(ERL_LUA_ALLOC, 1 ). 16 | -define(ERL_LUA_ATPANIC, 2 ). 17 | -define(ERL_LUA_CALL, 3 ). 18 | -define(ERL_LUA_CFUNCTION, 4 ). 19 | -define(ERL_LUA_CHECKSTACK, 5 ). 20 | -define(ERL_LUA_CLOSE, 6 ). 21 | -define(ERL_LUA_CONCAT, 7 ). 22 | -define(ERL_LUA_CPCALL, 8 ). 23 | -define(ERL_LUA_CREATETABLE, 9 ). 24 | -define(ERL_LUA_DUMP, 10). 25 | -define(ERL_LUA_EQUAL, 11). 26 | -define(ERL_LUA_ERROR, 12). 27 | -define(ERL_LUA_GC, 13). 28 | -define(ERL_LUA_GETALLOCF, 14). 29 | -define(ERL_LUA_GETFENV, 15). 30 | -define(ERL_LUA_GETFIELD, 16). 31 | -define(ERL_LUA_GETGLOBAL, 17). 32 | -define(ERL_LUA_GETMETATABLE, 18). 33 | -define(ERL_LUA_GETTABLE, 19). 34 | -define(ERL_LUA_GETTOP, 20). 35 | -define(ERL_LUA_INSERT, 21). 36 | -define(ERL_LUA_ISBOOLEAN, 22). 37 | -define(ERL_LUA_ISCFUNCTION, 23). 38 | -define(ERL_LUA_ISFUNCTION, 24). 39 | -define(ERL_LUA_ISLIGHTUSERDATA, 25). 40 | -define(ERL_LUA_ISNIL, 26). 41 | -define(ERL_LUA_ISNONE, 27). 42 | -define(ERL_LUA_ISNONEORNIL, 28). 43 | -define(ERL_LUA_ISNUMBER, 29). 44 | -define(ERL_LUA_ISSTRING, 30). 45 | -define(ERL_LUA_ISTABLE, 31). 46 | -define(ERL_LUA_ISTHREAD, 32). 47 | -define(ERL_LUA_ISUSERDATA, 33). 48 | -define(ERL_LUA_LESSTHAN, 34). 49 | -define(ERL_LUA_LOAD, 35). 50 | -define(ERL_LUA_NEWSTATE, 36). 51 | -define(ERL_LUA_NEWTABLE, 37). 52 | -define(ERL_LUA_NEWTHREAD, 38). 53 | -define(ERL_LUA_NEWUSERDATA, 39). 54 | -define(ERL_LUA_NEXT, 40). 55 | -define(ERL_LUA_OBJLEN, 41). 56 | -define(ERL_LUA_PCALL, 42). 57 | -define(ERL_LUA_POP, 43). 58 | -define(ERL_LUA_PUSHBOOLEAN, 44). 59 | -define(ERL_LUA_PUSHCCLOSURE, 45). 60 | -define(ERL_LUA_PUSHCFUNCTION, 46). 61 | -define(ERL_LUA_PUSHFSTRING, 47). 62 | -define(ERL_LUA_PUSHINTEGER, 48). 63 | -define(ERL_LUA_PUSHLIGHTUSERDATA, 49). 64 | -define(ERL_LUA_PUSHLITERAL, 50). 65 | -define(ERL_LUA_PUSHLSTRING, 51). 66 | -define(ERL_LUA_PUSHNIL, 52). 67 | -define(ERL_LUA_PUSHNUMBER, 53). 68 | -define(ERL_LUA_PUSHSTRING, 54). 69 | -define(ERL_LUA_PUSHTHREAD, 55). 70 | -define(ERL_LUA_PUSHVALUE, 56). 71 | -define(ERL_LUA_PUSHVFSTRING, 57). 72 | -define(ERL_LUA_RAWEQUAL, 58). 73 | -define(ERL_LUA_RAWGET, 59). 74 | -define(ERL_LUA_RAWGETI, 60). 75 | -define(ERL_LUA_RAWSET, 61). 76 | -define(ERL_LUA_RAWSETI, 62). 77 | -define(ERL_LUA_REGISTER, 63). 78 | -define(ERL_LUA_REMOVE, 64). 79 | -define(ERL_LUA_REPLACE, 65). 80 | -define(ERL_LUA_RESUME, 66). 81 | -define(ERL_LUA_SETALLOCF, 67). 82 | -define(ERL_LUA_SETFENV, 68). 83 | -define(ERL_LUA_SETFIELD, 69). 84 | -define(ERL_LUA_SETGLOBAL, 70). 85 | -define(ERL_LUA_SETMETATABLE, 71). 86 | -define(ERL_LUA_SETTABLE, 72). 87 | -define(ERL_LUA_SETTOP, 73). 88 | -define(ERL_LUA_STATUS, 74). 89 | -define(ERL_LUA_TOBOOLEAN, 75). 90 | -define(ERL_LUA_TOCFUNCTION, 76). 91 | -define(ERL_LUA_TOINTEGER, 77). 92 | -define(ERL_LUA_TOLSTRING, 78). 93 | -define(ERL_LUA_TONUMBER, 79). 94 | -define(ERL_LUA_TOPOINTER, 80). 95 | -define(ERL_LUA_TOSTRING, 81). 96 | -define(ERL_LUA_TOTHREAD, 82). 97 | -define(ERL_LUA_TOUSERDATA, 83). 98 | -define(ERL_LUA_TYPE, 84). 99 | -define(ERL_LUA_TYPENAME, 85). 100 | -define(ERL_LUA_XMOVE, 86). 101 | -define(ERL_LUA_YIELD, 87). 102 | 103 | 104 | %% Lua Auxiliary Library 105 | 106 | -define(ERL_LUAL_ADDCHAR, 88 ). 107 | -define(ERL_LUAL_ADDLSTRING, 89 ). 108 | -define(ERL_LUAL_ADDSIZE, 90 ). 109 | -define(ERL_LUAL_ADDSTRING, 91 ). 110 | -define(ERL_LUAL_ADDVALUE, 92 ). 111 | -define(ERL_LUAL_ARGCHECK, 93 ). 112 | -define(ERL_LUAL_ARGERROR, 94 ). 113 | -define(ERL_LUAL_BUFFINIT, 95 ). 114 | -define(ERL_LUAL_CALLMETA, 96 ). 115 | -define(ERL_LUAL_CHECKANY, 97 ). 116 | -define(ERL_LUAL_CHECKINT, 98 ). 117 | -define(ERL_LUAL_CHECKINTEGER, 99 ). 118 | -define(ERL_LUAL_CHECKLONG, 100). 119 | -define(ERL_LUAL_CHECKLSTRING, 101). 120 | -define(ERL_LUAL_CHECKNUMBER, 102). 121 | -define(ERL_LUAL_CHECKOPTION, 103). 122 | -define(ERL_LUAL_CHECKSTACK, 104). 123 | -define(ERL_LUAL_CHECKSTRING, 105). 124 | -define(ERL_LUAL_CHECKTYPE, 106). 125 | -define(ERL_LUAL_CHECKUDATA, 107). 126 | -define(ERL_LUAL_DOFILE, 108). 127 | -define(ERL_LUAL_DOSTRING, 109). 128 | -define(ERL_LUAL_ERROR, 110). 129 | -define(ERL_LUAL_GETMETAFIELD, 111). 130 | -define(ERL_LUAL_GETMETATABLE, 112). 131 | -define(ERL_LUAL_GSUB, 113). 132 | -define(ERL_LUAL_LOADBUFFER, 114). 133 | -define(ERL_LUAL_LOADFILE, 115). 134 | -define(ERL_LUAL_LOADSTRING, 116). 135 | -define(ERL_LUAL_NEWMETATABLE, 117). 136 | -define(ERL_LUAL_NEWSTATE, 118). 137 | -define(ERL_LUAL_OPENLIBS, 119). 138 | -define(ERL_LUAL_OPTINT, 120). 139 | -define(ERL_LUAL_OPTINTEGER, 121). 140 | -define(ERL_LUAL_OPTLONG, 122). 141 | -define(ERL_LUAL_OPTLSTRING, 123). 142 | -define(ERL_LUAL_OPTNUMBER, 124). 143 | -define(ERL_LUAL_OPTSTRING, 125). 144 | -define(ERL_LUAL_PREPBUFFER, 126). 145 | -define(ERL_LUAL_PUSHRESULT, 127). 146 | -define(ERL_LUAL_REF, 128). 147 | -define(ERL_LUAL_REGISTER, 129). 148 | -define(ERL_LUAL_TYPENAME, 130). 149 | -define(ERL_LUAL_TYPERROR, 131). 150 | -define(ERL_LUAL_UNREF, 132). 151 | -define(ERL_LUAL_WHERE, 133). -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/web_app_theme.css: -------------------------------------------------------------------------------- 1 | * {margin:0;padding:0} 2 | .clear { clear: both; height: 0; } 3 | 4 | h1 { margin: 15px 0; font-size: 22px; font-weight: normal; } 5 | h2 { font-size: 22px; margin: 15px 0; font-weight: normal;} 6 | h3 { font-size: 18px; margin: 10px 0; font-weight: normal;} 7 | h4 { font-size: 14px; margin: 5px 0; font-weight: bold;} 8 | hr {height: 1px; border: 0; } 9 | p { margin: 15px 0;} 10 | a img { border: none; } 11 | 12 | body { 13 | font-size: 12px; 14 | font-family: sans-serif; 15 | } 16 | 17 | #container { 18 | min-width: 960px; 19 | } 20 | 21 | #header, #wrapper { 22 | padding: 0 20px; 23 | } 24 | 25 | #header { 26 | /*position: relative;*/ 27 | padding-top: 1px; 28 | } 29 | 30 | #header h1 { 31 | margin: 0; 32 | padding: 0; 33 | font-size: 30px; 34 | } 35 | 36 | #header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited { 37 | text-decoration: none; 38 | } 39 | 40 | #main { 41 | /*width: 70%;*/ 42 | /*float: left;*/ 43 | } 44 | 45 | .actions-bar { 46 | padding: 10px 1px; 47 | } 48 | 49 | .actions-bar .actions { 50 | float: left; 51 | } 52 | 53 | 54 | .actions-bar .pagination { 55 | float: right; 56 | padding: 1px 0; 57 | } 58 | 59 | #sidebar { 60 | width: 28%; 61 | float: right; 62 | } 63 | 64 | #sidebar h3 { 65 | padding: 10px 15px; 66 | margin: 0; 67 | font-size: 13px; 68 | } 69 | 70 | #sidebar .block { 71 | margin-bottom: 20px; 72 | padding-bottom: 10px; 73 | } 74 | 75 | #sidebar .block .content { 76 | padding: 0 15px; 77 | } 78 | 79 | #sidebar ul.navigation li a:link, #sidebar ul.navigation li a:visited { 80 | display: block; 81 | padding: 10px 15px; 82 | } 83 | 84 | #sidebar .block .sidebar-block, #sidebar .notice { 85 | padding:10px; 86 | } 87 | 88 | #wrapper { 89 | padding-top: 20px; 90 | } 91 | 92 | #main .block { 93 | margin-bottom: 20px; 94 | padding-top: 1px; 95 | } 96 | 97 | #main .block .content .inner { 98 | padding: 0 15px 15px; 99 | } 100 | 101 | #main .main p.first { 102 | margin-top: 0; 103 | } 104 | 105 | #user-navigation { 106 | position: absolute; 107 | top: 0px; 108 | right: 20px; 109 | } 110 | 111 | #main-navigation { 112 | width: 100%; 113 | } 114 | 115 | #user-navigation ul, #main-navigation ul, .secondary-navigation ul, #sidebar ul.navigation { 116 | margin: 0; 117 | padding: 0; 118 | list-style-type: none; 119 | } 120 | 121 | #user-navigation ul li, #main-navigation ul li, .secondary-navigation ul li { 122 | float: left; 123 | } 124 | 125 | #main-navigation ul li { 126 | margin-right: 5px; 127 | } 128 | 129 | #user-navigation ul li { 130 | padding: 5px 10px; 131 | } 132 | 133 | #main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active, 134 | .secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active, 135 | #user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active { 136 | text-decoration: none; 137 | } 138 | 139 | #main-navigation ul li a { 140 | font-size: 15px; 141 | display: block; 142 | padding: 8px 15px; 143 | } 144 | 145 | .secondary-navigation { 146 | font-size: 13px; 147 | border-bottom-width: 10px; 148 | border-bottom-style: solid; 149 | } 150 | 151 | .secondary-navigation ul li a { 152 | display: block; 153 | padding: 10px 15px; 154 | } 155 | 156 | #footer { 157 | padding-bottom: 20px; 158 | } 159 | 160 | /* pagination */ 161 | 162 | .pagination a, .pagination span { 163 | padding: 2px 5px; 164 | margin-right: 5px; 165 | display: block; 166 | float: left; 167 | border-style: solid; 168 | border-width: 1px; 169 | } 170 | 171 | .pagination span.current { 172 | font-weight: bold; 173 | } 174 | 175 | .pagination a { 176 | text-decoration: none; 177 | } 178 | 179 | /* tables */ 180 | .table { 181 | width: 100%; 182 | border-collapse: collapse; 183 | margin-bottom: 15px; 184 | } 185 | 186 | .table th { 187 | padding: 10px; 188 | font-weight: bold; 189 | text-align: left; 190 | } 191 | 192 | .table th.first { 193 | /*width: 30px;*/ 194 | } 195 | 196 | .table th.last { 197 | /*width: 200px;*/ 198 | } 199 | 200 | .table .checkbox { 201 | margin-left: 10px; 202 | } 203 | 204 | .table td { 205 | padding: 10px; 206 | } 207 | 208 | .table td.last { 209 | text-align: right; 210 | } 211 | 212 | /* forms */ 213 | 214 | input.checkbox { 215 | margin: 0; 216 | padding: 0; 217 | } 218 | 219 | .form .group { 220 | margin-bottom: 15px; 221 | } 222 | 223 | .form div.left { 224 | width: 20%; 225 | float: left; 226 | } 227 | 228 | .form div.right { 229 | width: 75%; 230 | float: right; 231 | } 232 | 233 | .form .columns .column { 234 | width: 48%; 235 | } 236 | 237 | .form .columns .left { 238 | float: left; 239 | } 240 | 241 | .form .columns .right { 242 | float: right; 243 | } 244 | 245 | .form label.label, .form input.text_field, .form textarea.text_area { 246 | font-size: 1.2em; 247 | padding: 1px 0; 248 | margin: 0; 249 | } 250 | 251 | textarea.textarea { 252 | width: 75%; 253 | height: 300px; 254 | } 255 | 256 | .form label.right { 257 | text-align: right; 258 | } 259 | 260 | .form input.checkbox, .form input.radio { 261 | margin-right: 5px; 262 | } 263 | 264 | .form label.checkbox, .form label.radio { 265 | line-height: 1.5em; 266 | } 267 | 268 | .form label.label { 269 | display: block; 270 | padding-bottom: 2px; 271 | font-weight: bold; 272 | } 273 | 274 | .form div.fieldWithErrors label.label { 275 | display: inline; 276 | } 277 | 278 | .form .fieldWithErrors .error { 279 | color: red; 280 | } 281 | 282 | .form input.text_field, .form textarea.text_area { 283 | width: 100%; 284 | border-width: 1px; 285 | border-style: solid; 286 | } 287 | 288 | /* lists */ 289 | 290 | ul.list { 291 | margin: 0; 292 | padding: 0; 293 | list-style-type: none; 294 | } 295 | 296 | ul.list li { 297 | clear: left; 298 | padding-bottom: 5px; 299 | } 300 | 301 | ul.list li .left { 302 | float: left; 303 | } 304 | 305 | ul.list li .left .avatar { 306 | width: 50px; 307 | height: 50px; 308 | } 309 | 310 | ul.list li .item { 311 | margin-left: 80px; 312 | } 313 | 314 | ul.list li .item .avatar { 315 | float: left; 316 | margin: 0 5px 5px 0; 317 | width: 30px; 318 | height: 30px; 319 | } 320 | 321 | /* box */ 322 | 323 | #box { 324 | width: 500px; 325 | margin: 0px auto; 326 | } 327 | 328 | #box .block { 329 | margin-bottom: 20px; 330 | } 331 | 332 | #box .block h2 { 333 | padding: 10px 15px; 334 | margin: 0; 335 | } 336 | 337 | #box .block .content { 338 | padding: 10px 20px; 339 | } 340 | 341 | .teaser { 342 | font-size: .8em; 343 | color: #aaa; 344 | } 345 | 346 | tr.even { 347 | background: #ddd; 348 | } 349 | 350 | tr.odd { 351 | background: #fff; 352 | } 353 | 354 | -------------------------------------------------------------------------------- /erlmon-1.0/src/lua.erl: -------------------------------------------------------------------------------- 1 | -module(lua). 2 | 3 | -export([new_state/0, 4 | close/1, 5 | call/3, 6 | concat/2, 7 | dostring/2, 8 | dofile/2, 9 | dump_table/2, 10 | getfield/3, 11 | getglobal/2, 12 | gettable/3, 13 | gettable/2, 14 | gettop/1, 15 | next/2, 16 | pop/1, 17 | push/2, 18 | pushboolean/2, 19 | pushinteger/2, 20 | pushstring/2, 21 | pushnil/1, 22 | pushnumber/2, 23 | remove/2, 24 | setfield/3, 25 | setglobal/2, 26 | toboolean/2, 27 | tointeger/2, 28 | tolstring/2, 29 | tonumber/2, 30 | type/2, 31 | type_atom/2 32 | ]). 33 | 34 | -include("lua.hrl"). 35 | -include("lua_api.hrl"). 36 | 37 | new_state() -> 38 | {ok, lua_driver:open()}. 39 | 40 | close(L) -> 41 | lua_driver:close(L). 42 | 43 | dostring(#lua{port=Port}, Code) -> 44 | port_command(Port, term_to_binary({?ERL_LUAL_DOSTRING, Code})), 45 | receive_simple_response(). 46 | 47 | dofile(#lua{port=Port}, Filename) -> 48 | port_command(Port, term_to_binary({?ERL_LUAL_DOFILE, Filename})), 49 | receive_simple_response(). 50 | 51 | call(L, Args, Results) -> 52 | command(L, {?ERL_LUA_CALL, Args, Results}), 53 | receive_simple_response(). 54 | 55 | concat(L, N) -> 56 | command(L, {?ERL_LUA_CONCAT, N}). 57 | 58 | dump_table(L, N) -> 59 | dump_table(L, N, none). 60 | 61 | dump_table(L, N, NextKey) -> 62 | io:format("dump_table(~p, ~p)~n", [N, NextKey]), 63 | case NextKey of 64 | none -> 65 | Str=lists:concat(["tmpkey, tmpval = pairs(", N, ")(", N, ")"]); 66 | NK -> 67 | Str=lists:concat(["tmpkey, tmpval = pairs(", N, ")(", N, ", \"", NK, "\")"]) 68 | end, 69 | io:format("Str == ~p~n", [Str]), 70 | lual:dostring(L, Str), 71 | lua:getglobal(L, "tmpkey"), 72 | {ok, T} = lua:type(L, -1), 73 | case T of 74 | ?LUA_TNIL -> []; 75 | _ -> 76 | {ok, K} = lua:tolstring(L, -1), 77 | lua:remove(L, -1), 78 | lua:getglobal(L, "tmpval"), 79 | {ok, VT} = lua:type(L, -1), 80 | io:format("type == ~p~n", [VT]), 81 | case VT of 82 | ?LUA_TNUMBER -> 83 | {ok, V} = lua:tonumber(L, -1); 84 | ?LUA_TTABLE -> 85 | V = dump_table(L, lists:concat([N, ".", K])); 86 | _ -> 87 | {ok, V} = lua:tolstring(L, -1) 88 | end, 89 | lua:remove(L, -1), 90 | [{list_to_atom(K),V}|dump_table(L, N, K)] 91 | end. 92 | 93 | getfield(L, global, Name) -> 94 | getglobal(L, Name); 95 | getfield(L, Index, Name) -> 96 | command(L, {?ERL_LUA_GETFIELD, Index, Name}), 97 | receive_simple_response(). 98 | 99 | getglobal(L, Name) -> 100 | command(L, {?ERL_LUA_GETGLOBAL, Name}), 101 | receive_simple_response(). 102 | 103 | gettable(L, global, Name) when is_atom(Name) -> 104 | gettable(L, global, atom_to_list(Name)); 105 | gettable(L, global, Name) -> 106 | getfield(L, global, Name), 107 | {ok, T} = gettop(L), 108 | Table = gettable(L, T), 109 | lua:remove(L, T), 110 | Table. 111 | 112 | gettable(L, T) -> 113 | pushnil(L), 114 | gettablekey(L, T). 115 | 116 | gettablekey(L, T) -> 117 | next(L, T), 118 | {ok, OT} = gettop(L), 119 | case OT of 120 | T -> 121 | []; 122 | _ -> 123 | %% values can be tables or anything else 124 | %% recurse on tables 125 | case type_atom(L, -1) of 126 | {ok, table} -> 127 | %% keys can be strings or numbers 128 | case type_atom(L, -2) of 129 | {ok, number} -> 130 | {ok, Key} = tonumber(L, -2); 131 | _KT -> 132 | {ok, Key} = tolstring(L, -2) 133 | end, 134 | KV = {Key, gettable(L, T + 2)}, 135 | remove(L, -1), 136 | [KV|gettablekey(L, T)]; 137 | _TA -> 138 | {ok, _Type, Val} = pop(L), 139 | %% keys can be strings or numbers 140 | case type_atom(L, -1) of 141 | {ok, number} -> 142 | {ok, Key} = tonumber(L, -1); 143 | _KT -> 144 | {ok, Key} = tolstring(L, -1) 145 | end, 146 | [{Key, Val}|gettablekey(L, T)] 147 | end 148 | end. 149 | 150 | gettop(L) -> 151 | command(L, {?ERL_LUA_GETTOP}), 152 | receive_valued_response(). 153 | 154 | next(L, Index) -> 155 | command(L, {?ERL_LUA_NEXT, Index}), 156 | receive_simple_response(). 157 | 158 | pop(L) -> 159 | {ok, R} = gettop(L), 160 | if 161 | R < 1 -> 162 | {ok, empty}; 163 | true -> 164 | {ok, T} = type_atom(L, R), 165 | case T of 166 | number -> 167 | {ok, N} = tonumber(L, R), 168 | remove(L, R), 169 | {ok, number, N}; 170 | string -> 171 | {ok, N} = tolstring(L, R), 172 | remove(L, R), 173 | {ok, string, N}; 174 | boolean -> 175 | {other, N} = toboolean(L, R), 176 | remove(L, R), 177 | {ok, boolean, N}; 178 | function -> 179 | remove(L, R), 180 | {ok, function, function}; 181 | _ -> 182 | remove(L, R), 183 | {ok, unknown, unknown} 184 | end 185 | end. 186 | 187 | push(L, Term) when is_number(Term) -> 188 | pushnumber(L, Term); 189 | push(L, Term) when is_list(Term) -> 190 | pushstring(L, Term); 191 | push(L, true) -> 192 | pushboolean(L, true); 193 | push(L, false) -> 194 | pushboolean(L, false); 195 | push(L, Term) when is_atom(Term) -> 196 | pushstring(L, atom_to_list(Term)). 197 | 198 | pushboolean(L, Bool) -> 199 | command(L, {?ERL_LUA_PUSHBOOLEAN, Bool}), 200 | receive_simple_response(). 201 | 202 | pushinteger(L, Int) when is_integer(Int) -> 203 | command(L, {?ERL_LUA_PUSHINTEGER, Int}), 204 | receive_simple_response(). 205 | 206 | pushstring(L, String) when is_list(String) -> 207 | command(L, {?ERL_LUA_PUSHSTRING, String}), 208 | receive_simple_response(). 209 | 210 | pushnil(L) -> 211 | command(L, {?ERL_LUA_PUSHNIL}), 212 | receive_simple_response(). 213 | 214 | pushnumber(L, Num) when is_number(Num) -> 215 | command(L, {?ERL_LUA_PUSHNUMBER, Num}), 216 | receive_simple_response(). 217 | 218 | remove(L, Index) -> 219 | command(L, {?ERL_LUA_REMOVE, Index}), 220 | receive_simple_response(). 221 | 222 | setfield(L, global, Name) -> 223 | setglobal(L, Name); 224 | setfield(L, Index, Name) -> 225 | command(L, {?ERL_LUA_SETFIELD, Index, Name}), 226 | receive_simple_response(). 227 | 228 | setglobal(L, Name) -> 229 | command(L, {?ERL_LUA_SETGLOBAL, Name}), 230 | receive_simple_response(). 231 | 232 | toboolean(L, Index) -> 233 | command(L, {?ERL_LUA_TOBOOLEAN, Index}), 234 | receive_valued_response(). 235 | 236 | tointeger(L, Index) -> 237 | command(L, {?ERL_LUA_TOINTEGER, Index}), 238 | receive_valued_response(). 239 | 240 | tolstring(L, Index) -> 241 | command(L, {?ERL_LUA_TOLSTRING, Index}), 242 | receive_valued_response(). 243 | 244 | tonumber(L, Index) -> 245 | command(L, {?ERL_LUA_TONUMBER, Index}), 246 | {ok, Value} = receive_valued_response(), 247 | Value2 = list_to_binary(Value), 248 | {ok, binary_to_term(Value2)}. 249 | 250 | type(L, Index) -> 251 | command(L, {?ERL_LUA_TYPE, Index}), 252 | receive_valued_response(). 253 | 254 | type_atom(L, Index) -> 255 | command(L, {?ERL_LUA_TYPE, Index}), 256 | R = receive_valued_response(), 257 | case R of 258 | {ok, Str} -> 259 | {ok, type_int_to_atom(Str)}; 260 | _ -> 261 | R 262 | end. 263 | 264 | type_int_to_atom(TypeInt) when is_integer(TypeInt) -> 265 | case TypeInt of 266 | 0 -> 267 | Atom = nil; 268 | 1 -> 269 | Atom = boolean; 270 | 2 -> 271 | Atom = light_user_data; 272 | 3 -> 273 | Atom = number; 274 | 4 -> 275 | Atom = string; 276 | 5 -> 277 | Atom = table; 278 | 6 -> 279 | Atom = function; 280 | 7 -> 281 | Atom = user_data; 282 | 8 -> 283 | Atom = thread; 284 | _ -> 285 | Atom = unknown 286 | end, 287 | Atom. 288 | 289 | command(#lua{port=Port}, Data) -> 290 | port_command(Port, term_to_binary(Data)). 291 | 292 | receive_simple_response() -> 293 | receive 294 | ok -> 295 | ok; 296 | error -> 297 | {error, lua_error}; 298 | {error, Reason} -> 299 | {error, Reason}; 300 | Other -> 301 | {other, Other} 302 | after ?STD_TIMEOUT -> 303 | {error, timeout} 304 | end. 305 | 306 | receive_valued_response() -> 307 | receive 308 | {ok, Str} -> 309 | {ok, Str}; 310 | error -> 311 | {error, lua_error}; 312 | Other -> 313 | {other, Other} 314 | after ?STD_TIMEOUT -> 315 | {error, timeout} 316 | end. 317 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/facebox.js: -------------------------------------------------------------------------------- 1 | /* Facebox for Prototype, version 2.0 2 | * By Robert Gaal - http://wakoopa.com 3 | * 4 | * Heavily based on Facebox by Chris Wanstrath - http://famspam.com/facebox 5 | * First ported to Prototype by Phil Burrows - http://blog.philburrows.com 6 | * 7 | * Licensed under the MIT: 8 | * http://www.opensource.org/licenses/mit-license.php 9 | * 10 | * Need help? Join the Google Groups mailing list: 11 | * http://groups.google.com/group/facebox/ 12 | * 13 | * Dependencies: prototype & script.aculo.us + images & CSS files from original facebox 14 | * Usage: Append 'rel="facebox"' to an element to call it inside a so-called facebox 15 | * 16 | *--------------------------------------------------------------------------*/ 17 | 18 | 19 | var Facebox = Class.create({ 20 | initialize : function(extra_set){ 21 | this.settings = { 22 | show_overlay : false, 23 | loading_image : '/images/facebox/loading.gif', 24 | close_image : '/images/facebox/closelabel.gif', 25 | image_types : new RegExp('\.' + ['png', 'jpg', 'jpeg', 'gif'].join('|') + '$', 'i'), 26 | inited : true, 27 | facebox_html : '\ 28 | ' 55 | }; 56 | if (extra_set) Object.extend(this.settings, extra_set); 57 | $(document.body).insert({ 58 | bottom: this.settings.facebox_html 59 | }); 60 | 61 | this.preload = [ new Image(), new Image() ]; 62 | this.preload[0].src = this.settings.close_image; 63 | this.preload[1].src = this.settings.loading_image; 64 | 65 | f = this; 66 | $$('#facebox .b:first, #facebox .bl, #facebox .br, #facebox .tl, #facebox .tr').each(function(elem){ 67 | f.preload.push(new Image()); 68 | f.preload.slice(-1).src = elem.getStyle('background-image').replace(/url\((.+)\)/, '$1'); 69 | }); 70 | 71 | this.facebox = $('facebox'); 72 | this.keyPressListener = this.watchKeyPress.bindAsEventListener(this); 73 | 74 | this.watchClickEvents(); 75 | fb = this; 76 | Event.observe($$('#facebox .close').first(), 'click', function(e){ 77 | Event.stop(e); 78 | fb.close() 79 | }); 80 | Event.observe($$('#facebox .close_image').first(), 'click', function(e){ 81 | Event.stop(e); 82 | fb.close() 83 | }); 84 | }, 85 | 86 | watchKeyPress : function(e){ 87 | // Close if espace is pressed or if there's a click outside of the facebox 88 | if (e.keyCode == 27 || !Event.element(e).descendantOf(this.facebox)) this.close(); 89 | }, 90 | 91 | watchClickEvents : function(e){ 92 | var f = this; 93 | $$('a[rel=facebox]').each(function(elem,i){ 94 | Event.observe(elem, 'click', function(e){ 95 | Event.stop(e); 96 | f.click_handler(elem, e); 97 | }); 98 | }); 99 | }, 100 | 101 | loading : function() { 102 | if ($$('#facebox .loading').length == 1) return true; 103 | 104 | contentWrapper = $$('#facebox .content').first(); 105 | contentWrapper.childElements().each(function(elem, i){ 106 | elem.remove(); 107 | }); 108 | contentWrapper.insert({ 109 | bottom: '
    ' 110 | }); 111 | 112 | var pageScroll = document.viewport.getScrollOffsets(); 113 | this.facebox.setStyle({ 114 | 'top': pageScroll.top + (document.viewport.getHeight() / 10) + 'px', 115 | 'left': document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2) + 'px' 116 | }); 117 | 118 | Event.observe(document, 'keypress', this.keyPressListener); 119 | Event.observe(document, 'click', this.keyPressListener); 120 | }, 121 | 122 | reveal_with_overlay : function(data, klass){ 123 | this.settings.show_overlay = true; 124 | this.reveal(data, klass); 125 | }, 126 | 127 | reveal : function(data, klass){ 128 | this.loading(); 129 | load = $$('#facebox .loading').first(); 130 | if(load) load.remove(); 131 | 132 | if(this.settings.show_overlay) this.show_overlay(); 133 | 134 | contentWrapper = $$('#facebox .content').first(); 135 | if (klass) contentWrapper.addClassName(klass); 136 | contentWrapper.insert({ 137 | bottom: data 138 | }); 139 | 140 | $$('#facebox .body').first().childElements().each(function(elem,i){ 141 | elem.show(); 142 | }); 143 | 144 | if(!this.facebox.visible()) new Effect.Appear(this.facebox, { 145 | duration: .3 146 | }); 147 | this.facebox.setStyle({ 148 | 'left': document.viewport.getWidth() / 2 - (this.facebox.getWidth() / 2) + 'px' 149 | }); 150 | 151 | Event.observe(document, 'keypress', this.keyPressListener); 152 | Event.observe(document, 'click', this.keyPressListener); 153 | }, 154 | 155 | close : function(){ 156 | if(this.settings.show_overlay) this.hide_overlay(); 157 | new Effect.Fade('facebox', { 158 | duration: .3 159 | }); 160 | }, 161 | 162 | click_handler : function(elem, e){ 163 | this.loading(); 164 | Event.stop(e); 165 | 166 | // support for rel="facebox[.inline_popup]" syntax, to add a class 167 | var klass = elem.rel.match(/facebox\[\.(\w+)\]/); 168 | if (klass) klass = klass[1]; 169 | 170 | new Effect.Appear(this.facebox, { 171 | duration: .3 172 | }); 173 | 174 | if (elem.href.match(/#/)){ 175 | var url = window.location.href.split('#')[0]; 176 | var target = elem.href.replace(url+'#',''); 177 | // var data = $$(target).first(); 178 | var d = $(target); 179 | // create a new element so as to not delete the original on close() 180 | var data = new Element(d.tagName); 181 | data.innerHTML = d.innerHTML; 182 | this.reveal(data, klass); 183 | } else if (elem.href.match(this.settings.image_types)) { 184 | var image = new Image(); 185 | fb = this; 186 | image.onload = function() { 187 | fb.reveal('
    ', klass) 188 | } 189 | image.src = elem.href; 190 | } else { 191 | var fb = this; 192 | var url = elem.href; 193 | new Ajax.Request(url, { 194 | method : 'get', 195 | onFailure : function(transport){ 196 | fb.reveal(transport.responseText, klass); 197 | }, 198 | onSuccess : function(transport){ 199 | fb.reveal(transport.responseText, klass); 200 | } 201 | }); 202 | 203 | } 204 | }, 205 | 206 | show_overlay: function() { 207 | if (!$("facebox_overlay")) { 208 | new Insertion.Top(document.body, ''); 209 | } 210 | this.set_overlay_size(); 211 | // this.hide_selects(); 212 | new Effect.Appear("facebox_overlay", { 213 | duration: 0.3 214 | }); 215 | }, 216 | 217 | hide_overlay: function() { 218 | // this.show_selects(); 219 | new Effect.Fade("facebox_overlay", { 220 | duration: 0.3 221 | }); 222 | }, 223 | 224 | set_overlay_size: function() { 225 | if (window.innerHeight && window.scrollMaxY) { 226 | yScroll = window.innerHeight + window.scrollMaxY; 227 | } else if (document.body.scrollHeight > document.body.offsetHeight) { 228 | yScroll = document.body.scrollHeight; 229 | } else { 230 | yScroll = document.body.offsetHeight; 231 | } 232 | $("facebox_overlay").style['height'] = (yScroll+20) + "px"; 233 | }, 234 | 235 | hide_selects: function() { 236 | selects = document.getElementsByTagName("select"); 237 | for (i = 0; i < selects.length; i++) { 238 | selects[i].style.visibility = "hidden"; 239 | } 240 | }, 241 | 242 | show_selects: function() { 243 | selects = document.getElementsByTagName("select"); 244 | for (i = 0; i < selects.length; i++) { 245 | selects[i].style.visibility = "visible"; 246 | } 247 | } 248 | }); 249 | 250 | var facebox; 251 | document.observe('dom:loaded', function(){ 252 | facebox = new Facebox(); 253 | }); -------------------------------------------------------------------------------- /erlmon-1.0/c_src/commands.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "erlua.h" 8 | #include "commands.h" 9 | 10 | static void reply_ok(lua_drv_t *driver_data); 11 | static void reply_error(lua_drv_t *driver_data); 12 | static char* decode_string(char *buf, int *index); 13 | 14 | 15 | void 16 | erl_lua_call(lua_drv_t *driver_data, char *buf, int index) 17 | { 18 | long args, results; 19 | 20 | ei_decode_long(buf, &index, &args); 21 | ei_decode_long(buf, &index, &results); 22 | 23 | lua_call(driver_data->L, args, results); 24 | 25 | reply_ok(driver_data); 26 | } 27 | 28 | void 29 | erl_lua_concat(lua_drv_t *driver_data, char *buf, int index) 30 | { 31 | long n; 32 | 33 | ei_decode_long(buf, &index, &n); 34 | 35 | lua_concat(driver_data->L, n); 36 | 37 | reply_ok(driver_data); 38 | } 39 | 40 | void 41 | erl_lua_getfield(lua_drv_t *driver_data, char *buf, int index) 42 | { 43 | long i; 44 | char *name; 45 | 46 | ei_decode_long(buf, &index, &i); 47 | name = decode_string(buf, &index); 48 | 49 | lua_getfield(driver_data->L, i, name); 50 | 51 | reply_ok(driver_data); 52 | free(name); 53 | } 54 | 55 | void 56 | erl_lua_getglobal(lua_drv_t *driver_data, char *buf, int index) 57 | { 58 | char *name; 59 | 60 | name = decode_string(buf, &index); 61 | 62 | lua_getglobal(driver_data->L, name); 63 | 64 | reply_ok(driver_data); 65 | free(name); 66 | } 67 | 68 | void 69 | erl_lua_gettop(lua_drv_t *driver_data, char *buf, int index) 70 | { 71 | int size; 72 | 73 | size = lua_gettop(driver_data->L); 74 | 75 | ErlDrvTermData spec[] = { 76 | ERL_DRV_ATOM, ATOM_OK, 77 | ERL_DRV_INT, (ErlDrvTermData) size, 78 | ERL_DRV_TUPLE, 2 79 | }; 80 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 81 | } 82 | 83 | void 84 | erl_lua_next(lua_drv_t *driver_data, char *buf, int index) 85 | { 86 | long n; 87 | 88 | ei_decode_long(buf, &index, &n); 89 | 90 | lua_next(driver_data->L, n); 91 | 92 | reply_ok(driver_data); 93 | } 94 | 95 | void 96 | erl_lua_pushboolean(lua_drv_t *driver_data, char *buf, int index) 97 | { 98 | int b; 99 | 100 | ei_decode_boolean(buf, &index, &b); 101 | 102 | lua_pushboolean(driver_data->L, b); 103 | 104 | reply_ok(driver_data); 105 | } 106 | 107 | void 108 | erl_lua_pushinteger(lua_drv_t *driver_data, char *buf, int index) 109 | { 110 | long long num; 111 | 112 | ei_decode_longlong(buf, &index, &num); 113 | 114 | lua_pushinteger(driver_data->L, num); 115 | 116 | reply_ok(driver_data); 117 | } 118 | 119 | void 120 | erl_lua_pushstring(lua_drv_t *driver_data, char *buf, int index) 121 | { 122 | char *str; 123 | 124 | str = decode_string(buf, &index); 125 | 126 | lua_pushstring(driver_data->L, str); 127 | 128 | reply_ok(driver_data); 129 | free(str); 130 | } 131 | 132 | void 133 | erl_lua_pushnil(lua_drv_t *driver_data, char *buf, int index) 134 | { 135 | lua_pushnil(driver_data->L); 136 | reply_ok(driver_data); 137 | } 138 | 139 | void 140 | erl_lua_pushnumber(lua_drv_t *driver_data, char *buf, int index) 141 | { 142 | double dnum; 143 | long long lnum; 144 | int type, len; 145 | 146 | ei_get_type(buf, &index, &type, &len); 147 | 148 | switch (type) { 149 | case ERL_FLOAT_EXT: 150 | ei_decode_double(buf, &index, &dnum); 151 | lua_pushnumber(driver_data->L, dnum); 152 | break; 153 | default: 154 | ei_decode_longlong(buf, &index, &lnum); 155 | lua_pushnumber(driver_data->L, lnum); 156 | break; 157 | } 158 | 159 | reply_ok(driver_data); 160 | } 161 | 162 | void 163 | erl_lua_remove(lua_drv_t *driver_data, char *buf, int index) 164 | { 165 | long i; 166 | 167 | ei_decode_long(buf, &index, &i); 168 | 169 | lua_remove(driver_data->L, i); 170 | 171 | reply_ok(driver_data); 172 | } 173 | 174 | void 175 | erl_lua_setfield(lua_drv_t *driver_data, char *buf, int index) 176 | { 177 | long i; 178 | char *name; 179 | 180 | ei_decode_long(buf, &index, &i); 181 | name = decode_string(buf, &index); 182 | 183 | lua_setfield(driver_data->L, i, name); 184 | 185 | reply_ok(driver_data); 186 | free(name); 187 | } 188 | 189 | void 190 | erl_lua_setglobal(lua_drv_t *driver_data, char *buf, int index) 191 | { 192 | char *name; 193 | 194 | name = decode_string(buf, &index); 195 | 196 | lua_setglobal(driver_data->L, name); 197 | 198 | reply_ok(driver_data); 199 | free(name); 200 | } 201 | 202 | void 203 | erl_lua_toboolean(lua_drv_t *driver_data, char *buf, int index) 204 | { 205 | long i; 206 | int res; 207 | ErlDrvTermData spec[2]; 208 | spec[0] = ERL_DRV_ATOM; 209 | 210 | ei_decode_long(buf, &index, &i); 211 | 212 | res = lua_toboolean(driver_data->L, i); 213 | if (res) 214 | spec[1] = driver_mk_atom("true"); 215 | else 216 | spec[1] = driver_mk_atom("false"); 217 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 218 | } 219 | 220 | void 221 | erl_lua_tointeger(lua_drv_t *driver_data, char *buf, int index) 222 | { 223 | long i; 224 | long long res; 225 | 226 | ei_decode_long(buf, &index, &i); 227 | 228 | res = lua_tointeger(driver_data->L, i); 229 | 230 | ErlDrvTermData spec[] = { 231 | ERL_DRV_ATOM, ATOM_OK, 232 | ERL_DRV_INT, (ErlDrvTermData) res, 233 | ERL_DRV_TUPLE, 2 234 | }; 235 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 236 | } 237 | 238 | void 239 | erl_lua_tolstring(lua_drv_t *driver_data, char *buf, int index) 240 | { 241 | size_t len; 242 | long i; 243 | const char *str; 244 | 245 | ei_decode_long(buf, &index, &i); 246 | 247 | str = lua_tolstring(driver_data->L, i, &len); 248 | 249 | ErlDrvTermData spec[] = { 250 | ERL_DRV_ATOM, ATOM_OK, 251 | ERL_DRV_STRING, (ErlDrvTermData) str, len, 252 | ERL_DRV_TUPLE, 2 253 | }; 254 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 255 | } 256 | 257 | 258 | /* TODO: return a binary instead of a list that is then converted to a binary */ 259 | void 260 | erl_lua_tonumber(lua_drv_t *driver_data, char *buf, int index) 261 | { 262 | long i; 263 | double res; 264 | int encode_i = 0; 265 | int size; 266 | char *eibuf; 267 | 268 | ei_decode_long(buf, &index, &i); 269 | 270 | res = lua_tonumber(driver_data->L, i); 271 | 272 | ei_encode_version(NULL, &encode_i); 273 | if ((long long) res == res) { 274 | ei_encode_longlong(NULL, &encode_i, (long long) res); 275 | size = encode_i; 276 | encode_i = 0; 277 | eibuf = malloc(sizeof(char) * (size + 1)); 278 | 279 | ei_encode_version(eibuf, &encode_i); 280 | ei_encode_longlong(eibuf, &encode_i, res); 281 | } else { 282 | ei_encode_double(NULL, &encode_i, res); 283 | size = encode_i; 284 | encode_i = 0; 285 | eibuf = malloc(sizeof(char) * (size + 1)); 286 | 287 | ei_encode_version(eibuf, &encode_i); 288 | ei_encode_double(eibuf, &encode_i, res); 289 | } 290 | 291 | ErlDrvTermData spec[] = { 292 | ERL_DRV_ATOM, ATOM_OK, 293 | ERL_DRV_STRING, (ErlDrvTermData) eibuf, size, 294 | ERL_DRV_TUPLE, 2 295 | }; 296 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 297 | free(eibuf); 298 | //driver_free_binary(bin); 299 | } 300 | 301 | void 302 | erl_lua_type(lua_drv_t *driver_data, char *buf, int index) 303 | { 304 | long i; 305 | int lua_t; 306 | 307 | ei_decode_long(buf, &index, &i); 308 | 309 | lua_t = lua_type(driver_data->L, i); 310 | 311 | ErlDrvTermData spec[] = { 312 | ERL_DRV_ATOM, ATOM_OK, 313 | ERL_DRV_INT, (ErlDrvTermData) lua_t, 314 | ERL_DRV_TUPLE, 2 315 | }; 316 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 317 | } 318 | 319 | 320 | void 321 | erl_lual_dostring(lua_drv_t *driver_data, char *buf, int index) 322 | { 323 | char *code; 324 | 325 | code = decode_string(buf, &index); 326 | 327 | if (!luaL_dostring(driver_data->L, code)) 328 | reply_ok(driver_data); 329 | else 330 | reply_error(driver_data); 331 | } 332 | 333 | void 334 | erl_lual_dofile(lua_drv_t *driver_data, char *buf, int index) 335 | { 336 | char *code; 337 | 338 | code = decode_string(buf, &index); 339 | 340 | if (!luaL_dofile(driver_data->L, code)) 341 | reply_ok(driver_data); 342 | else 343 | reply_error(driver_data); 344 | } 345 | 346 | void 347 | erl_lua_no_command(lua_drv_t *driver_data) 348 | { 349 | ErlDrvTermData spec[] = { 350 | ERL_DRV_ATOM, ATOM_ERROR, 351 | ERL_DRV_STRING, (ErlDrvTermData) "No Command Found", 16, 352 | ERL_DRV_TUPLE, 2 353 | }; 354 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 355 | } 356 | 357 | 358 | static void 359 | reply_ok(lua_drv_t *driver_data) 360 | { 361 | ErlDrvTermData spec[] = {ERL_DRV_ATOM, ATOM_OK}; 362 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 363 | } 364 | 365 | static void 366 | reply_error(lua_drv_t *driver_data) 367 | { 368 | ErlDrvTermData spec[] = {ERL_DRV_ATOM, ATOM_ERROR}; 369 | driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0])); 370 | } 371 | 372 | 373 | static char* 374 | decode_string(char *buf, int *index) 375 | { 376 | int type, length; 377 | char *str; 378 | 379 | ei_get_type(buf, index, &type, &length); 380 | str = malloc(sizeof(char) * (length + 1)); 381 | ei_decode_string(buf, index, str); 382 | return str; 383 | } 384 | -------------------------------------------------------------------------------- /erlmon-1.0/wwwroot/nitrogen/livevalidation.js: -------------------------------------------------------------------------------- 1 | // LiveValidation 1.3 (standalone version) 2 | // Copyright (c) 2007-2008 Alec Hill (www.livevalidation.com) 3 | // LiveValidation is licensed under the terms of the MIT License 4 | var LiveValidation=function(B,A){this.initialize(B,A);};LiveValidation.VERSION="1.3 standalone";LiveValidation.TEXTAREA=1;LiveValidation.TEXT=2;LiveValidation.PASSWORD=3;LiveValidation.CHECKBOX=4;LiveValidation.SELECT=5;LiveValidation.FILE=6;LiveValidation.massValidate=function(C){var D=true;for(var B=0,A=C.length;B=300){this.removeMessageAndFieldClass();}var A=this;if(this.timeout){clearTimeout(A.timeout);}this.timeout=setTimeout(function(){A.validate();},A.wait);},doOnBlur:function(A){this.focused=false;this.validate(A);},doOnFocus:function(A){this.focused=true;this.removeMessageAndFieldClass();},getElementType:function(){switch(true){case (this.element.nodeName.toUpperCase()=="TEXTAREA"):return LiveValidation.TEXTAREA;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="TEXT"):return LiveValidation.TEXT;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="PASSWORD"):return LiveValidation.PASSWORD;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="CHECKBOX"):return LiveValidation.CHECKBOX;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="FILE"):return LiveValidation.FILE;case (this.element.nodeName.toUpperCase()=="SELECT"):return LiveValidation.SELECT;case (this.element.nodeName.toUpperCase()=="INPUT"):throw new Error("LiveValidation::getElementType - Cannot use LiveValidation on an "+this.element.type+" input!");default:throw new Error("LiveValidation::getElementType - Element must be an input, select, or textarea!");}},doValidations:function(){this.validationFailed=false;for(var C=0,A=this.validations.length;CNumber(C)){Validate.fail(K);}break;}return true;},Format:function(C,E){var C=String(C);var E=E||{};var A=E.failureMessage||"Not valid!";var B=E.pattern||/./;var D=E.negate||false;if(!D&&!B.test(C)){Validate.fail(A);}if(D&&B.test(C)){Validate.fail(A);}return true;},Email:function(B,C){var C=C||{};var A=C.failureMessage||"Must be a valid email address!";Validate.Format(B,{failureMessage:A,pattern:/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i});return true;},Length:function(F,G){var F=String(F);var G=G||{};var E=((G.minimum)||(G.minimum==0))?G.minimum:null;var H=((G.maximum)||(G.maximum==0))?G.maximum:null;var C=((G.is)||(G.is==0))?G.is:null;var A=G.wrongLengthMessage||"Must be "+C+" characters long!";var B=G.tooShortMessage||"Must not be less than "+E+" characters long!";var D=G.tooLongMessage||"Must not be more than "+H+" characters long!";switch(true){case (C!==null):if(F.length!=Number(C)){Validate.fail(A);}break;case (E!==null&&H!==null):Validate.Length(F,{tooShortMessage:B,minimum:E});Validate.Length(F,{tooLongMessage:D,maximum:H});break;case (E!==null):if(F.lengthNumber(H)){Validate.fail(D);}break;default:throw new Error("Validate::Length - Length(s) to validate against must be provided!");}return true;},Inclusion:function(H,F){var F=F||{};var K=F.failureMessage||"Must be included in the list!";var G=(F.caseSensitive===false)?false:true;if(F.allowNull&&H==null){return true;}if(!F.allowNull&&H==null){Validate.fail(K);}var D=F.within||[];if(!G){var A=[];for(var C=0,B=D.length;C