crashdump_viewer.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,144 行 · 第 1/5 页
ERL
2,144 行
crashdump_viewer_html:info_page(What,[TruncText,LastCalls]); {_,"StackDump"} -> crashdump_viewer_html:info_page(What,[TruncText,Expanded]); {"false",_} -> crashdump_viewer_html:pretty_info_page(What,Expanded); {"true",_} -> crashdump_viewer_html:info_page(What,[TruncText,Expanded]) end, {reply,Reply,State};handle_call({expand_memory,Input},_From,State=#state{file=File,binaries=B}) -> [{"pid",Pid},{"what",What}] = httpd:parse_query(Input), Reply = case truncated_warning([{"=proc",Pid}]) of [] -> Expanded = expand_memory(File,What,Pid,B), crashdump_viewer_html:expanded_memory(What,Expanded); _TW -> Info = "The crashdump is truncated in the middle of this " "process' memory information, so this information " "can not be extracted.", crashdump_viewer_html:info_page(What,Info) end, {reply,Reply,State};handle_call({expand_binary,Input},_From,State=#state{file=File}) -> [{"pos",Pos0}] = httpd:parse_query(Input), Pos = list_to_integer(Pos0), Fd = open(File), pos_bof(Fd,Pos), {Bin,_Line} = get_binary(val(Fd)), close(Fd), Reply=crashdump_viewer_html:expanded_binary(io_lib:format("~p",[Bin])), {reply,Reply,State};handle_call({next,Input},_From,State=#state{file=File}) -> [{"pos",Pos},{"num",N},{"start",Start},{"what",What}] = httpd:parse_query(Input), Tags = related_tags(What), TW = truncated_warning(Tags), Next = get_next(File,list_to_integer(Pos),list_to_integer(N), list_to_integer(Start),What), Reply = crashdump_viewer_html:next(Next,TW), {reply,Reply,State};handle_call(general_info,_From,State=#state{file=File}) -> GenInfo=general_info(File), Reply = crashdump_viewer_html:general_info(GenInfo), {reply,Reply,State};handle_call(procs_summary,_From,State=#state{file=File,shared_heap=SH}) -> ProcsSummary = case State#state.procs_summary of undefined -> procs_summary(File); PS -> PS end, TW = truncated_warning(["=proc"]), Reply = crashdump_viewer_html:procs_summary("pid",ProcsSummary,TW,SH), {reply,Reply,State#state{procs_summary=ProcsSummary,sorted="pid"}};handle_call({sort_procs,Input}, _From, State=#state{shared_heap=SH}) -> {ok,Sort} = get_value("sort",httpd:parse_query(Input)), {ProcsSummary,Sorted} = do_sort_procs(Sort, State#state.procs_summary, State#state.sorted), TW = truncated_warning(["=proc"]), Reply = crashdump_viewer_html:procs_summary(Sort,ProcsSummary,TW,SH), {reply,Reply,State#state{sorted=Sorted}};handle_call({proc_details,Input},_From,State=#state{file=File,shared_heap=SH}) -> {ok,Pid} = get_value("pid",httpd:parse_query(Input)), Reply = case get_proc_details(File,Pid) of {ok,Proc} -> TW = truncated_warning([{"=proc",Pid}]), crashdump_viewer_html:proc_details(Pid,Proc,TW,SH); {other_node,Node} -> TW = truncated_warning(["=visible_node", "=hidden_node", "=not_connected"]), crashdump_viewer_html:nods(Node,TW); not_found -> crashdump_viewer_html:info_page(["Could not find process: ", Pid],?space) end, {reply, Reply, State};handle_call({ports,Input},_From,State=#state{file=File}) -> Reply = case get_value("port",httpd:parse_query(Input)) of {ok,P} -> Id = [$#|P], case get_port(File,Id) of {ok,PortInfo} -> TW = truncated_warning([{"=port",Id}]), crashdump_viewer_html:ports(Id,[PortInfo],TW); {other_node,Node} -> TW = truncated_warning(["=visible_node", "=hidden_node", "=not_connected"]), crashdump_viewer_html:nods(Node,TW); not_found -> crashdump_viewer_html:info_page( ["Could not find port: ",Id],?space) end; error -> % no port identity in Input - get all ports Ports=get_ports(File), TW = truncated_warning(["=port"]), crashdump_viewer_html:ports("Port Information",Ports,TW) end, {reply,Reply,State};handle_call({ets_tables,Input},_From,State=#state{file=File,wordsize=WS}) -> {Pid,Heading,InternalEts} = case get_value("pid",httpd:parse_query(Input)) of {ok,P} -> {P,["ETS Tables for Process ",P],[]}; error -> I = get_internal_ets_tables(File,WS), {'_',"ETS Table Information",I} end, EtsTables = get_ets_tables(File,Pid,WS), TW = truncated_warning(["=ets"]), Reply = crashdump_viewer_html:ets_tables(Heading,EtsTables,InternalEts,TW), {reply,Reply,State};handle_call({timers,Input},_From,State=#state{file=File}) -> {Pid,Heading} = case get_value("pid",httpd:parse_query(Input)) of {ok,P} -> {P,["Timers for Process ",P]}; error -> {'_',"Timer Information"} end, Timers=get_timers(File,Pid), TW = truncated_warning(["=timer"]), Reply = crashdump_viewer_html:timers(Heading,Timers,TW), {reply,Reply,State};handle_call(dist_info,_From,State=#state{file=File}) -> Nods=nods(File), TW = truncated_warning(["=visible_node","=hidden_node","=not_connected"]), Reply = crashdump_viewer_html:nods(Nods,TW), {reply,Reply,State};handle_call(loaded_mods,_From,State=#state{file=File}) -> LoadedMods=loaded_mods(File), TW = truncated_warning(["=mod"]), Reply = crashdump_viewer_html:loaded_mods(LoadedMods,TW), {reply,Reply,State};handle_call({loaded_mod_details,Input},_From,State=#state{file=File}) -> {ok,Mod} = get_value("mod",httpd:parse_query(Input)), ModInfo = get_loaded_mod_details(File,Mod), TW = truncated_warning([{"=mod",Mod}]), Reply = crashdump_viewer_html:loaded_mod_details(ModInfo,TW), {reply,Reply,State};handle_call(funs,_From,State=#state{file=File}) -> Funs=funs(File), TW = truncated_warning(["=fun"]), Reply = crashdump_viewer_html:funs(Funs,TW), {reply,Reply,State};handle_call(atoms,_From,State=#state{file=File,num_atoms=Num}) -> Atoms=atoms(File), TW = truncated_warning(["=atoms","=num_atoms"]), Reply = crashdump_viewer_html:atoms(Atoms,Num,TW), {reply,Reply,State};handle_call(memory,_From,State=#state{file=File}) -> Memory=memory(File), TW = truncated_warning(["=memory"]), Reply = crashdump_viewer_html:memory(Memory,TW), {reply,Reply,State};handle_call(allocated_areas,_From,State=#state{file=File}) -> AllocatedAreas=allocated_areas(File), TW = truncated_warning(["=allocated_areas"]), Reply = crashdump_viewer_html:allocated_areas(AllocatedAreas,TW), {reply,Reply,State};handle_call(allocator_info,_From,State=#state{file=File}) -> SlAlloc=allocator_info(File), TW = truncated_warning(["=allocator"]), Reply = crashdump_viewer_html:allocator_info(SlAlloc,TW), {reply,Reply,State};handle_call(hash_tables,_From,State=#state{file=File}) -> HashTables=hash_tables(File), TW = truncated_warning(["=hash_table","=index_table"]), Reply = crashdump_viewer_html:hash_tables(HashTables,TW), {reply,Reply,State};handle_call(index_tables,_From,State=#state{file=File}) -> IndexTables=index_tables(File), TW = truncated_warning(["=hash_table","=index_table"]), Reply = crashdump_viewer_html:index_tables(IndexTables,TW), {reply,Reply,State}.%%--------------------------------------------------------------------%% Function: handle_cast/2%% Description: Handling cast messages%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%--------------------------------------------------------------------handle_cast({background_done,{Page,File,Binaries},Dict}, State) -> lists:foreach(fun({Key,Val}) -> put(Key,Val) end, Dict), {noreply, State#state{file=File,binaries=Binaries,bg_status={done,Page}}};handle_cast({background_status,Status}, State) -> {noreply, State#state{bg_status=Status}}.%%--------------------------------------------------------------------%% Function: handle_info/2%% Description: Handling all non call/cast messages%% Returns: {noreply, State} |%% {noreply, State, Timeout} |%% {stop, Reason, State} (terminate/2 is called)%%--------------------------------------------------------------------handle_info(_Info, State) -> {noreply, State}.%%--------------------------------------------------------------------%% Function: terminate/2%% Description: Shutdown the server%% Returns: any (ignored by gen_server)%%--------------------------------------------------------------------terminate(_Reason, _State) -> ok.%%--------------------------------------------------------------------%% Func: code_change/3%% Purpose: Convert process state when code is changed%% Returns: {ok, NewState}%%--------------------------------------------------------------------code_change(_OldVsn, State, _Extra) -> {ok, State}.%%--------------------------------------------------------------------%%% Internal functions%%-------------------------------------------------------------------- call(Request) -> gen_server:call(?SERVER,Request,?call_timeout).cast(Msg) -> gen_server:cast(?SERVER,Msg).unexpected(_Fd,{eof,_LastLine},_Where) -> ok; % truncated fileunexpected(Fd,{part,What},Where) -> skip_rest_of_line(Fd), io:format("WARNING: Found unexpected line in ~s:~n~s ...~n",[Where,What]);unexpected(_Fd,What,Where) -> io:format("WARNING: Found unexpected line in ~s:~n~s~n",[Where,What]).truncated_warning([]) -> [];truncated_warning([Tag|Tags]) -> case truncated_here(Tag) of true -> truncated_warning(); false -> truncated_warning(Tags) end.truncated_warning() -> ["WARNING: The crash dump is truncated here. " "Some information might be missing."].truncated_here(Tag) -> case get(truncated) of true -> case get(last_tag) of Tag -> % Tag == {TagType,Id} true; {Tag,_Id} -> true; _LastTag -> truncated_earlier(Tag) end; false -> false end. %% Check if the dump was truncated with the same tag, but earlier id.%% Eg if this is {"=proc","<0.30.0>"}, we should warn if the dump was%% truncated in {"=proc","<0.29.0>"} or earliertruncated_earlier({"=proc",Pid}) -> compare_pid(Pid,get(truncated_proc));truncated_earlier(_Tag) -> false.compare_pid("<"++Id,"<"++OtherId) -> Id>=OtherId;compare_pid(_,_) -> false.background_status(Action,File) -> SizeInfo = filesizeinfo(File), background_status(Action,File,SizeInfo).background_status(translating,File,SizeInfo) -> "Converting " ++ File ++ SizeInfo ++ " to new crashdump format";background_status(processing,File,SizeInfo) -> "Processing " ++ File ++ SizeInfo;background_status(reading,File,SizeInfo) -> "Reading file " ++ File ++ SizeInfo.filesizeinfo(File) -> case file:read_file_info(File) of {ok,#file_info{size=Size}} -> " (" ++ integer_to_list(Size) ++ " bytes)"; _X -> "" end.open(File) -> {ok,Fd} = file:open(File,[read,read_ahead,raw,binary]), Fd.close(Fd) -> erase(chunk), file:close(Fd).pos_bof(Fd,Pos) -> reset_chunk(), file:position(Fd,{bof,Pos}). get_chunk(Fd) -> case erase(chunk) of undefined -> case read(Fd) of eof -> put_pos(Fd), eof; Other -> Other end; Bin -> {ok,Bin} end.read(Fd) -> file:read(Fd,?chunk_size).put_chunk(Fd,Bin) -> {ok,Pos0} = file:position(Fd,cur), Pos = Pos0 - size(Bin), put(chunk,Bin), put(pos,Pos).put_pos(Fd) -> {ok,Pos} = file:position(Fd,cur), put(pos,Pos). reset_chunk() -> erase(chunk), erase(pos).line_head(Fd) -> case get_chunk(Fd) of {ok,Bin} -> line_head(Fd,Bin,[],0); eof -> {eof,[]} end.line_head(Fd,Bin,Acc,?max_line_size) -> put_chunk(Fd,Bin), {part,lists:reverse(Acc)};line_head(Fd,<<$\n:8,Bin/binary>>,Acc,_N) -> put_chunk(Fd,Bin), lists:reverse(Acc);line_head(Fd,<<$::8,$\r:8,$\n:8,Bin/binary>>,Acc,_N) -> put_chunk(Fd,Bin), lists:reverse(Acc);line_head(Fd,<<$::8,Space:8,Bin/binary>>,Acc,_N) when Space=:=$ ;Space=:=$\n -> put_chunk(Fd,Bin), lists:reverse(Acc);line_head(Fd,Colon,Acc,N) when Colon == <<$::8>>; Colon == <<$::8,$\r:8>>-> case get_chunk(Fd) of {ok,Bin} -> line_head(Fd,<<$:,Bin/binary>>,Acc,N); eof -> {eof,lists:reverse(Acc)} end;line_head(Fd,<<$::8,Bin/binary>>,Acc,_N) -> put_chunk(Fd,Bin), lists:reverse(Acc);line_head(Fd,<<$\r:8,Bin/binary>>,Acc,N) -> line_head(Fd,Bin,Acc,N+1);line_head(Fd,<<Char:8,Bin/binary>>,Acc,N) -> line_head(Fd,Bin,[Char|Acc],N+1);line_head(Fd,<<>>,Acc,N) -> case get_chunk(Fd) of {ok,Bin} -> line_head(Fd,Bin,Acc,N); eof -> {eof,lists:reverse(Acc)} end.skip_rest_of_line(Fd) -> case get_chunk(Fd) of {ok,Bin} -> skip(Fd,Bin); eof -> ok end.skip(Fd,<<$\n:8,Bin/binary>>) -> put_chunk(Fd,Bin), ok;skip(Fd,<<_Char:8,Bin/binary>>) -> skip(Fd,Bin);skip(Fd,<<>>) -> case get_chunk(Fd) of {ok,Bin} -> skip(Fd,Bin); eof -> ok end.val(Fd) -> case get_rest_of_line(Fd) of {eof,[]} -> "-1"; [] -> "-1"; {eof,Val} -> Val; Val -> Val end.get_rest_of_line(Fd) -> case get_chunk(Fd) of {ok,Bin} -> get_rest_of_line_1(Fd, Bin, 0, []); eof -> {eof,[]} end.get_rest_of_line_1(Fd, Bin0, I, Acc) -> case Bin0 of <<_:I/binary,$\n:8,Bin/binary>> -> put_chunk(Fd, Bin), lists:reverse(Acc); <<_:I/binary,$\r:8,_/binary>> -> get_rest_of_line_1(Fd, Bin0, I+1, Acc); <<_:I/binary,Char:8,_/binary>> -> get_rest_of_line_1(Fd, Bin0, I+1, [Char|Acc]); <<_:I/binary>> -> case get_chunk(Fd) of {ok,Bin} -> get_rest_of_line_1(Fd, Bin, 0, Acc); eof -> {eof,lists:reverse(Acc)} end end.count_rest_of_line(Fd) -> case get_chunk(Fd) of {ok,Bin} -> count_rest_of_line(Fd,Bin,0); eof -> {eof,0} end.count_rest_of_line(Fd,<<$\n:8,Bin/binary>>,N) -> put_chunk(Fd,Bin), N;count_rest_of_line(Fd,<<$\r:8,Bin/binary>>,N) ->
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?