aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src')
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl16
-rw-r--r--lib/inets/src/http_server/mod_get.erl16
-rw-r--r--lib/inets/src/inets_app/Makefile3
-rw-r--r--lib/inets/src/inets_app/inets.app.src5
-rw-r--r--lib/inets/src/inets_app/inets.appup.src28
-rw-r--r--lib/inets/src/inets_app/inets.erl267
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl6
-rw-r--r--lib/inets/src/inets_app/inets_trace.erl357
8 files changed, 417 insertions, 281 deletions
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index bfe9b14ef6..714fd6f16d 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -852,13 +852,14 @@ connect(SocketType, ToAddress,
inet6fb4 ->
Opts3 = [inet6 | Opts2],
case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
- {error, _Reason} = Error ->
+ {error, Reason6} ->
Opts4 = [inet | Opts2],
case http_transport:connect(SocketType,
ToAddress, Opts4, Timeout) of
- {error, _} ->
- %% Reply with the "original" error
- Error;
+ {error, Reason4} ->
+ {error, {failed_connect,
+ [{inet6, Opts3, Reason6},
+ {inet, Opts4, Reason4}]}};
OK ->
OK
end;
@@ -867,7 +868,12 @@ connect(SocketType, ToAddress,
end;
_ ->
Opts3 = [IpFamily | Opts2],
- http_transport:connect(SocketType, ToAddress, Opts3, Timeout)
+ case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
+ {error, Reason} ->
+ {error, {failed_connect, [{IpFamily, Opts3, Reason}]}};
+ Else ->
+ Else
+ end
end.
connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
diff --git a/lib/inets/src/http_server/mod_get.erl b/lib/inets/src/http_server/mod_get.erl
index 5cb30e3d97..c58d1f3508 100644
--- a/lib/inets/src/http_server/mod_get.erl
+++ b/lib/inets/src/http_server/mod_get.erl
@@ -18,9 +18,16 @@
%%
%%
-module(mod_get).
+
-export([do/1]).
+
-include("httpd.hrl").
-include("httpd_internal.hrl").
+-include("inets_internal.hrl").
+
+-define(VMODULE,"GET").
+
+
%% do
do(Info) ->
@@ -84,15 +91,16 @@ send_response(_Socket, _SocketType, Path, Info)->
file:close(FileDescriptor),
{proceed,[{response,{already_sent,200,
FileInfo#file_info.size}},
- {mime_type,MimeType}|Info#mod.data]};
+ {mime_type,MimeType} | Info#mod.data]};
{error, Reason} ->
+ ?hdrt("send_response -> failed open file",
+ [{path, Path}, {reason, Reason}]),
Status = httpd_file:handle_error(Reason, "open", Info, Path),
- {proceed,
- [{status, Status}| Info#mod.data]}
+ {proceed, [{status, Status} | Info#mod.data]}
end.
%% send
-
+
send(#mod{socket = Socket, socket_type = SocketType} = Info,
StatusCode, Headers, FileDescriptor) ->
?DEBUG("send -> send header",[]),
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index d99e33b4ea..6da6a1d79f 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -46,7 +46,8 @@ MODULES = \
inets_service \
inets_app \
inets_sup \
- inets_regexp
+ inets_regexp \
+ inets_trace
INTERNAL_HRL_FILES = inets_internal.hrl
EXTERNAL_HRL_FILES = ../../include/httpd.hrl \
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index 1db7ed2c30..4aea2ef3d7 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -18,14 +18,15 @@
%%
{application,inets,
- [{description,"INETS CXC 138 49"},
- {vsn,"%VSN%"},
+ [{description, "INETS CXC 138 49"},
+ {vsn, "%VSN%"},
{modules,[
inets,
inets_sup,
inets_app,
inets_service,
inets_regexp,
+ inets_trace,
%% FTP
ftp,
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 9d7b1e6c93..1be5a958ce 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,15 +18,21 @@
{"%VSN%",
[
- {"5.8.1",
+ {"5.8.1",
[
{load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_response, soft_purge, soft_purge, []},
- {load_module, httpd_script_env, soft_purge, soft_purge, []}
+ {load_module, httpd_script_env, soft_purge, soft_purge, []},
+
+ {load_module, inets, soft_purge, soft_purge, [inets_trace]},
+ {update, httpc_handler, soft, soft_purge, soft_purge, []},
+ {add_module, inets_trace}
]
},
{"5.8",
[
+ {load_module, inets, soft_purge, soft_purge, [inets_trace]},
+
{load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_response, soft_purge, soft_purge, []},
{load_module, httpd_script_env, soft_purge, soft_purge, []},
@@ -35,25 +41,33 @@
{update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
soft_purge, soft_purge, []},
{update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [httpc_handler]}
+ soft_purge, soft_purge, [httpc_handler]},
+
+ {add_module, inets_trace}
]
},
{"5.7.2",
[
{restart_application, inets}
]
- }
+ }
],
[
{"5.8.1",
[
{load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_response, soft_purge, soft_purge, []},
- {load_module, httpd_script_env, soft_purge, soft_purge, []}
+ {load_module, httpd_script_env, soft_purge, soft_purge, []},
+
+ {load_module, inets, soft_purge, soft_purge, []},
+ {update, httpc_handler, soft, soft_purge, soft_purge, []},
+ {remove, {inets_trace, soft_purge, brutal_purge}}
]
},
{"5.8",
[
+ {load_module, inets, soft_purge, soft_purge, []},
+
{load_module, httpd_conf, soft_purge, soft_purge, []},
{load_module, httpd_response, soft_purge, soft_purge, []},
{load_module, httpd_script_env, soft_purge, soft_purge, []},
@@ -62,7 +76,9 @@
{update, httpc_handler, {advanced, upgrade_from_pre_5_8_1},
soft_purge, soft_purge, []},
{update, httpc_manager, {advanced, upgrade_from_pre_5_8_1},
- soft_purge, soft_purge, [httpc_handler]}
+ soft_purge, soft_purge, [httpc_handler]},
+
+ {remove, {inets_trace, soft_purge, brutal_purge}}
]
},
{"5.7.2",
diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl
index 054468e445..8e79f8d456 100644
--- a/lib/inets/src/inets_app/inets.erl
+++ b/lib/inets/src/inets_app/inets.erl
@@ -28,7 +28,7 @@
stop/0, stop/2,
services/0, services_info/0,
service_names/0]).
--export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1,
+-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1,
report_event/4]).
-export([versions/0,
print_version_info/0, print_version_info/1]).
@@ -409,47 +409,8 @@ service_names() ->
%% Severity withing Limit) will be written to stdout using io:format.
%%
%%-----------------------------------------------------------------
-enable_trace(Level, Dest) ->
- enable_trace(Level, Dest, all).
-
-enable_trace(Level, Dest, Service) ->
- case valid_trace_service(Service) of
- true ->
- enable_trace2(Level, Dest, Service);
- false ->
- {error, {invalid_service, Service}}
- end.
-
-enable_trace2(Level, File, Service)
- when is_list(File) ->
- case file:open(File, [write]) of
- {ok, Fd} ->
- HandleSpec = {fun handle_trace/2, {Service, Fd}},
- do_enable_trace(Level, process, HandleSpec);
- Err ->
- Err
- end;
-enable_trace2(Level, Port, _) when is_integer(Port) ->
- do_enable_trace(Level, port, dbg:trace_port(ip, Port));
-enable_trace2(Level, io, Service) ->
- HandleSpec = {fun handle_trace/2, {Service, standard_io}},
- do_enable_trace(Level, process, HandleSpec);
-enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) ->
- do_enable_trace(Level, process, HandleSpec).
-
-do_enable_trace(Level, Type, HandleSpec) ->
- case dbg:tracer(Type, HandleSpec) of
- {ok, _} ->
- set_trace(Level),
- ok;
- Error ->
- Error
- end.
-
-valid_trace_service(all) ->
- true;
-valid_trace_service(Service) ->
- lists:member(Service, [httpc, httpd, ftpc, tftp]).
+enable_trace(Level, Dest) -> inets_trace:enable(Level, Dest).
+enable_trace(Level, Dest, Service) -> inets_trace:enable(Level, Dest, Service).
%%-----------------------------------------------------------------
@@ -458,12 +419,7 @@ valid_trace_service(Service) ->
%% Description:
%% This function is used to stop tracing.
%%-----------------------------------------------------------------
-disable_trace() ->
- %% This is to make handle_trace/2 close the output file (if the
- %% event gets there before dbg closes)
- inets:report_event(100, "stop trace", stop_trace, [stop_trace]),
- dbg:stop().
-
+disable_trace() -> inets_trace:disable().
%%-----------------------------------------------------------------
@@ -476,60 +432,7 @@ disable_trace() ->
%% This function is used to change the trace level when tracing has
%% already been started.
%%-----------------------------------------------------------------
-set_trace(Level) ->
- set_trace(Level, all).
-
-set_trace(Level, Service) ->
- Pat = make_pattern(?MODULE, Service, Level),
- change_pattern(Pat).
-
-make_pattern(Mod, Service, Level)
- when is_atom(Mod) andalso is_atom(Service) ->
- case Level of
- min ->
- {Mod, Service, []};
- max ->
- Head = ['$1', '_', '_', '_'],
- Body = [],
- Cond = [],
- {Mod, Service, [{Head, Cond, Body}]};
- DetailLevel when is_integer(DetailLevel) ->
- Head = ['$1', '_', '_', '_'],
- Body = [],
- Cond = [{ '=<', '$1', DetailLevel}],
- {Mod, Service, [{Head, Cond, Body}]};
- _ ->
- exit({bad_level, Level})
- end.
-
-change_pattern({Mod, Service, Pattern})
- when is_atom(Mod) andalso is_atom(Service) ->
- MFA = {Mod, report_event, 4},
- case Pattern of
- [] ->
- try
- error_to_exit(ctp, dbg:ctp(MFA)),
- error_to_exit(p, dbg:p(all, clear))
- catch
- exit:{Where, Reason} ->
- {error, {Where, Reason}}
- end;
- List when is_list(List) ->
- try
- error_to_exit(ctp, dbg:ctp(MFA)),
- error_to_exit(tp, dbg:tp(MFA, Pattern)),
- error_to_exit(p, dbg:p(all, [call, timestamp]))
- catch
- exit:{Where, Reason} ->
- {error, {Where, Reason}}
- end
- end,
- ok.
-
-error_to_exit(_Where, {ok, _} = OK) ->
- OK;
-error_to_exit(Where, {error, Reason}) ->
- exit({Where, Reason}).
+set_trace(Level) -> inets_trace:set_level(Level).
%%-----------------------------------------------------------------
@@ -546,164 +449,8 @@ error_to_exit(Where, {error, Reason}) ->
%% put trace on this function.
%%-----------------------------------------------------------------
-report_event(Severity, Label, Service, Content)
- when (is_integer(Severity) andalso
- (Severity >= 0) andalso (100 >= Severity)) andalso
- is_list(Label) andalso
- is_atom(Service) andalso
- is_list(Content) ->
- hopefully_traced.
-
-
-%% ----------------------------------------------------------------------
-%% handle_trace(Event, Fd) -> Verbosity
-%%
-%% Parameters:
-%% Event -> The trace event (only megaco 'trace_ts' events are printed)
-%% Fd -> standard_io | file_descriptor() | trace_port()
-%%
-%% Description:
-%% This function is used to "receive" and print the trace events.
-%% Events are printed if:
-%% - Verbosity is max
-%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
-%% Events are not printed if:
-%% - Verbosity is min
-%% - Severity is > Verbosity
-%%-----------------------------------------------------------------
-
-handle_trace(_, closed_file = Fd) ->
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- {_, standard_io} = Fd) ->
- (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- standard_io = Fd) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- Fd;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- {_Service, Fd}) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- (catch file:close(Fd)),
- closed_file;
-handle_trace({trace_ts, _Who, call,
- {?MODULE, report_event,
- [_Sev, "stop trace", stop_trace, [stop_trace]]},
- Timestamp},
- Fd) ->
- (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
- (catch file:close(Fd)),
- closed_file;
-handle_trace({trace_ts, Who, call,
- {?MODULE, report_event,
- [Sev, Label, Service, Content]}, Timestamp},
- Fd) ->
- (catch print_inets_trace(Fd, Sev, Timestamp, Who,
- Label, Service, Content)),
- Fd;
-handle_trace(Event, Fd) ->
- (catch print_trace(Fd, Event)),
- Fd.
-
-
-print_inets_trace({Service, Fd},
- Sev, Timestamp, Who, Label, Service, Content) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content);
-print_inets_trace({ServiceA, Fd},
- Sev, Timestamp, Who, Label, ServiceB, Content)
- when (ServiceA =:= all) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content);
-print_inets_trace({ServiceA, _Fd},
- _Sev, _Timestamp, _Who, _Label, ServiceB, _Content)
- when ServiceA =/= ServiceB ->
- ok;
-print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
- do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content).
-
-do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
- Ts = format_timestamp(Timestamp),
- io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s "
- "~n Content: ~p"
- "~n",
- [Service, Sev, Who, Ts, Label, Content]).
-
-print_trace({_, Fd}, Event) ->
- do_print_trace(Fd, Event);
-print_trace(Fd, Event) ->
- do_print_trace(Fd, Event).
-
-do_print_trace(Fd, {trace, Who, What, Where}) ->
- io:format(Fd, "[trace]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Who, What, Where]);
-
-do_print_trace(Fd, {trace, Who, What, Where, Extra}) ->
- io:format(Fd, "[trace]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n Extra: ~p"
- "~n", [Who, What, Where, Extra]);
-
-do_print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[trace ~s]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Ts, Who, What, Where]);
-
-do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[trace ~s]"
- "~n Who: ~p"
- "~n What: ~p"
- "~n Where: ~p"
- "~n Extra: ~p"
- "~n", [Ts, Who, What, Where, Extra]);
-
-do_print_trace(Fd, {seq_trace, What, Where}) ->
- io:format(Fd, "[seq trace]"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [What, Where]);
-
-do_print_trace(Fd, {seq_trace, What, Where, When}) ->
- Ts = format_timestamp(When),
- io:format(Fd, "[seq trace ~s]"
- "~n What: ~p"
- "~n Where: ~p"
- "~n", [Ts, What, Where]);
-
-do_print_trace(Fd, {drop, Num}) ->
- io:format(Fd, "[drop trace] ~p~n", [Num]);
-
-do_print_trace(Fd, Trace) ->
- io:format(Fd, "[trace] "
- "~n ~p"
- "~n", [Trace]).
-
-
-format_timestamp({_N1, _N2, N3} = Now) ->
- {Date, Time} = calendar:now_to_datetime(Now),
- {YYYY,MM,DD} = Date,
- {Hour,Min,Sec} = Time,
- FormatDate =
- io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
- [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
- lists:flatten(FormatDate).
+report_event(Severity, Label, Service, Content) ->
+ inets_trace:report_event(Severity, Label, Service, Content).
%%--------------------------------------------------------------------
diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl
index 55c3669e4a..e56af3b59d 100644
--- a/lib/inets/src/inets_app/inets_internal.hrl
+++ b/lib/inets/src/inets_app/inets_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. 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
@@ -24,8 +24,8 @@
%% Various trace macros
-define(report(Severity, Label, Service, Content),
- inets:report_event(Severity, Label, Service,
- [{module, ?MODULE}, {line, ?LINE} | Content])).
+ inets_trace:report_event(Severity, Label, Service,
+ [{module, ?MODULE}, {line, ?LINE} | Content])).
-define(report_important(Label, Service, Content),
?report(20, Label, Service, Content)).
-define(report_verbose(Label, Service, Content),
diff --git a/lib/inets/src/inets_app/inets_trace.erl b/lib/inets/src/inets_app/inets_trace.erl
new file mode 100644
index 0000000000..8911f65897
--- /dev/null
+++ b/lib/inets/src/inets_app/inets_trace.erl
@@ -0,0 +1,357 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2012. 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%
+%%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Module for debug trace functions of the inets application
+%%----------------------------------------------------------------------
+
+-module(inets_trace).
+
+%% API
+-export([enable/2, enable/3,
+ disable/0,
+ set_level/1, set_level/2,
+ report_event/4]).
+
+
+%%====================================================================
+%% API
+%%====================================================================
+
+%%-----------------------------------------------------------------
+%% enable(Level, Destination) -> void()
+%% enable(Level, Destination, Service) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%% Destination -> File | Port | io | HandlerSpec
+%% Service -> httpc | httpd | ftpc | tftp | all
+%% File -> string()
+%% Port -> integer()
+%% Verbosity -> true | false
+%% HandlerSpec = {function(), Data}
+%% Data = term()
+%%
+%% Description:
+%% This function is used to start tracing at level Level and send
+%% the result either to the file File, the port Port or to a
+%% trace handler.
+%% Note that it starts a tracer server.
+%% When Destination is the atom io (or the tuple {io, Verbosity}),
+%% all (printable) inets trace events (trace_ts events which has
+%% Severity withing Limit) will be written to stdout using io:format.
+%%
+%%-----------------------------------------------------------------
+enable(Level, Dest) ->
+ enable(Level, Dest, all).
+
+enable(Level, Dest, Service) ->
+ case valid_trace_service(Service) of
+ true ->
+ enable2(Level, Dest, Service);
+ false ->
+ {error, {invalid_service, Service}}
+ end.
+
+enable2(Level, File, Service)
+ when is_list(File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ HandleSpec = {fun handle_trace/2, {Service, Fd}},
+ do_enable(Level, process, HandleSpec);
+ Err ->
+ Err
+ end;
+enable2(Level, Port, _) when is_integer(Port) ->
+ do_enable(Level, port, dbg:trace_port(ip, Port));
+enable2(Level, io, Service) ->
+ HandleSpec = {fun handle_trace/2, {Service, standard_io}},
+ do_enable(Level, process, HandleSpec);
+enable2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) ->
+ do_enable(Level, process, HandleSpec).
+
+do_enable(Level, Type, HandleSpec) ->
+ case dbg:tracer(Type, HandleSpec) of
+ {ok, _} ->
+ set_level(Level),
+ ok;
+ Error ->
+ Error
+ end.
+
+valid_trace_service(all) ->
+ true;
+valid_trace_service(Service) ->
+ lists:member(Service, [httpc, httpd, ftpc, tftp]).
+
+
+%%-----------------------------------------------------------------
+%% disable() -> void()
+%%
+%% Description:
+%% This function is used to stop tracing.
+%%-----------------------------------------------------------------
+
+disable() ->
+ %% This is to make handle_trace/2 close the output file (if the
+ %% event gets there before dbg closes)
+ inets_trace:report_event(100, "stop trace", stop_trace, [stop_trace]),
+ dbg:stop().
+
+
+
+%%-----------------------------------------------------------------
+%% set_level(Level) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%%
+%% Description:
+%% This function is used to change the trace level when tracing has
+%% already been started.
+%%-----------------------------------------------------------------
+set_level(Level) ->
+ set_level(Level, all).
+
+set_level(Level, Service) ->
+ Pat = make_pattern(?MODULE, Service, Level),
+ change_pattern(Pat).
+
+make_pattern(Mod, Service, Level)
+ when is_atom(Mod) andalso is_atom(Service) ->
+ case Level of
+ min ->
+ {Mod, Service, []};
+ max ->
+ Head = ['$1', '_', '_', '_'],
+ Body = [],
+ Cond = [],
+ {Mod, Service, [{Head, Cond, Body}]};
+ DetailLevel when is_integer(DetailLevel) ->
+ Head = ['$1', '_', '_', '_'],
+ Body = [],
+ Cond = [{ '=<', '$1', DetailLevel}],
+ {Mod, Service, [{Head, Cond, Body}]};
+ _ ->
+ exit({bad_level, Level})
+ end.
+
+change_pattern({Mod, Service, Pattern})
+ when is_atom(Mod) andalso is_atom(Service) ->
+ MFA = {Mod, report_event, 4},
+ case Pattern of
+ [] ->
+ try
+ error_to_exit(ctp, dbg:ctp(MFA)),
+ error_to_exit(p, dbg:p(all, clear))
+ catch
+ exit:{Where, Reason} ->
+ {error, {Where, Reason}}
+ end;
+ List when is_list(List) ->
+ try
+ error_to_exit(ctp, dbg:ctp(MFA)),
+ error_to_exit(tp, dbg:tp(MFA, Pattern)),
+ error_to_exit(p, dbg:p(all, [call, timestamp]))
+ catch
+ exit:{Where, Reason} ->
+ {error, {Where, Reason}}
+ end
+ end.
+
+error_to_exit(_Where, {ok, _} = OK) ->
+ OK;
+error_to_exit(Where, {error, Reason}) ->
+ exit({Where, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% report_event(Severity, Label, Service, Content)
+%%
+%% Parameters:
+%% Severity -> 0 =< integer() =< 100
+%% Label -> string()
+%% Service -> httpd | httpc | ftp | tftp
+%% Content -> [{tag, term()}]
+%%
+%% Description:
+%% This function is used to generate trace events, that is,
+%% put trace on this function.
+%%-----------------------------------------------------------------
+
+report_event(Severity, Label, Service, Content)
+ when (is_integer(Severity) andalso
+ (Severity >= 0) andalso (100 >= Severity)) andalso
+ is_list(Label) andalso
+ is_atom(Service) andalso
+ is_list(Content) ->
+ hopefully_traced.
+
+
+%% ----------------------------------------------------------------------
+%% handle_trace(Event, Fd) -> Verbosity
+%%
+%% Parameters:
+%% Event -> The trace event
+%% Fd -> standard_io | file_descriptor() | trace_port()
+%%
+%% Description:
+%% This function is used to "receive" and pretty print the trace events.
+%% Events are printed if:
+%% - Verbosity is max
+%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
+%% Events are not printed if:
+%% - Verbosity is min
+%% - Severity is > Verbosity
+%%-----------------------------------------------------------------
+
+handle_trace(_, closed_file = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ {_, standard_io} = Fd) ->
+ (catch io:format(standard_io, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ standard_io = Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ {_Service, Fd}) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [_Sev, "stop trace", stop_trace, [stop_trace]]},
+ Timestamp},
+ Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, Who, call,
+ {?MODULE, report_event,
+ [Sev, Label, Service, Content]}, Timestamp},
+ Fd) ->
+ (catch print_inets_trace(Fd, Sev, Timestamp, Who,
+ Label, Service, Content)),
+ Fd;
+handle_trace(Event, Fd) ->
+ (catch print_trace(Fd, Event)),
+ Fd.
+
+
+print_inets_trace({Service, Fd},
+ Sev, Timestamp, Who, Label, Service, Content) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content);
+print_inets_trace({ServiceA, Fd},
+ Sev, Timestamp, Who, Label, ServiceB, Content)
+ when (ServiceA =:= all) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content);
+print_inets_trace({ServiceA, _Fd},
+ _Sev, _Timestamp, _Who, _Label, ServiceB, _Content)
+ when ServiceA =/= ServiceB ->
+ ok;
+print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
+ do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content).
+
+do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) ->
+ Ts = format_timestamp(Timestamp),
+ io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s "
+ "~n Content: ~p"
+ "~n",
+ [Service, Sev, Who, Ts, Label, Content]).
+
+print_trace({_, Fd}, Event) ->
+ do_print_trace(Fd, Event);
+print_trace(Fd, Event) ->
+ do_print_trace(Fd, Event).
+
+do_print_trace(Fd, {trace, Who, What, Where}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Who, What, Where]);
+
+do_print_trace(Fd, {trace, Who, What, Where, Extra}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Who, What, Where, Extra]);
+
+do_print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, Who, What, Where]);
+
+do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Ts, Who, What, Where, Extra]);
+
+do_print_trace(Fd, {seq_trace, What, Where}) ->
+ io:format(Fd, "[seq trace]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [What, Where]);
+
+do_print_trace(Fd, {seq_trace, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[seq trace ~s]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, What, Where]);
+
+do_print_trace(Fd, {drop, Num}) ->
+ io:format(Fd, "[drop trace] ~p~n", [Num]);
+
+do_print_trace(Fd, Trace) ->
+ io:format(Fd, "[trace] "
+ "~n ~p"
+ "~n", [Trace]).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+