Question
· Aug 7

Is there a simple, perhaps built in, way of recording sequence of function calls?

For example, you start debugging the AAA function, which calls the BBB function, then goes to the CCC^ABC function in a different routine and ends up while executing XXX^XYZ. No other routines or functions are visited in this example. What I would like is to get the record of AAA -> BBB -> CCC^ABC -> XXX^XYZ. No marking each function with recording code should be involved: too time consuming, too many functions in real code.

UPD: Iris has built in %SYS.Trace for this purpose but this class is apparently absent in Cache 2017. Did not find any substitutes yet.

Product version: Caché 2017.1
Discussion (12)6
Log in or sign up to continue

To record function calls dynamically without modifying all functions in code, you can use tools like %SYS.MONLBL, the TRACE utility, or external profiling tools. Here are some options:

  1. %SYS.MONLBL: This built-in utility is designed primarily for performance tracing. It can monitor all routines called in a process, including transitions between functions and routines. To use it:

    • Start your application in one terminal session.
    • Use another session to run %SYS.MONLBL, specifying the process ID of your application session.
    • Perform the operations you want to trace, then review the generated report in %SYS.MONLBL. Note that this might not fully work with deployed code and focuses on performance rather than debugging details [1].
  2. TRACE Utility: This tool can monitor the execution of scripts, including function calls. Refer to the InterSystems documentation or communities for more detailed setups of TRACE for function monitoring [1].

  3. Stack Inspection:

    • Use routines to save or display stack information dynamically, such as $Stack, which can reveal the execution path.
    • Stack information can be saved via a method like:
      objectscript
      ClassMethod StackToDisplay()
      {
      For loop = 0:1:$Stack(-1) {
      Write !, "Context level:", loop, ?25, "Context type: ", $Stack(loop)
      Write !, ?5, "Current place: ", $Stack(loop, "PLACE")
      Write !, ?5, "Current source: ", $Stack(loop, "MCODE")
      Write !
      }
      }

      This approach provides lightweight function call tracking without constantly modifying every function [2].

These methods allow dynamic call recording without hardcoding manual markers in each function.

Sources:

So  %SYS>d ^TRACE might be a useful start

This utility traces the execution of a process.  Traced processes write events
to a trace file with details about the routine line where the event occurred
and, if applicable, the global reference.  The events available for tracing
correspond to the metrics availabe in performance monitoring tools (PERFMON,
%SYS.MONLBL etc).  Raw data is written to iristrace_<pid>.txt in the
configured directory, and is then parsed and displayed by this utility.
 
 
Trace file directory:   not set
Trace file size limit: unlimited
Trace events selected:  RtnLoad, GloRef, BlockWait, NCacheMiss, DirBlkRd
   UpntBlkRd, BpntBlkRd, DataBlkRd, BdataBlkRd, MapBlkRd, OthBlkRd
 
1) Configure Trace
2) Trace Process (Foreground)
3) Start Background Trace
4) Stop Background Trace
5) Display Trace Files
6) Delete All Trace Files
 
Option?

All the heavy lifting can be done with the $STACK() function. Here is a start:

ZTEST	; SRS 2025-08-07
	DO A
	QUIT
A	DO B
	QUIT
B	DO C
	QUIT
C	DO D
	QUIT
D	DO STACK
	QUIT
STACK	NEW
	FOR i=0:1:$STACK(-1)-1 {
	  SET s=$STACK(i,"PLACE")
	  SET retloc=$PIECE(s," ")
	  TRY { SET code=$TEXT(@retloc) } CATCH { SET code="n/a" }
	  WRITE !,retloc," (",$PIECE(s," ",2),") -> ",code
	}
	QUIT

You only need to install this in one place, in the last method or routine call in your call stack. If your stack is like this AAA -> BBB -> CCC^ABC -> XXX^XYZ, then you need to put Stuart's code in a method called by XXX^XYZ

For example, assume you have these classmethods

ClassMethod GrandParent()
{
    do ..Parent()
}
ClassMethod Parent()
{
    do ..Child()
}
ClassMethod Child()
{
    do ..Inspector()
}
ClassMethod Inspector()
{
    FOR i=0:1:$STACK(-1)-1 {
      SET s=$STACK(i,"PLACE")
      SET retloc=$PIECE(s," ")
      TRY { SET code=$TEXT(@retloc) } CATCH { SET code="n/a" }
      WRITE !,retloc," (",$PIECE(s," ",2),") -> ",code
    }
}

Then if you call GrandParent(), then it will print this:

@ (+1) -> n/a
GrandParent+1^Sample.Test.1 (+1) ->     do ..Parent() }
Parent+1^Sample.Test.1 (+1) ->     do ..Child() }
Child+1^Sample.Test.1 (+1) ->     do ..Inspector() }

Not sure for Caché 2017 
BUT
Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2018.1.5 (Build 659U) Mon Mar 22 2021 07:12:43 EDT
Has ^TRACE in %SYS
with enough $v(..) and $ZU(..) to look promising 

 W $ZU(5)
%SYS
%SYS>D ^TRACE
 
TRACE utility for Cache. You can signal a process to write a record of all
procedure, function, or subroutine calls to a file. Then use this utility to 
interpret and display the trace. The trace file is named: CacheTrace_'pid'.txt 

Use $$DIR^TRACE(dir) to set the directory where the file(s) should be written
(process must have create/write access to the directory). $$DIR^TRACE() returns
the current directory for trace files. 

Use $$ON^TRACE(pid) to start the trace and $$OFF^TRACE(pid) to end the 
recording. Then just run ^TRACE to see the results. 

Process ID for trace file: