When ::OPTIONS TRACE ?R (or similar with the interactive flag) is specified, all ROUTINEs and METHODs in a package have interactive tracing automatically switched on. This is very useful for debugging as adding one line switches tracing on everywhere but sometimes there might be a small number of ROUTINEs or METHODs (those called frequently and /or with known correct behaviour) for which this is not required or desired.
The global option can generally be overridden on a case by case basis by inserting CALL TRACE( '?') before the first instruction in a ROUTINE or METHOD, but it seems that in a METHOD that uses EXPOSE, the first instruction must be EXPOSE and interactive tracing will pause here before the earliest place the override code can be added and this limits the effectiveness of this method.
There is a workaround which is NOT to use the global option and instead add code to activate tracing to each ROUTINE or METHOD, and actually when the workaround is not available it does just add the requirement for an extra <enter> to the tracing process whenever the METHOD is called but it would be nice if this corner case could be addressed.</enter>
Anonymous
On Sun, 26 May 2024, at 20:09, Dom Wise wrote:
In the mid 1980s I had a 16,000+ line interactive COBOL program (on a
VM/CMS system) which had a raft of debugging facilities built in (eg the
ability to trigger garbage collection of its internal heap, options for
chaining through data in linked-lists, forcing a 'page' fault - it handled
variable length strings whose total volume exceeded the max size of its
addressable working storage so WS's contents got 'paged' in & out as
needed) ... and part of that was a system which enabled me to turn
tracing off/on (& maybe also set a level-of-detail - I can't remember
now) for selected subroutines.
I did it simply by giving each subroutine a partly numeric name. In
REXX terms it's like the difference between having
string_free: procedure ....
return
string_change_length: procedure ...
return
vv
p810_string_free: procedure ....
return
p820_string_change_length: procedure ...
return
and then a particular routine would have (in REXX terms):
p913_whatever: procedure expose ...
if global_debug_flag[913] .... then do
say "entered p913_ whatever" ...
...
end
...
return
I ordered the subroutine defs (in the COBOL source) in numeric
order, which made it considerably easier to find any of them,
even if one was manually scrolling up & down.
Latterly I went further & ensured my 'Xedit' profile defined labels
for each routine's entry point as an edit session started, so that
an: l .913 editor command would take me to the start of p913's
code. (The command means 'locate' ie go to the line, labelled
".913".)
Periodically I used an Xedit macro (ie a program that ran
within Xedit) to check that all the trace-specific logic inside
each subroutine nnn correctly referred to (in REXX terms)
global_debug_flag[nnn].
I kept families & sub-[sub-]* families of routines together. So eg
the routines numbered 900-950 might all have been related to
memory management; 930-949 might all have been related to
garbage collection.
[I was working in an academic environment; once in a while I
took a program listing to the library where they had splendid
wooden tables - which I suppose 12-20 people could sit at -
and laid the listing out along one of those tables, spilling on
to the floor at each end. I certainly got some funny looks...]
Where was i? - oh yes: in the interactive debugger I could turn
on/off debugging of (say) the whole 9xx range of routines in
one command.
I've used the same idea in a few Rexx programs since then, but
not many.
It's easy to do this for code that's entirely under one's own
control.
I can see that even if I wanted some level of tracing to
apply to ALL of my own code, I wouldn't necessarily want
any (or the some level of detail) applied to code in
functions/classes incorporrted via ::REQUIRES directives.
It might be sensible to try and formulate a "standard"
way to control this sort of thing.
/I/ don't mind having integer elements in the names of
procedures (or subroutines) in /my own/ code, but
something like that won't work for method names
whose classes get included from elewhere in my
code, nor - as far as I understand it - those implicity
defined via eg ooDIalog.
One could possibly have a class-specific debug
flags data-structure, but how that would interact
with super/sub-classes is way beyond me...
--
Jeremy Nicoll - my opinions are my own.
I used a similar technique in 2009/2010.
Requires this package in each file I need to debug: https://github.com/jlfaucher/executor/blob/master/incubator/DocMusings/transformxml/trace.cls
Declare possible trace points where needed.
For example https://github.com/jlfaucher/executor/blob/a91c4f518cc91915795e842dd56e548c9792387c/incubator/DocMusings/transformxml/sdtokenizer.cls#L1263
and then activate interactively or programmatically the trace points I need to debug :
.t~on("isl2rDispatcher")
I don't remember using ::options trace "?R", maybe it was not yet available, or I wanted to trace only a limited set of entry points.
I never reused this technique since then. Instead I add 'say' instructions...
Of course, with Dom's debugger, I no longer need to insert those trace points or 'say' instructions.
Jean Louis
Thank you for the feedback so far.
It would certainly be possible to have a small code snippet at the top of most, but not every code object that can configure tracing based on a flag in e.g. .local, rather than using global options though this does feel a bit cumbersome and is more code to slow things down
I don't know if it would be possible but one thought I had was to have a trace (or just 'notrace') flag available for code objects such as methods and perhaps also routines that would override any global settings to enable tracing to be controlled for just that item. There wouldn't necessarily need to be keywords for this. So long it could be controlled in code a debugger would be able to configure traceability of its own code before it started intercepting tracing activity.
The comment above is from me but I didn't realise I wasn't logged in to SourceForge
At the 2014 Symposium I did a presentation that addressed this topic. René recently asked me to update the documentation for the purpose of publishing the RexxLA Symposium proceedings. Here is the opening section of that document.
ooRexx Tracing through Metaprogramming
A recent discussion on the RexxLA list regarding the lack of a "global trace" capability in ooRexx led to an analysis of tracing in an object oriented environment. Due to encapsulation, each method of a class begins execution with the default trace setting (Normal) in effect. Therefore to trace all the methods of a class would requiring editing each one to add a trace statement with the desired setting. The TRACECLS tool was developed to simplify the tracing of the methods of a class by using metaprogramming. In addition, the TRHILITE tool was written to assist in the identification of the trace output on the console. It may be used either alone or in conjunction with TRACECLS. It can prepend a "flag" string to each line of trace output and/or change the color attributes of that output line using the TXTCOLOR.CLS framework.
Note that at that time I don't believe "::options trace" was available. The document is available as a PDF but hasn't been added to the website Symposium page for 2014 as of now. It describes the process and programs whose source is also included.
Hi Gil,
That sounds really interesting. It's a shame it's not available. The work on global options has made it very easy to add tracing across all code objects, but it is an "all or nothing" setting.
I'm glad you brought it up though because the whole "metaprogramming" concept got me thinking and led me to a nice workaround to this problem.
The issue is I have a few methods that should ignore (in particular switch off) any global tracing options set at the package level for the source module which can easily be changed. I can't do this with any keywords but ooRexx has a rich API for manipulating packages, methods and classes and it turns out what I want can be achieved with the following:
This can all be done, including object creation, in 6 lines for 1 method, with 2 more for each additional method.
I've only written a proof of concept so far but it does seem to work as expected and it's a small enough set of changes that I can at least try it out in my debugger without too much disruption to existing code
I just love how flexible ooRexx is!
Best Regards,
Dom
Well, you have "discovered" the essence of what I did for that presentation 10 years ago. I am going to send you the PDF off-list so you can compare what I did with your proof of concept. While my program was concerned with adding trace statements to methods prior to their execution, the same approach could add a "call trace <whatever>" to suppress tracing in selective methods. I hope you can make use of the code in some form.</whatever>
Thank you for providing that. Very nice article and code!
I'd forgotten that it's ok to 'define' (i.e. replace) methods in a non-core class. This means there is no subclassing needed so no requirement for replacing object variables with attributes . Also I've learned that a new package isn't needed to recompile a method without source module global ::OPTIONS - the method just needs to be rebuilt from source
This makes the whole process very straightforward and each method can be protected against module level tracing with a single line and no code changes to the method itself:
.MyClass~define("mymethod", .method~new("mymethod", .MyClass~method("mymethod")~source))
Once all required methods have been updated new instances created in the usual way will incorporate the updated method(s).
This approach does exlude all global options from the rebuilt method but any that are needed can be incorporated by appending suitable ::OPTIONS statements to the method source code before building it
Glad it was helpful!
I found it interesting that you found that no code changes were required, just creating a new method object from the same source would do the trick. I'm guessing the processing of the ::options trace directive must build a "list" of method objects to be traced and when one replaces or adds one (or more) of them with new objects, they will not be on the already created "list" and therefore not get traced. Good to know!
On Thu, Jun 27, 2024 at 1:56 PM Gil Barmwater orange-e@users.sourceforge.net wrote:
A bad guess. The trace options are stored in the package object from which
the method is created. However, if you create a new method object, it is
associated with a different package object that does not have the same
associated trace options.
Rick
Related
Feature Requests: #836
OK, fair enough. But I still find it "surprising" that the determination of the routine and method objects to be traced under "::options trace" is made when the directive is processed and not at run time.
On Fri, Jun 28, 2024 at 5:48 PM Gil Barmwater orange-e@users.sourceforge.net wrote:
All directives are processed at translate time, none have a runtime
component. One piece of information contained within a package object is
the Initial trace settings. All executable units use that value when they
start up. If not specified via a ::options statement, then those settings
are just the default "Trace N" setting. The same thing happens with the
::options numeric settings.
Rick
Related
Feature Requests: #836
One thing to add.
Method attributes such as "unguarded" are not part of the source of a method so if a method is to be fully rebuilt from source these need to be added with an appropriate call (e.g. setUnguarded) to the newly created method object.
For the the example I gave earlier, if the original method is unguarded the method replacement code changes to:
.MyClass~define("mymethod", .method~new("mymethod", .MyClass~method("mymethod")~source)~~setUnguarded)
On Sat, Jun 29, 2024 at 8:40 PM Dom Wise melcaspazar@users.sourceforge.net
wrote:
Related
Feature Requests: #836