inviso_lfm_tpfreader.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 385 行 · 第 1/2 页

ERL
385
字号
%% ``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$
%%
%% Author: Lennart 謍man, lennart.ohman@st.se

%%
%% INVISO LogFileMerger TracePort File READER.
%%
%% This module implements a reader process capable of reading traceport files
%% and feeding them according to the logfile merger process message protocoll
%% to the logfile merger process.
%% This module can also serve as example for writing file readers for other
%% file formats.
%%
%% A reader process must:
%%   Support the reader-receiver protocoll.
%%     receive next_entry message: {get_next_entry,ReceiverPid}
%%     recieve stop message should the receiver wish to quit: {stop,ReceiverPid}.
%%     send next_entry message, either with entry or fault-code.
%%       next_entry message contains:{next_entry,self(),PidMappings,Timestamp,Term}
%%                                   {next_entry,self(),Error}
%%     recognize receiver termination (EXIT-signal).
%%  Understand logfile structure, both filename structure and content.
%%  Understand content (log-entry) details to extract the entry and entry
%%    components as timestamp and originating pid (to make pid-mappings).
%%  Understand any trace information files (ti).
%%
%%  The logfile structure written by inviso_rt_meta is:
%%    {Pid,Alias,Op,TimeStamp} where:
%%      Pid=pid(), if Alias==unalias: pid()|other_than_pid()
%%      Op=alias|unalias,
%%      TimeStamp=now()
%% -----------------------------------------------------------------------------
-module(inviso_lfm_tpfreader).

-export([init/2]).
%% -----------------------------------------------------------------------------

-export([handle_logfile_sort_wrapset/1]).   % Exported as a service to other readers.
%% -----------------------------------------------------------------------------

%% init(RecPid,FileStruct)=N/A
%%   RecPid=pid(), the process id of the log file merger.
%%   FileStruct=LogFiles | [LogFiles,...]
%%     LogFiles=[{trace_log,[File,...]} [,{ti_log,[File]}] ]
%%       File=string()
%% Spawn on this function to start a reader process for trace-port generated
%% logfiles, possibly with inviso-generated ti-files.
init(RecPid,LogFiles=[Tuple|_]) when tuple(Tuple) -> % Only one LogFiles.
    init(RecPid,[LogFiles]);
init(RecPid,FileStruct) when list(FileStruct) ->
    logfiles_loop(RecPid,FileStruct).
%% -----------------------------------------------------------------------------

logfiles_loop(RecPid,[LogFiles|Rest]) ->
    {TIalias,TIunalias}=handle_ti_file(LogFiles),% If there is a ti-file, read it.
    Files=handle_logfiles(LogFiles),        % Returns a sorted list of logfiles.
    case open_next_file(Files) of
	{ok,FileName,FD,NewFiles} ->
	    case loop(RecPid,FileName,NewFiles,TIalias,TIunalias,FD) of
		next ->
		    logfiles_loop(RecPid,Rest);
		stop ->
		    true                    % Terminate normally.
	    end;
	done ->                             % Hmm, already out of files.
	    true;                           % Then lets terminate normally.
	{error,Reason} ->                   % Couldn't even open the first file.
	    exit(Reason)
    end;
logfiles_loop(_RecPid,[]) ->                % No more files in LogFiles.
    true.                                   % Terminate normally.

%% This workloop reads an entry from the input file upon request from the merger
%% process and sends it back to the merger process (Parent). If the file ends
%% there are more files to open and read in Files, the next file will be opened. 
loop(RecPid,FileName,Files,TIalias,TIunalias,FD) ->
    receive
	{get_next_entry,RecPid} ->           % The receiver request the next entry.
	    case fetch_next(FileName,FD,Files) of
		{ok,Term,NewCurrFile,NewFiles,NewFD} ->
		    TS=find_timestamp_in_term(Term),
		    PidMappings=make_pid_mappings(Term,TIalias,TIunalias,TS),
		    RecPid ! {next_entry,self(),PidMappings,TS,Term},
		    loop(RecPid,NewCurrFile,NewFiles,TIalias,TIunalias,NewFD);
		{error,Reason} ->            % Not a properly formatted entry.
		    RecPid ! {next_entry,self(),{error,Reason}},
		    loop(RecPid,FileName,Files,TIalias,TIunalias,FD);
		done ->                     % No more files to read in this LogFiles.
		    next                    % Are there more Files in FileStruct?
	    end;
	{stop,RecPid} ->                    % The receiver process is done.
	    file:close(FD),                 % Close file and terminate normally.
	    stop
    end.
%% -----------------------------------------------------------------------------

%% Function which reads the next trace-entry from the file handled by FD, or if
%% that file reaches EOF opens the next file in Files. Files must be sorted in
%% the correct order.
%% Returns {ok,Term,NewFileName,NewFiles,NewFD}, {error,Reason} or 'done'.
fetch_next(FileName,FD,Files) ->
    case read_traceport_file(FileName,FD) of
	{ok,Term} ->                        % There were more terms in the file.
	    {ok,Term,FileName,Files,FD};    % No changes necessary then.
	eof ->                              % This file is empty, try next file!
	    file:close(FD),
	    case open_next_file(Files) of
		{ok,NewFileName,NewFD,NewFiles} -> % A new file has been opened.
		    fetch_next(NewFileName,NewFD,NewFiles); % Try again.
		done ->                     % No more files.
		    done;
		{error,Reason} ->           % Problems opening files.
		    {error,Reason}
	    end;
	{error,Reason} ->                   % Problems reading the file.
	    {error,Reason}
    end.

read_traceport_file(FileName,FD) ->
    case file:read(FD,5) of                 % Trace-port file entries start with 5 bytes.
	{ok,<<0,Size:32>>} ->               % Each entry in a traceport file begins.
	    case file:read(FD,Size) of
		{ok,Bin} when binary(Bin),size(Bin)=:=Size ->
		    try binary_to_term(Bin) of
			Term ->             % Bin was a properly formatted term!
			    {ok,Term}
		    catch
			error:_Reason ->    % Not a properly formatted term!
			    {error,{binary_to_term,[FileName,Bin]}}
		    end;
		{ok,Bin} ->                 % Incorrect length.
		    {error,{faulty_length,[FileName,Size,Bin]}};
		eof ->                      % This is premature end of file!
		    {error,{premature_eof,FileName}}
	    end;
	{ok,<<1,DroppedMsgs:32>>} ->
	    {ok,{drop,DroppedMsgs}};
	{ok,JunkBin} ->                     % Don't understand, report it as error.
	    {error,{junk,[FileName,JunkBin]}};
	eof ->                              % A correct end of file!
	    eof
    end.

%% Help function which opens a file in raw binary mode and returns
%% {ok,FileName,FD,Rest} or {error,Reason}.
open_next_file([]) ->                       % There are no more files to open.
    done;
open_next_file([FileName|Rest]) ->
    case file:open(FileName,[read,raw,binary]) of
	{ok,FD} ->
	    {ok,FileName,FD,Rest};
	{error,Reason} ->
	    {error,{open,[FileName,Reason]}}
    end.
%% ------------------------------------------------------------------------------

%% ==============================================================================
%% Help functions.
%% ==============================================================================


%% Help function which extract the originating process id from the log entry
%% Term and returns a list of all associations to the PID found in TIalias.
make_pid_mappings(_,void,_,_) ->            % Trace Information is not used.
    [];                                     % Simply no pid mappings then!
make_pid_mappings(Term,TIalias,TIunalias,TS)
  when element(1,Term)==trace;element(1,Term)==trace_ts ->
    Pid=element(2,Term),                    % The pid.
    TempAliases=find_aliases(ets:lookup(TIalias,Pid),TS),
    remove_expired_aliases(TempAliases,TIalias,TIunalias,TS),
    lists:map(fun({_,_,Alias})->Alias end,
	      find_aliases(ets:lookup(TIalias,Pid),TS));
make_pid_mappings(_Term,_TIalias,_TIunalias,_TS) -> % Don't understand Term.
    [].                                     % Simply no translations then!

%% Help function traversing a list of ets-alias-table entries and returning a
%% list of those old enough to have happend before TS.
find_aliases(List,TS) ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?