Current section
Files
Jump to
Current section
Files
src/xprof_web_handler.erl
-module(xprof_web_handler).
-export([init/3,handle/2,terminate/3]).
-behavior(cowboy_http_handler).
%% Cowboy callbacks
init(_Type, Req, _Opts) ->
{ok, Req, no_state}.
handle(Req, State) ->
{What,_} = cowboy_req:binding(what, Req),
handle_req(What, Req, State).
terminate(_Reason, _Req, _State) ->
ok.
%% Private
%% Handling different HTTP requests
handle_req(<<"funs">>, Req, State) ->
{Query, _} = cowboy_req:qs_val(<<"query">>, Req, <<"">>),
Funs = lists:sort(xprof_vm_info:get_available_funs(Query)),
Json = jiffy:encode(Funs),
lager:debug("Returning ~b functions matching phrase \"~s\"",
[length(Funs), Query]),
{ok, Req2} = cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}],
Json,
Req),
{ok, Req2, State};
handle_req(<<"mon_start">>, Req, State) ->
MFA = {M,F,A} = get_mfa(Req),
lager:info("Starting monitoring via web on ~w:~w/~w~n",[M,F,A]),
xprof_tracer:monitor(MFA),
{ok, Req, State};
handle_req(<<"mon_stop">>, Req, State) ->
MFA = {M,F,A} = get_mfa(Req),
lager:info("Stopping monitoring via web on ~w:~w/~w~n",[M,F,A]),
xprof_tracer:demonitor(MFA),
{ok, Req, State};
handle_req(<<"mon_get_all">>, Req, State) ->
Funs = xprof_tracer:all_monitored(),
FunsArr = [tuple_to_list(MFA) || MFA <- Funs],
Json = jiffy:encode(FunsArr),
{ok, ResReq} = cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}],
Json, Req),
{ok, ResReq, State};
handle_req(<<"data">>, Req, State) ->
MFA = get_mfa(Req),
{LastTS, _} = cowboy_req:qs_val(<<"last_ts">>, Req, <<"0">>),
{ok, ResReq} =
case xprof_tracer:data(MFA, binary_to_integer(LastTS)) of
{error, not_found} ->
cowboy_req:reply(404, Req);
Vals ->
Json = jiffy:encode([{Val} || Val <- Vals]),
cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}],
Json, Req)
end,
{ok, ResReq, State};
handle_req(<<"trace_set">>, Req, State) ->
{Spec, _} = cowboy_req:qs_val(<<"spec">>, Req),
{ok, ResReq} = case lists:member(Spec, [<<"all">>, <<"pause">>]) of
true ->
xprof_tracer:trace(list_to_atom(binary_to_list(Spec))),
cowboy_req:reply(200, Req);
false ->
lager:info("Wrong spec for tracing: ~p",[Spec]),
cowboy_req:reply(400, Req)
end,
{ok, ResReq, State};
handle_req(<<"trace_status">>, Req, State) ->
{_, Paused, _} = xprof_tracer:trace_status(),
Json = jiffy:encode({[{tracing, not Paused}]}),
{ok, ResReq} = cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}],
Json, Req),
{ok, ResReq, State};
handle_req(<<"capture">>, Req, State) ->
MFA = {M,F,A} = get_mfa(Req),
{ThresholdStr, _} = cowboy_req:qs_val(<<"threshold">>, Req),
{LimitStr, _} = cowboy_req:qs_val(<<"limit">>, Req),
Threshold = binary_to_integer(ThresholdStr),
Limit = binary_to_integer(LimitStr),
lager:info("Capture ~b calls to ~w:~w:~b~n exceeding ~b ms",
[Limit ,M,F,A,Threshold]),
{ok, CaptureId} = xprof_tracer_handler:capture(MFA, Threshold, Limit),
Json = jiffy:encode({[{capture_id, CaptureId}]}),
{ok, ResReq} = cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}], Json, Req),
{ok, ResReq, State};
handle_req(<<"capture_data">>, Req, State) ->
MFA = get_mfa(Req),
{OffsetStr, _} = cowboy_req:qs_val(<<"offset">>, Req),
Offset = binary_to_integer(OffsetStr),
{ok, {Id, Threshold, Limit}, Items} =
xprof_tracer_handler:get_captured_data(MFA, Offset),
ItemsJson = [{args_res2proplist(Item)} || Item <- Items],
Json = jiffy:encode({[{capture_id, Id},
{threshold, Threshold},
{limit, Limit},
{items, ItemsJson}]}),
{ok, ResReq} = cowboy_req:reply(200,
[{<<"content-type">>,
<<"application/json">>}],
Json, Req),
{ok, ResReq, State}.
%% Helpers
-spec get_mfa(cowboy:req()) -> xprof:mfaid().
get_mfa(Req) ->
{Params, _} = cowboy_req:qs_vals(Req),
{list_to_atom(binary_to_list(proplists:get_value(<<"mod">>, Params))),
list_to_atom(binary_to_list(proplists:get_value(<<"fun">>, Params))),
case proplists:get_value(<<"arity">>, Params) of
<<"*">> -> '*';
Arity -> binary_to_integer(Arity)
end}.
args_res2proplist([Id, Pid, CallTime, Args, Res]) ->
[{id, Id},
{pid, list_to_binary(io_lib:format("~p",[Pid]))},
{call_time, CallTime},
{args, list_to_binary(io_lib:format("~p",[Args]))},
{res, list_to_binary(io_lib:format("~p",[Res]))}].