%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1998-2009. All Rights Reserved. %% %% 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 online 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. %% %% %CopyrightEnd% %% -module(seq_trace). -define(SEQ_TRACE_SEND, 1). %(1 << 0) -define(SEQ_TRACE_RECEIVE, 2). %(1 << 1) -define(SEQ_TRACE_PRINT, 4). %(1 << 2) -define(SEQ_TRACE_TIMESTAMP, 8). %(1 << 3) -export([set_token/1, set_token/2, get_token/0, get_token/1, print/1, print/2, reset_trace/0, set_system_tracer/1, get_system_tracer/0]). %%--------------------------------------------------------------------------- -type flag() :: 'send' | 'receive' | 'print' | 'timestamp'. -type component() :: 'label' | 'serial' | flag(). -type value() :: non_neg_integer() | {non_neg_integer(), non_neg_integer()} | boolean(). -type token_pair() :: {component(), value()}. %%--------------------------------------------------------------------------- -type token() :: [] | {integer(), boolean(), _, _, _}. -spec set_token(token()) -> token() | 'ok'. set_token([]) -> erlang:seq_trace(sequential_trace_token,[]); set_token({Flags,Label,Serial,_From,Lastcnt}) -> F = decode_flags(Flags), set_token2([{label,Label},{serial,{Lastcnt, Serial}} | F]). %% We limit the label type to always be a small integer because erl_interface %% expects that, the BIF can however "unofficially" handle atoms as well, and %% atoms can be used if only Erlang nodes are involved -spec set_token(component(), value()) -> token_pair(). set_token(Type, Val) -> erlang:seq_trace(Type, Val). -spec get_token() -> term(). get_token() -> element(2,process_info(self(),sequential_trace_token)). -spec get_token(component()) -> token_pair(). get_token(Type) -> erlang:seq_trace_info(Type). -spec print(term()) -> 'ok'. print(Term) -> erlang:seq_trace_print(Term), ok. -spec print(integer(), term()) -> 'ok'. print(Label, Term) when is_atom(Label) -> erlang:error(badarg, [Label, Term]); print(Label, Term) -> erlang:seq_trace_print(Label, Term), ok. -spec reset_trace() -> 'true'. reset_trace() -> erlang:system_flag(1, 0). %% reset_trace(Pid) -> % this might be a useful function too -type tracer() :: pid() | port() | 'false'. -spec set_system_tracer(tracer()) -> tracer(). set_system_tracer(Pid) -> erlang:system_flag(sequential_tracer, Pid). -spec get_system_tracer() -> tracer(). get_system_tracer() -> element(2, erlang:system_info(sequential_tracer)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% internal help functions %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_token2([{Type,Val}|T]) -> erlang:seq_trace(Type, Val), set_token2(T); set_token2([]) -> ok. decode_flags(Flags) -> Print = (Flags band ?SEQ_TRACE_PRINT) > 0, Send = (Flags band ?SEQ_TRACE_SEND) > 0, Rec = (Flags band ?SEQ_TRACE_RECEIVE) > 0, Ts = (Flags band ?SEQ_TRACE_TIMESTAMP) > 0, [{print,Print},{send,Send},{'receive',Rec},{timestamp,Ts}].