mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-07 23:32:42 +01:00
git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2229 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
221 lines
8.3 KiB
Plaintext
221 lines
8.3 KiB
Plaintext
[[Property:title|Tracing]]
|
|
[[Property:weight|8]]
|
|
[[Property:uuid|ecb9dd1e-52a9-25c4-b27b-4b5ec806b115]]
|
|
=Introduction=
|
|
|
|
The '''tracing facility''' allows you to see a structured log of the flow of control through your system, feature by feature. By default, execution traces are written to standard output.
|
|
|
|
|
|
{{note|The tracing facility is not supported on the Microsoft .NET platform.}}
|
|
|
|
|
|
=The "Trace" project setting=
|
|
|
|
You can make tracing usable for a particular cluster by setting the '''Trace''' setting to '''True''' in your project settings for a particular cluster.
|
|
|
|
To do this:
|
|
* Open the [[Group Options|Project Settings]] dialog.
|
|
* Under '''Clusters''' select the cluster you want to see traced.
|
|
* Set the value of '''Trace''' to '''True'''.
|
|
* Click '''Apply''' or '''OK'''.
|
|
* You must [[Generating executables|recompile]] your project for the changes to take effect.
|
|
|
|
This will cause a trace entry to be written to the console for any feature execution on a class in the cluster(s) you selected for tracing. To get a feel for this, look at the following trace outputs, built on the default Eiffel application ("Hello Eiffel World!).
|
|
|
|
First, here's what the "Hello Eiffel World!" output looks like without using the tracing facility.
|
|
|
|
|
|
[[Image:Tracing 01 off]]
|
|
|
|
|
|
Next, here's the output when the '''Trace''' project setting is set to '''True''' on the root cluster.
|
|
|
|
|
|
[[Image:Tracing 01 on]]
|
|
|
|
|
|
Last, here's the output when '''Trace''' is '''True''' for both the root cluster and EiffelBase.
|
|
|
|
|
|
[[Image:Tracing 01 with EiffelBase]]
|
|
|
|
|
|
=Dynamic control=
|
|
|
|
It is also possible to enable and disable the trace dynamically. To do this:
|
|
* Create an object of type [[ref:libraries/base/reference/tracing_setting_chart|TRACING_SETTING]] .
|
|
* Call [[ref:libraries/base/reference/tracing_setting_flatshort|enable_tracing]] on this object to start the trace.
|
|
* Call [[ref:libraries/base/reference/tracing_setting_flatshort|disable_tracing]] on this object to stop the trace.
|
|
|
|
{{tip|To enable tracing on only part of a system, disable tracing at the very beginning of the program, enable it just before the part of the code that should be traced, and then disable it again after this section. The code below illustrates this tip. }}
|
|
|
|
|
|
In the root feature:
|
|
|
|
<code>
|
|
local
|
|
ts: TRACING_SETTING
|
|
-- Other local variables if necessary.
|
|
do
|
|
create ts.make
|
|
ts.disable_tracing
|
|
-- Program execution continues.
|
|
...
|
|
|
|
-- Restore tracing before exiting for proper cleanup.
|
|
ts.enable_tracing
|
|
end
|
|
</code>
|
|
|
|
|
|
Then, in a feature in which tracing is desired:
|
|
|
|
<code>
|
|
local
|
|
ts: TRACING_SETTING
|
|
-- Other local variables if necessary.
|
|
do
|
|
create ts.make
|
|
ts.enable_tracing -- Enable trace
|
|
-- Section needing trace.
|
|
...
|
|
ts.disable_tracing -- Disable trace
|
|
end
|
|
</code>
|
|
|
|
{{warning| Enabling/disabling tracing as shown above has to be done within the same routine otherwise the computed depth would be inaccurate and this would cause some unpredictable results.}}
|
|
|
|
=Using a trace handler=
|
|
|
|
You can do more complex tracing tasks by using a trace handler. The deferred class <code>TRACE_HANDLER</code> contains a deferred feature <code>trace</code> which you can effect in a descendant of <code>TRACE_HANDLER</code>. Your effective version of <code>trace</code> will be called whenever a trace event occurs. <code>{TRACE_HANDLER}.trace</code> looks like this:
|
|
|
|
<code>
|
|
trace (a_type_id: INTEGER; a_c_class_name, a_c_feature_name: POINTER; a_depth: INTEGER; a_is_entering: BOOLEAN)
|
|
-- Trigger a trace operation from a feature represented by `a_c_feature_name' defined in
|
|
-- class `a_c_class_name' and applied to an object of type `a_type_id' at a call depth `a_depth'.
|
|
-- If `a_is_entering' we are entering the routine, otherwise we are exiting it.
|
|
require
|
|
a_type_id_non_negative: a_type_id >= 0
|
|
a_depth_non_negative: a_depth >= 0
|
|
deferred
|
|
end
|
|
</code>
|
|
|
|
You may notice in the specification for <code>trace</code> above that the arguments representing the class and feature names are of type <code>POINTER</code> (versus some variant of <code>STRING</code>).
|
|
|
|
To make this facility more approachable for common tasks, EiffelBase also contains another class, a deferred descendant of <code>TRACING_HANDLER</code>, called <code>STRING_TRACING_HANDLER</code> in which the <code>trace</code> feature's arguments for class and feature names are strings, and the argument for type is an instance of <code>TYPE</code> rather than an integer type id as in <code>TRACING_HANDLER</code>. <code>{STRING_TRACING_HANDLER}.trace</code> looks like this:
|
|
|
|
<code>
|
|
trace (a_type: TYPE [detachable ANY]; a_class_name, a_feature_name: detachable STRING; a_depth: INTEGER; a_is_entering: BOOLEAN)
|
|
-- Trigger a trace operation from a feature represented by `a_feature_name' defined in
|
|
-- class `a_class_name' and applied to an object of type `a_type' at a call depth `a_depth'.
|
|
-- If `a_is_entering' we are entering the routine, otherwise we are exiting it.
|
|
require
|
|
a_depth_non_negative: a_depth >= 0
|
|
deferred
|
|
end
|
|
</code>
|
|
|
|
Suppose we wanted to write trace long entries in a private log file for the entry and exit of a number of routines during the run of a simple application. We could create a descendant of <code>STRING_TRACING_HANDLER</code> that looks like this:
|
|
|
|
<code>
|
|
class
|
|
EXAMPLE_HANDLER
|
|
inherit
|
|
STRING_TRACING_HANDLER
|
|
|
|
feature
|
|
|
|
trace (a_type: TYPE [ANY]; a_class_name, a_feature_name: STRING_8; a_depth: INTEGER_32; a_is_entering: BOOLEAN)
|
|
-- <Precursor>
|
|
do
|
|
trace_log_file.put_string (create {STRING}.make_filled ('>', a_depth))
|
|
if a_is_entering then
|
|
trace_log_file.put_string (" Is entering " + "{" + a_class_name + "}." + a_feature_name + "%N")
|
|
else
|
|
trace_log_file.put_string (" Is leaving " + "{" + a_class_name + "}." + a_feature_name + "%N")
|
|
end
|
|
end
|
|
|
|
trace_log_file: PLAIN_TEXT_FILE
|
|
-- Log file
|
|
once
|
|
create Result.make_open_write ("my_log_file.txt")
|
|
end
|
|
|
|
close_log_file
|
|
-- Close log file
|
|
do
|
|
trace_log_file.close
|
|
end
|
|
end
|
|
</code>
|
|
|
|
In <code>EXAMPLE_HANDLER</code> the procedure <code>trace</code> is effected to write the desired information to the <code>log_file</code>.
|
|
|
|
Then we could use <code>EXAMPLE_HANDLER</code> in a class that might look like this:
|
|
|
|
<code>
|
|
class
|
|
APPLICATION
|
|
|
|
create
|
|
make
|
|
|
|
feature
|
|
|
|
make
|
|
-- Run application.
|
|
local
|
|
tracing_setting: TRACING_SETTING
|
|
tracing_handler: EXAMPLE_HANDLER
|
|
do
|
|
create tracing_setting
|
|
tracing_setting.enable_tracing
|
|
create tracing_handler
|
|
tracing_handler.activate
|
|
|
|
call_depth_one
|
|
|
|
tracing_handler.deactivate
|
|
tracing_handler.close_log_file
|
|
tracing_setting.disable_tracing
|
|
end
|
|
|
|
call_depth_one
|
|
-- Call depth one routine
|
|
do
|
|
call_depth_two
|
|
end
|
|
|
|
call_depth_two
|
|
-- Call depth two routine
|
|
do
|
|
call_depth_three
|
|
end
|
|
|
|
call_depth_three
|
|
-- Call depth three routine
|
|
do
|
|
|
|
end
|
|
end
|
|
</code>
|
|
|
|
In <code>{APPLICATION}.make</code>, the instances of <code>TRACING_SETTING</code> and <code>EXAMPLE_HANDLER</code> are created. Tracing is enabled and the handler is activated. After the section of interest, the handler is deactivated, the log file closed, and tracing disabled.
|
|
|
|
Now consider a system in which <code>{APPLICATION}.make</code> is the root, <code>APPLICATION</code> is the only class in the root cluster, and that the project setting '''Trace''' is true for the root cluster only. After running the system, the content of <code>my_log_file.txt</code> would be:
|
|
|
|
<code lang="text">
|
|
> Is entering {APPLICATION}.call_depth_one
|
|
>> Is entering {APPLICATION}.call_depth_two
|
|
>>> Is entering {APPLICATION}.call_depth_three
|
|
>>> Is leaving {APPLICATION}.call_depth_three
|
|
>> Is leaving {APPLICATION}.call_depth_two
|
|
> Is leaving {APPLICATION}.call_depth_one
|
|
</code>
|
|
|
|
|
|
|
|
|