et_contents_viewer.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 591 行 · 第 1/2 页
ERL
591 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%%%----------------------------------------------------------------------%% Purpose: Displays details of a trace event%%-----------------------------------------------------------------------module(et_contents_viewer).-behaviour(gen_server).%% External exports-export([start_link/1, stop/1]).%% gen_server callbacks-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).-include("../include/et.hrl").-include("et_internal.hrl").-record(state, {parent_pid, % Pid of parent process viewer_pid, % Pid of viewer process event_order, % Field to be used as primary key event, % The original event filtered_event, % Event processed by active filter active_filter, % Name of the active filter filters, % List of possible filters win, % GUI: Window object packer, % GUI: Packer object width, % GUI: Window width height}). % GUI: Window height%%%----------------------------------------------------------------------%%% Client side%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% start_link(Options) -> {ok, ContentsPid} | {error, Reason}%%%% Start an viewer for the event contents as window in GS%%%% Options = [option()]%% %% option() =%% %% {parent_pid, pid()} | % Pid of parent process%% {viewer_pid, pid()} | % Pid of viewer process%% {event_order, event_order()} | % Field to be used as primary key %% {active_filter, atom()} | % Name of the active filter%% {filter, atom(), fun()} % A named filter fun%% %% event_order() = 'trace_ts' | 'event_ts'%% ContentsPid = pid()%% Reason = term()%%----------------------------------------------------------------------start_link(Options) -> case parse_opt(Options, default_state()) of {ok, S} -> case gen_server:start_link(?MODULE, [S], []) of {ok, ContentsPid} when S#state.parent_pid /= self() -> unlink(ContentsPid), {ok, ContentsPid}; Other -> Other end; {error, Reason} -> {error, Reason} end.default_state() -> #state{parent_pid = self(), viewer_pid = undefined, active_filter = collector, filters = [#filter{name = collector, function = fun(E) -> E end}], width = 600, height = 300}.parse_opt([], S) -> Name = S#state.active_filter, Filters = S#state.filters, if S#state.event == undefined -> {error, {badarg, no_event}}; atom(Name) -> case lists:keysearch(Name, #filter.name, Filters) of {value, F} when record(F, filter) -> {ok, S#state{active_filter = Name}}; false -> {error, {badarg, {no_such_filter, Name, Filters}}} end end;parse_opt([H | T], S) -> case H of {parent_pid, ParentPid} when pid(ParentPid) -> parse_opt(T, S#state{parent_pid = ParentPid}); {viewer_pid, ViewerPid} when pid(ViewerPid) -> parse_opt(T, S#state{viewer_pid = ViewerPid}); {event_order, trace_ts} -> parse_opt(T, S#state{event_order = trace_ts}); {event_order, event_ts} -> parse_opt(T, S#state{event_order = event_ts}); {event, Event} when record(Event, event) -> parse_opt(T, S#state{event = Event}); {active_filter, Name} when atom(Name) -> parse_opt(T, S#state{active_filter = Name}); F when record(F, filter), atom(F#filter.name), function(F#filter.function) -> Filters = lists:keydelete(F#filter.name, #filter.name, S#state.filters), Filters2 = lists:keysort(#filter.name, [F | Filters]), parse_opt(T, S#state{filters = Filters2}); {width, Width} when integer(Width), Width > 0 -> parse_opt(T, S#state{width = Width}); {height, Height} when integer(Height), Height > 0 -> parse_opt(T, S#state{height = Height}); Bad -> {error, {bad_option, Bad}} end;parse_opt(BadList, _S) -> {error, {bad_option_list, BadList}}.%%----------------------------------------------------------------------%% stop(ContentsPid) -> ok%%%% Stops a contents viewer process%%%% ContentsPid = pid()%%----------------------------------------------------------------------stop(ContentsPid) -> unlink(ContentsPid), call(ContentsPid, stop).call(ContentsPid, Request) -> gen_server:call(ContentsPid, Request, infinity).%%%----------------------------------------------------------------------%%% Callback functions from gen_server%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, State} |%% {ok, State, Timeout} |%% ignore |%% {stop, Reason}%%----------------------------------------------------------------------init([S]) when record(S, state) -> process_flag(trap_exit, true), S2 = create_window(S), {ok, S2}.%%----------------------------------------------------------------------%% Func: handle_call/3%% Returns: {reply, Reply, State} |%% {reply, Reply, State, Timeout} |%% {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, Reply, State} | (terminate/2 is called)%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_call(stop, _From, S) -> unlink(S#state.parent_pid), {stop, shutdown, ok, S};handle_call(Request, From, S) -> ok = error_logger:format("~p(~p): handle_call(~p, ~p, ~p)~n", [?MODULE, self(), Request, From, S]), Reply = {error, {bad_request, Request}}, {reply, Reply, S}.%%----------------------------------------------------------------------%% Func: handle_cast/2%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_cast(Msg, S) -> ok = error_logger:format("~p(~p): handle_cast(~p, ~p)~n", [?MODULE, self(), Msg, S]), {noreply, S}.%%----------------------------------------------------------------------%% Func: handle_info/2%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%----------------------------------------------------------------------handle_info({gs, Button, click, Data, _Other}, S) -> case Button of close -> gs:destroy(S#state.win), {stop, normal, S}; save -> Event = S#state.event, Bin = list_to_binary(event_to_string(Event, S#state.event_order)), TimeStamp = case S#state.event_order of trace_ts -> Event#event.trace_ts; event_ts -> Event#event.event_ts end, FileName = ["et_contents_viewer_", now_to_string(TimeStamp), ".save"], file:write_file(lists:flatten(FileName), Bin), {noreply, S}; _PopupMenuItem when record(Data, filter) -> F = Data, ChildState= S#state{active_filter = F#filter.name}, case gen_server:start_link(?MODULE, [ChildState], []) of {ok, Pid} when S#state.parent_pid /= self() -> unlink(Pid), {noreply, S}; _ -> {noreply, S} end; {hide, Actors} -> send_viewer_event(S, {delete_actors, Actors}), {noreply, S}; {show, Actors} -> send_viewer_event(S, {insert_actors, Actors}), {noreply, S}; {mode, Mode} -> send_viewer_event(S, {mode, Mode}), {noreply, S}; Nyi -> ok = error_logger:format("~p: click ~p ignored (nyi)~n", [?MODULE, Nyi]), {noreply, S} end;handle_info({gs, _Obj, destroy,_, _}, S) -> unlink(S#state.parent_pid), gs:destroy(S#state.win), {stop, normal, S};handle_info({gs, _Obj, keypress, _, [KeySym, _Keycode, _Shift, _Control | _]}, S) -> case KeySym of 'c' -> gs:destroy(S#state.win), {stop, normal, S}; 'f' -> E = S#state.filtered_event, From = E#event.from, send_viewer_event(S, {delete_actors, [From]}), {noreply, S}; 't' -> E = S#state.filtered_event, To = E#event.to, send_viewer_event(S, {delete_actors, [To]}), {noreply, S}; 'b' -> E = S#state.filtered_event, From = E#event.from, To = E#event.to, send_viewer_event(S, {delete_actors, [From, To]}), {noreply, S}; 'F' -> E = S#state.filtered_event, From = E#event.from, send_viewer_event(S, {insert_actors, [From]}), {noreply, S}; 'T' -> E = S#state.filtered_event, To = E#event.to, send_viewer_event(S, {insert_actors, [To]}), {noreply, S}; 'B' -> E = S#state.filtered_event, From = E#event.from, To = E#event.to, send_viewer_event(S, {insert_actors, [From, To]}), {noreply, S}; 's' -> E = S#state.filtered_event, From = E#event.from, To = E#event.to,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?