1 / 8

Camtool - monitoring realtime information

Camtool - monitoring realtime information. webcam images for currently observing stations taken from remote URL, cached in Erlang DB webcam definitions stored in MySQL database URL, associated databasekey, refreshrate TSYS plots taken from logfile monitoring utility’s gnuplot frontend

ross-barton
Download Presentation

Camtool - monitoring realtime information

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Camtool - monitoring realtime information • webcam images for currently observing stations • taken from remote URL, cached in Erlang DB • webcam definitions stored in MySQL database • URL, associated databasekey, refreshrate • TSYS plots • taken from logfile monitoring utility’s gnuplot frontend • also cached locally in Erlang DB • generate webpage(s) with dynamic content • serve the images from Erlang i.s.o. disk • fault tolerant: if process dies, restart it

  2. Startup of the utility start() -> % gen_servers make interfacing to a % piece of code very simple! % They are trivial to create and GREAT % our mnesia database interface, a gen_server dumpstore:start(), % virtual time server, also a gen_server nowserver:start_link(), % these are supervisors webcammonitor:start_link(), tsysmonitor:start_link(), % webserver, mapping URLs to Erlang calls webtool:start( standard_path, [{port, 8000}, {bind_address, {0,0,0,0}}] ).

  3. a supervisor: webcammonitor init(_) -> {one_for_one, 10, 1}, [ % This is the list of (static) ChildSpecifications % {Module, Function, [Arguments]} % the database connection first {dbconn, {mysql, start_link,[pool,”Host”, “User”, “Pass”, “DB”]}, permanent, 1000, worker, []}, % Poll(*) JSON from “.py” URL for current status % implemented as a gen_server {jsonneer, {jsonserver, start_link, []}, permanent, 1000, worker, []}, % Poll(*) the current status from the jsonserver % also implemented as a gen_server {monitorloop, {webcamloop, start_link, []}, permanent, 1000, worker, []} ] }. (*) In future version maybe publish-subscribe architecture

  4. a gen_server: jsonserver % Handle a clock-tick, fetch new “current” data. handle_cast(tick, State) -> % Get the current time {{Y,M,D}, {HH,MM,SS}} = nowserver:datetime(), % Call a pythonscript over HTTP (queries SQLite DB and returns result as JSON) B = “http://beoserv-m.jivepci:8090/current_vlbi.py?datetime=%d-%d-%d %d:%d:%d”, Url = io_lib:format(B, [Y,M,D,HH,MM,SS]), % Actually GET the json JSON = case http:request(Url) of % only accept http-status “200” (succesfully retrieved url) {ok, {{_200,_}, _, Body}} -> Body; _ -> [] end, % And parse it Obj = case rfc4627:decode(JSON) of {ok, {obj, KVList}, _} -> KVList; % Parsed into a [{Key, Value}[,{Key,Value}]] {ok, List, _} -> [{stations, List}]; _ -> [{stations, []}] end, {noreply, dict:store(currentjson, Obj, State)}.

  5. Dynamic supervision: add/remove childs otf % Experiment stayed the same, now add/remove watchers update(NewExp, NewExp, CurrentStations, State) -> OldSet = sets:from_list(dict:fetch(stations, State)), NewSet = sets:from_list(CurrentStations), Removed = sets:subtract(OldSet, NewSet), Added = sets:subtract(NewSet, sets:intersection(OldSet,NewSet)), S0 = unwatch_tsys(sets:to_list(Removed), State), S1 = watch_tsys(sets:to_list(Added), S0) % dynamically add a child to the supervisor watch_tsys([Atom|Rest], State) -> % call helper function which creates a “ChildSpecification” Child = tsysgetter:mk(Atom, Expt, Station, DBKey), supervisor:start_child(?TSYSMONITOR, Child) % And remove it from supervision unwatch_tsys([Atom|Rest], State) -> supervisor:terminate_child(?TSYSMONITOR, Atom), supervisor:delete_child(?TSYSMONITOR, Atom),

  6. mnesia - the database It is transactional - enforced and working. get_data(Id) -> % query the datenbank for a record where the lumpdata is still alive % (i.e. its “age” is <= Now + records’ “time-to-live” (ttl) Fun = fun() -> Now = nowfunc(), qlc:eval( qlc:q( [X || X <- mnesia:table(Table), X#lump.id =:= Id, Now<X#lump.last_refresh+X#lump.ttl] ) ) end, case mnesia:transaction( Fun ) of % data in record “too old” {atomic, []} -> {reply, stale_data, Table}; % Still up-to-date {atomic, [R]} -> {reply, R#lump.data, Table}; % something went wrong {aborted, Reason} -> {reply, {error, Reason}, Table} end;

  7. mnesia - the database It stores binary data, actually any data. % From the webcam-image-getter-process Url = “http://www.jb.man.ac.uk/common/upgrade15m.jpg”, case http:request(Url) of % Only accept statuscode 200 {ok, {{_,200,_}, _Headers, Jpeg}} -> dumpstore:update(DBKey, Jpeg, Now); _ -> error end, % From the tsys-image-getter-process case rpc:call('plotserver@services.jive.nl', gnuplot, make_plot, [....]) of {ok, Png} -> dumpstore:update(DBKey, Png, Now); {error, Why} -> Why; _ -> fail_but_buggered_if_we_know_why end,

  8. webtool - mapping URLs to Erlang fn calls -compile(export_all). % return configdata for the “webtool” application webtool(_Args) -> {camtool, [{web_data,{"CamTool","/webcams/camtool/camtool"}}, {alias, {erl_alias, "/webcams", [camtool]}}]}. % The {alias, {erl_alias ...}} statement maps URLs of the form % “/webcams/camtool/function?arguments” % into the Erlang function call [Module:Function(Arguments)] % camtool:function(WebserverEnvironment, Arguments) % http://services.jive.nl:8000/webcams/camtool/image?id=tsys_Mc&foo=bar camtool:image(Env, Args) -> case get_input_data(Args, "id") of undefined -> [head(),”Please give an Id”,closing()]; ImgId -> case dumpstore:get_lump(list_to_atom(ImgId)) of undefined -> [head(), “Invalid ImageId given”, closing()]; R -> MimeType=R#lump.mimetype, Data=R#lump.data, "Content-Type: "++MimeType++"\r\n\r\n"++Data end end.

More Related