Article
· May 12, 2023 4m read

How to debug your code in IRIS

In this brief article I would like to share a few strategies to run objectscript code in debug mode.

How to enter debug mode

There are two ways to launch the debugger.

Launching a command

Let's suppose that we have to debug the following method

Class Custom.Example Extends %RegisteredObject
{

/// check if a string can be a valid STP code ("STP" + 13 digits)
/// w ##class(Custom.Example).isValidSTPCode("STP1234567891011")
ClassMethod isValidSTPCode(code As %String) As %Boolean
{
	set STPPrefixCode= "STP"
	if ($extract(code,1,$length(STPPrefixCode)) = STPPrefixCode) {
		set tmpDX=$piece(code,STPPrefixCode,2)
		return ($zstrip(tmpDX,"*N") = "") && ($length(tmpDX) = 13)
	}
	return 0
}

}
  1. put the cursor on the first line of you method
  2. menu Debug -> Enable/Disable breakpoint (F9)
  3. menu Debug -> Debug destination -> ObjectScript method -> input a plain command (no do/write before):  ##class(Custom.Example).isValidSTPCode("STP123")
  4. Debug -> Go

The debug engine will enter your method and stop the execution where you set the brekpoint

 

Attaching to a process

There are cases where the method you are trying to debug is called by some external procedure (for example a stored procedure call by a JDBC client) and you don't know what kind of input is provided. Or it might be the case that your method relies on data set in the process context (for example in the %request variable). To avoid replicating the context in which the method is run in the actual execution, you can attach studio to the actual process running it.

If your job is running as a business process/service etc.. in a production, you can retrieve the job id from the IRIS portal, selecting the Job tab of your production element.

However, if you don't know this information, you can use the following approach: 

  1. add the following snippet in your method where you would normally put the breakpoint
    set ^zDebug("job") = $job
    while $get(^zDebug) && $get(^zDebug("job")) {
        hang 0.5
    }
     
  2. in the terminal, launch set ^zDebug=1
  3. trigger the execution of your code (by calling the stored procedure from the client, or launching a user action in your web application...) 
  4. your procedure will enter the infinite loop, in the terminal launch w ^zDebug("job") and copy the output 
  5. menu Debug -> Attach -> Input the process id -> OK (using the keyboard: CTRL+SHIFT+A --> TAB --> CTRL+V)
  6. You'll enter in debug mode in one of the lines of the snippet defined above. In the terminal, launch k ^zDebug("job")
  7. Debug as usual

 

How to debug

Once you are in debug mode, you can use the usual debugging buttons "execute instruction" to run one line of code, "enter/exit instruction" to enter or exit the current method being executed, "execute to the cursor" to run until the line you select in the editor.

Another particularly useful feature of the debugger is that you can inspect all the variables in the context, and even launch commands that will take those variables as input, either by setting "control expressions" or by launching commands in the console. I find very usefull doing zw myObjectand zw myArrayto get the whole content of structured variables.

Keep in mind that by launching set commands you can even change your variables and see how the following code behaves, for example forcing it to enter an if branch that would otherwise be really hard to replicate.

Finally, in the "control" panel, you can inspect the whole stack that lead to the call of your method. By clicking on each stack line studio will try to take you to the actual class (if the class is in deployed mode you will get an error, it's normal, just hit ok). On the right it will list all the variables available in the context of the method you selected.

 

A few giveaways

These are just a few ways do debug code, In my examples I use studio, but the approach can be replicated in a very similar way in VS code, and if you are willing to learn the commands, even by terminal.

Studio can have a few glitches while debugging, for example it might highlight a line of code but it's not the one actually being executed. This happens especially with embedded SQL, you can always switch to the internal code representation (CTRL+SHIFT+V) that will be more reliable.

The reason why is added the $get(^zDebug) is that you can easily turn off debug mode without having to recompile the class. Of course you can rename the global to whatever is more convenient for you.

If you are working on a shared environment, keep in mind that everyone executing your code will get stuck in an infinite loop. You can consider adding other conditions to the while, for example if you have a session you could add this at the beginning if %session.SessionId = "xxxxxxxx" or limit it to the specific inputs that you are working on.

Discussion (4)5
Log in or sign up to continue