Debug Instrumentation
The Panorama X Preferences Instrumentation panel works with the zlog statement to enable conditional logging of the internal state of Panorama program code. The panel allows the granularity of logging to be controlled at the level of individual procedures. This means that the code necessary for outputting debug information can be left permanently in production code, but selectively enabled only when trying to diagnose a problem. This granularity lets you keep clutter in the log to a minimum, improving performance and making the log easier to analyze.

Instrumentation can be added to any procedure in any database (by adding one or more zlog statements). In addition to instrumentation in your database, much of Panorama’s internal code includes instrumentation. If you run into a problem with Panorama, ProVUE tech support staff may ask you to enable selected instrumentation. The first half of this page will show how you can work with tech support to enable the instrumentation already built into Panorama. The second half covers how you can add your instrumentation to your own databases.

### Enabling Instrumentation

The first step is to enable the Instrumentation panel, which is done by opening the Preferences window (from the Panorama menu), then clicking on the Advanced tab, then clicking the Enable Instrumentation Panel checkbox. You’ll immediately see an additional panel option, Instrumentation.

Here’s what this panel typically looks like. The top portion of the panel controls where the instrumentation output is sent, either a file or the console, or both. The bottom portion of the panel controls which databases and procedures currently have enabled instrumentation coverage.

When the Instrumentation panel is enabled, you’ll also see a new Instrumentation menu at the end of the menu bar. This menu is displayed with a microscope icon.

The top item in this menu provides quick access to the Instrumentation panel. The other items provide quick, universal access to features in the Instrumentation panel without having to actually open that panel. These items are described in more detail below.

#### Instrumentation Output to a Text File

If you want the instrumentation to output to a text file, check the Log Path box. (Note: You can also enable output to a text file by checking the Save Log to File item in the Instrumentation menu.)

By default, the instrumentation output will be put into a file named Panorama X Instrumentation Log.txt in your desktop folder. You can change both the name and the folder. If you type in a different folder path, Panorama will automatically create the specified folder for you if it doesn’t already exist.

Click the gear icon for a pop-up menu containing common operations that can be performed with the instrumentation log file (these commands also appear in the Instrumentation menu).

Choose Reveal Log in Finder to see the instrumentation log file in the Finder, for example if you wanted to attach it to an email. Another way to put the log into an email would be to choose Copy Log to Clipboard and then paste it into your email client.

If you want to view the log file, a great way to do that is with the BBEdit text editor from Bare Bones Software. If you don’t already have a copy of this application, a free version is available on the Mac App Store or directly from the Bare Bones web site. The free version doesn’t have all of the fancy bells and whistles of the paid version, but it is more than sufficient for viewing an instrumentation log file.

Choose Archive Log to rename the log file and start fresh with a new log file. The existing log file stays in the same folder, but with the date and time appended to the end, for example Panorama X Instrumentation Log Archive 2020_05_20_10_32_12.txt. Choose Archive Log… to display a dialog that allows you to choose the name and location of the archived file, instead of having Panorama generate the name automatically.

The final option, Clear Log, clears the log so you can start fresh. Whatever is currently in the log is permanently lost.

#### Real Time Instrumentation Output

Instrumentation can also be monitored in real time. Instead of viewing the instrumentation results after the fact in a file, you see the output immediately, as it happens. (Note: You can enable both log to a file and immediate output at the same time, allowing both instant viewing and a permanent record.) Real time instrumentation is monitored thru a separate app, either Console.app or Terminal.app. You have to launch these apps separately to use this feature. Both Console.app and Terminal.app require some special preparation to work with Panorama X; the necessary techniques are described below.

Viewing Instrumentation with Console.app

Start by opening the Console app. This app is included with macOS: it’s located in the Utilities folder inside the Applications folder. Alternatively, you can open it from within Panorama by choosing Open Console,app from the Instrumentation menu. The Console window will look something like this:

By default, the Console window displays a continuous firehouse of information. In the screenshot above you can even see that the console captured the fact that a screenshot was being taken! We need to cut down this torrent of data so that only output from Panorama X is shown. Start by typing PanoramaX into the search box and pressing Return.

This will still show too much information, because in addition to the instrumentation it will also show internal macOS messages related to Panorama. To fix, this, click on the ˇ symbol, then choose Library from the pop-up menu.

When you’re finished, the Console window should look like this.

Since you’ll probably want to use this configuration again, you should save it. To do that, click the Save button on the right, just below the tool bar.

We suggest saving the configuration using the name PanoramaX. After you press the Save button, the saved configuration will appear in bar immediately below the tool bar. Now any time you open the Console window, you just have to click this button to prepare for viewing output from Panorama. (You can also choose this option from the Action menu.)

Once the Console app is running open you’ll see the Console.app icon in the Instrumentation panel (in the Preferences window). Click the Log to Console checkbox to enable real time output (you can also select this option in the Instrumentation menu).

Now you’re all set, when you run code that contains instrumentation, the log output will immediately appear in the Console window.

Note: If you open the Console app after opening the Instrumentation panel, Panorama will automatically detect it and the icon will appear. In other words, you can open the Console app before or after opening the Instrumentation panel.

Viewing Instrumentation with Terminal.app

Using Terminal.app with Panorama X instrumentation also requires a slight bit of prep. The first step is to open the Preferences window. Then choose the Install “Run Panorama X using Terminal.app” command from the Install menu. This will create a new icon inside the Applications folder inside your user folder.

Note that this is not your primary Applications folder, but your alternate Applications folder that is inside your user folder. Panorama will open this folder for you when it creates the file, so it should be easy to find. Once it is created you can use it in place, or you can move it to another location (including the primary Applications folder), and you can install it in the dock if you want. You can also rename it if you wish.

To view realtime Panorama instrumentation using Terminal.app, first quit Panorama if it is currently open. Then double click the Run Panorama X Using Terminal icon (or single click if it is in the dock). This will launch Terminal.app, or open a new terminal window if Terminal.app is already open. Then Panorama X will launch from this terminal window.

When you open Panorama this way, you’ll see the icon for Terminal.app in the Instrumentation panel. Make sure that Log To Terminal is checked to enable real time output to the terminal window (you can also select this option in the Instrumentation menu).

Now you’re all set, when you run code that contains instrumentation, the log output will immediately appear in the Terminal window. A nice aspect of this approach is that you can easily select and copy multiple lines of the log text.

Note: You must leave Terminal.app running with this window open for as long as Panorama itself is running. If you close this terminal window, or quit the Terminal application, Panorama will immediately stop running.

Note: You cannot drag a database onto the Run Panorama X Using Terminal icon to open the database. Instead, you must first double click on the Run Panorama X Using Terminal icon to launch Terminal and Panorama, then drag the database icon onto the Panorama icon in the dock (or simply double click on the database idon).

Viewing Instrumentation with Xcode

If you launch Panorama with Xcode, you’ll see the Xcode icon in the Instrumentation panel and all instrumentation output will go to Xcode’s console window.

Sorry, this is just a tease. You can’t launch Panorama with Xcode unless you work here at ProVUE Development. But we use this technique all the time, so we thought we’d give you a peek.

Bringing Console.app or Terminal.app to the Front A quick way to bring the app you are using to view instrumentation output to the front is to click on the icon. You can also use the Instrumentation menu, which will contain a Bring Console to Front or Bring Terminal to Front item, depending on which you are using. (Of course you can also use regular macOS methods to bring the app to the front, for example clicking on it’s dock icon or pressing Command-Tab.)

Note: If you are running Panorama X under Terminal.app, it doesn’t matter whether Console.app is running or not – the output will go to Terminal.app. There is no way to make the output go to both Console.app and Terminal.app at the same time.

#### Testing the Instrumentation Output

To verify that the instrument output is configured correctly, you can click on the Instrumentation Note icon (or choose Instrumentation Note from the Instrumentation menu. This opens a dialog that allows you to send anything you want to the log.

Additional features of the Instrumentation Note dialog are explained later on this page.

### Instrumentation Coverage

The bulk of the Instrumentation panel is devoted to specifying what procedures will produce instrumentation output. By default, instrumentation coverage is completely turned off. To see instrumentation output, you must enable coverage for one or more procedures.

#### Using Instrumentation Favorites

Panorama includes several favorite configurations for instrumentation coverage, and you can also set up your own favorites. If you are working with Panorama technical staff, they may ask you to use one or more favorites to set up coverage. Instrumentation favorites are accessed by clicking on the star icon.

Choosing one of the favorite options will automatically set up coverage for a collection of procedures, as set up by the person who created the favorite (usually either you or ProVUE Development). Panorama will automatically start sending instrumentation output to the log as the specified procedures are used.

Combining Multiple Favorites Normally choosing a favorite turns off all other coverage, but in some situations you may want to combine the coverage of two or more favorites. To do this, first select one of the favorites as described above. Then hold down the Shift key and click on the star again. The names of the favorites are prefixed with a + symbol to show that the coverage will be added to the previously selected coverage, rather than replacing the existing coverage.

The end result in this example is that coverage is now set up for both basic and advanced shared database operation.

When you want to switch to different coverage, simply choose another favorite, or choose the Clear All Coverage option.

Creating your own favorites will be covered later on this page.

#### Customizing Instrumentation Coverage

If needed, you can customize instrumentation coverage at the level of individual procedures. Typically you set up the coverage you want, run the code you want to test, then turn the coverage back off again. (Usually you don’t want to leave coverage on all the time for two reasons. First, it can create large log files that are unwieldy to work with. Secondly, enabled instrumentation can impact the performance of the code – in other words, the code runs somewhat slower when coverage is enabled. So you usually want to turn coverage off when you’re not using it.)

The left side of the panel lists all of the currently open databases. Your databases are listed at the top, followed by Panorama’s internal databases.

Since the list can be rather long, you have the option of searching to quickly find the database you want.

Clicking on a database allows you to change the coverage of the procedures in that database. All of the procedures that are enabled for instrumentation are listed (procedures that do not contain zlog statements are not listed, so for some databases, the list may be empty).

Click anywhere on a procedure to toggle whether or not instrumentation is enabled for that procedure.

Instrumentation for the ShellScript statement is now enabled. If you run a procedure that contains this statement, you’ll see information about the internal operation of this statement in the log.

In addition to toggling procedures individually, there are shortcuts to toggle multiple procedures. Hold down the Shift key to toggle a range of procedures, from the previous click to this one. To toggle all procedures in this database, click on the larger checkbox at the top of the list.

If you want to enable coverage for all procedures in a database, another method is to click on the `--- ALL ---` item at the top of the list. If this item is checked, coverage is enabled for every procedure, no matter what other items are checked.

In the example above, coverage for all of these procedures is enabled, even though only one is checked. This is a nice way to temporarily enable all procedures, allowing you to easily go back to the more custom coverage when you’re finished.

If a database has a long list of procedures, you can search to winnow the list and quickly find the procedures you are interested in.

#### Customizing Coverage from the Procedure Window

If a procedure window is open, you can quickly enable or disable coverage for that procedure by choosing Enable Coverage (This Procedure) from the Instruments menu. You don’t even have to open the Instrumentation panel to do this. (You do, however, have to add one or more zlog statements to the procedure.)

If you want to enable coverage for all procedures in this database, choose the Enable Coverage (All Procedures) command from the menu.

#### Working with Favorites

Once you’ve set up the coverage you want, you can save it as a favorite so that you can easily recall that same coverage later. For example, suppose you’ve set up coverage for scripting, like this:

To save this, click on the star and choose Add to Favorites… from the pop-up menu.

The top part of this dialog lists your current instrumentation coverage. You’ll see each database and each procedure that is covered. This is handy as a reminder of what coverage you have set up. Type in the name of the new favorite at the bottom and press the Add Favorite button. (Note: You should avoid names that end with (Client) or (Server), these names have special meaning.

Your new favorite now appears in the pop-up menu when you click on the star. The favorites are listed in the menu in alphabetical order.

Updating a Favorite There’s a bit of a trick you can use to modify an existing favorite. Start by modifying the coverage the way you want, then click on the star and choose Add to Favorites…. Now type in the name of the favorite you want to modify. When you press the Add Favorite button, the existing favorite will be updated. To save you the trouble of typing in the name of the favorite again, you can click on the star to choose from the list of existing favorites.

Renaming and Deleting Favorites To rename and/or delete a favorite, click on the star and choose Edit Favorites…. This displays a dialog that lists each favorite, one per line.

To rename a favorite, simply edit the name. To delete a favorite, select and delete the entire line. If you are careful, you could also manually edit the coverage of a favorite, but we don’t recommend this. When your changes are complete, press the Update Favorites button.

### Updating Factory Default Favorites

Panorama X comes pre-loaded with intrumentation favorites set up by ProVUE Development. These favorites aren’t actually part of Panorama itself, they are downloaded from the provue.com server, so they can be updated as needed. Panorama automatically checks for updates every time you open the Preferences window, but you can also force an immediate update by clicking on the star and choosing Update ProVUE Favorites.

Note: Since these favorites will get automatically updated, you probably don’t want to edit or remove them – they will just revert to their factory configuration the next time the Preference window is opened. If you want to modify one of these favorites, first select it, then modify the coverage, then add it as a new favorite.

### Enabling Coverage During Panorama Startup

Panorama runs a lot of code when it first launches. Usually you are not interested in this code, so Panorama automatically disables log output during the startup process. If you do want to see logs of startup activity, click on the white star and check the Enable while Panorama is Starting Up option.

Keep in mind that depending on what coverage you have enabled, this can produce pages and pages of output before you even get your database open.

### Coverage Links

Panorama allows you to export the current instrumentation coverage as a link. You can save the link for later, or send it to another computer, for example via email, etc. First set up the coverage you want, then click on the Share icon and choose Export Coverage Link from the pop-up menu.

The link will look something like this (it may be much longer if you have a lot of databases and procedures included in the coverage.

    panoramax://zlog?_ScriptLib=APPLESCRIPT,SHELLSCRIPT

There are two ways you can use this link. First, you can copy it into the clipboard, then click on the star icon and choose Import Coverage Link.

Secondly, you can simply click on the link in any application that works with links – web browsers, email clients, Messages.app, Slack, etc. The link will automatically bring Panorama to the front (even launching Panorama if it is not already open) and set up the coverage according to the contents of the link. You don’t even need to open the Preferences window, Panorama simply activates the specified coverage automatically.

### Adding Code Instrumentation

To use instrumentation, you need to put special statements into your code. As the code runs, these statements will output information into the log (assuming the coverage is enabled, as described above).

The primary statement for instrumentation is zlog. This statement has one parameter, a formula.

    zlog formula

When the code runs, Panorama calculates the formula and puts the result into the log. So when you look at the log, you can see the result of that formula at that particular instant in time. Here’s an example of a short program with zlog statements added to monitor the progress of the program. I’ve put this into a procedure named Test Loop.

    zlog "Start program."
    for n,1,5
        zlog n
    endloop
    zlog "Finished."

If you run this program, the log output will look like this. (Don’t forget to enable the coverage for the procedure. If the coverage is off, the zlog statements will be ignored.) Notice that the start of each line begins with `[Test Loop]`, the name of the procedure. This helps you keep track in the log of what code is running, especially useful in large complicated databases with lots of procedures.

    [Test Loop] Start program.
    [Test Loop] 1
    [Test Loop] 2
    [Test Loop] 3
    [Test Loop] 4
    [Test Loop] 5
    [Test Loop] Finished.

#### Displaying Variables in the Log

It’s very common to display a variable or field in the log. Of course you can construct a formula to do that manually, but there is a function called labelize( that can help make that easier. This function displays not only the value of the variable or field, but its name. Here’s a revised version of the program that uses this function.

    zlog "Start program."
    for n,1,5
        zlog labelize(n)
    endloop
    zlog "Finished."

The log output looks very similar, except that now the variable name is displayed as well as the value. If you have a complicated log with pages of output, this can be invaluable.

    [Test Loop] Start program.
    [Test Loop] n: 1
    [Test Loop] n: 2
    [Test Loop] n: 3
    [Test Loop] n: 4
    [Test Loop] n: 5
    [Test Loop] Finished.

If the variable contains multiple lines of text, the labelize( function will automatically switch to a multi-line format.

    zlog "Start program."
    let Address = "1234 Tank Farm Road"+cr()+"Suite 72"+cr()+"San Luis Obispo, CA"
    zlog labelize(Address)

Here’s what a multi line value looks like in the log:

    [Test] Start program.
    [Test] === Address ============
    [Test] 1234 Tank Farm Road
    [Test] Suite 72
    [Test] San Luis Obispo, CA
    [Test] === END OF Address ============

By the way, there is no reason you can’t use multiple labelize( functions in one zlog statement, like this.

    let dbname = info("databasename")
    let fname = info("fieldname")
    zlog labelize(fname)+" in "+labelize(dbname)

The log output from this code will look something like this:

    [Test] fname: Phone in dbname: Contacts

However, this won’t work if any of the variables or fields contain multiple lines. In that case, you should only use a single labelize( function.

If you don’t like the format the labelize( function uses for the label and data, you can customize it. See labelize( for further information.

#### Displaying Formulas in the Log

The labelize( function only works with an individual variable or field name. You cannot use it with a general formula. For example, this code won’t work.

    zlog labelize(FirstName+" "+LastName))

In fact, it will result in an error that will stop the program. There are three possible solutions. First, you could just set up the required formula yourself.

    zlog "Full Name: "+FirstName+" "+LastName

Alternately, you could set up a temporary variable and use that.

    let fullname = FirstName+" "+LastName
    zlog labelize(fullname)

Finally, you can use the labelizeformula( function, as shown below. Note that the entire formula must be quoted, in this case with curly braces ({ and }).

    zlog labelizeformula({FirstName+" "+LastName})

The result will look like this:

    [Test] FirstName+" "+LastName --> Mary McCormack

If the formula result contains multiple lines of text, the labelizeformula( function will automatically switch to a multi-line format.

    zlog labelizeformula({listfiles(info("desktopfolder"))})

Depending on the contents of your desktop folder, the output will look something like this:

    [Test] === listfiles(info("desktopfolder")) ============
    [Test] AMW46_Registration.pdf
    [Test] Cataract Simulations.sox
    [Test] Chevy Chase Flag Crosswalk.napkin
    [Test] Colorado Boulevard Flag Crosswalk.napkin
    [Test] Golden Gate Bridge Photo.jpg
    [Test] Mount Fuji in Winter.jpg
    [Test] Personnel Roster.pandb
    [Test] Real Estate Listings.pandb
    [Test] US Airports.pandb
    [Test] === END OF listfiles(info("desktopfolder")) ============

#### Displaying Info Functions in the Log

The results of the info( function can be displayed using the labelizeformula( function, but this is so common that Panorama has a special function to make this easier, labelizeinfo(. For example, to display the name of the current database, use this code:

    zlog labelizeinfo("databasename")

The result will look something like this:

    [Test] info("databasename") --> US Airports

If the function result contains more than one line, a different default pattern is used. For example, the code:

    zlog labelizeinfo("files")

will put something like this into the log:

    [Test] === info("files") ============
    [Test] Contacts
    [Test] Orders
    [Test] Products
    [Test] === END OF info("files") ============

#### Displaying a Dictionary in the Log

If you need to display a dictionary (see Data Dictionaries), use the zlogdictionary statement. For example, the code:

    zlogdictionary windowinfo("","ALL")

will put something like this into the log:

    [Test] == DICTIONARY windowinfo("","ALL") ============
    [Test] DATABASE="Formula Workshop"
    [Test] HORIZONTALSCROLLBAR=0
    [Test] VARIABLES="
    [Test] theWizardFormula
    [Test] resultFormat
    [Test] theWizardFormulaResult
    [Test] theWizardFormulaError
    [Test] theFormulaDatabase"
    [Test] OPTIONS="NoToolBar NoHorzScroll NoVertScroll"
    [Test] VERTICALSCROLLBAR=0
    [Test] TOOLBAR=0
    [Test] TYPE="Form"
    [Test] LASTTIMEINFRONT=3673970363
    [Test] NAME="Formula Workshop"
    [Test] PROCEDURE=""
    [Test] FORM="Formula"
    [Test] === END OF DICTIONARY windowinfo("","ALL") ============

The parameter must be just a dictionary, you cannot mix in anything else.

#### Extra Logging Code

It’s rarely necessary, but if you need to run additional code only when logging is enabled, you can use the zlogging( function to check whether logging is currently enabled. For example if for some reason you wanted to display a message only when logging is enabled, you could do that.

    if zlogging()
        message "Logging is enabled"
    endif

Remember, you don’t need to use zlogging( when you are using the zlog and zlogdictionary statements, these statements already check whether logging is enabled.

#### Code Instrumentation in Anonymous Procedures

The zlog statement only works in code within a named procedure (see Procedures to learn about named vs. anonymous procedures). Use the zlogalways statement if you need output log information from code in an execute, starttimer, or other anonymous procedure. See the zlogalways statement for full details on how to do this.

#### Hard Coding Coverage

Usually instrumentation coverage is enabled or disabled in the Instrumentation panel as described earlier on this page, but the zlogcoverage statement allows coverage to be controlled by the program itself. This statement has one parameter, which may be always, never or normal (it can also be `""`, which is the same as normal).

    zlog "This will appear if coverage is enabled in Instrumentation panel."
    zlogcoverage "always"
    zlog "This will always appear."
    zlogcoverage "never"
    zlog "This will never appear."
    zlogcoverage "normal"
    zlog "Again, will appear if coverage for this procedure is enabled in Instrumentation panel."

Note that coverage is only enabled for this exact procedure, not for any subroutines called by this procedure.

### Sending a Note to the Instrumentation Log

The Instrumentation Note dialog provides a way to send an arbitrary message into the instrumentation log. For example, if you are about to start an experiment, you could put a note about it into the log, to help you remember later what you did.

Usually the easiest way to open this dialog is to choose Instrumentation Note from the Instrumentation menu. (If the Instrumentation panel is open, you can also open the dialog by clicking on the Note icon.) The dialog looks like this:

Whatever you type will be sent to the log, with a prefix identifying it as a note, and the current time. It will look something like this:

    [NOTE @12:54:34 am] Testing 1, 2, 3

#### Embedding a Formula in the Note

To embed a formula in the note, enclose the formula in curly braces (`{` and `}`).

Before sending the note to the log, Panorama will calculate the value of the formula and merge it into the note. In this case, the final result looks like this:

    [NOTE @12:58:01 am] User is Jim Rea

A second option is to make the entire note a formula.

The example above will produce the same log output as the previous example.

#### Choosing Which Log the Note Appears In

If there is a copy of Panorama X Server running on the current computer, you have a choice of whether to send note to the local log, the server log, or both.

If you send the note to the server, any formula in the note will be calculated on the server. This makes a great investigative tool to poke around and see what is going on on the server. Keep in mind, however, that you have no control over what database is active, or what record and field are active. So you generally don’t want to use database fields in the formula directly. Instead, use formulas with functions that allow you to specify exactly what database, fields, and records you want to investigate, for example info(, dbinfo(, fieldvalue(, fileglobalvalue(, arraybuild(, lookup( etc.

If you choose the Local + Server Log option, any formulas will be calculated twice – once on the local computer, and once on the server. The result of the local calculation will appear in the local log, and the result of the server calculation will appear in the server log. The results won’t necessarily be the same.

To learn more about using Panorama X Server with instrumentation, see Client/Server Debug Instrumentation.

### Including Procedure Triggers in the Instrumentation Log

In addition to adding instrumentation to your code, you can also ask Panorama to log every time code is triggered. If some code is malfunctioning but you’re not sure where, this helps you to quickly track down what section of code is causing the problem. If you enable the Debug Instrumentation Objective-C Classes/CodeTriggers option, Panorama will add an entry to the Instrumentation Log every time a procedure is triggered, whether explicitly or implicitly. Whenever a menu is chosen, a button is pressed, or implicit code is triggered, the exact trigger will be noted for later examination. This is especially useful for implicit code since you may not be aware that the code is even being triggered (see Implicitly Triggered Procedures).

To enable this option, open the Instrumentation panel in the Preferences dialog. Then click on Objective-C Classes at the bottom of the list on the left, then click on CodeTriggers on the right.

With this option enabled, any action that triggers a procedure will be added to the instrumentation log. For example, suppose you have the Help>Font Awesome Icons window open and you click on the button that opens a new window:

If the CodeTriggers option is enabled, two new lines will appear in the instrumentation log:

    TextDisplayObject RUN CODE --> call "New Catalog Window"
    RUN FORM EVENT --> OPEN (Catalog)

The first line records that you clicked on a Text Display Object, and that this object had code associated with it which was run. The log even includes the code itself (if the database is locked down then the code will be redacted). This is an explicit trigger.

The button code opens a new cloned Catalog form. The Catalog form has been set up to implicitly trigger code when it opens. This implicit code trigger has been recorded on the second line of the log (RUN FORM EVENT). If there was a problem in opening the window, the log shows that Panorama got as far as the OPEN FORM EVENT code, so that might be a good place to start looking for the problem.

As this example shows, the instrumentation log not only shows code in your own databases that are triggered, but code in Panorama itself. Much of Panorama is written in Panorama code, so it can be educational to enable the CodeTriggers option and then start clicking on things in Panorama to see what is being triggered. (Note: Some code built into Panorama is protected and will not be recorded.)

#### Including Call/Return Flow in the Instrumentation Log

You can also configure instrumentation to record procedure flow as your program calls subroutines and then returns back to main code. Click on Objective-C Classes at the bottom of the list on the left, then choose the control flow statements you want to record in the log.

The available control flow statements that can be recorded are:

- call
- callwithin
- execute
- farcall
- farcallwithin
- goto
- returnerror
- return
- shortcall
- stop

Keep in mind that if you record all of these statements, your log may contain more information than you really want to look at. In fact, recording all of these may slow down Panorama operation as it takes time to record these items.

The instrumentation log not only shows code in your own databases that are triggered, but code in Panorama itself. Much of Panorama is written in Panorama code, so it can be educational to enable recording of control flow statements and then start clicking on things in Panorama to see what is being called within Panorama. For example you’ll see lots of action if you open the Find/Select dialog and click a few buttons.

    -[ExecuteStatement run] findselectdialog
    -[ExecuteStatement run] windowglobal «_HotKeys»
    -[ExecuteStatement run] rtn           settrigger "Key.ESCAPE"         resume {}         if error             global dlgStack             dlgStac
    -[ExecuteStatement run] rtn              global dlgStack             define dlgStack,""             local s             let cb=tagparameter(arra
    -[ExecuteStatement run] rtn              global dlgStack             define dlgStack,""             local s,cb             let cb=tagparameter(a
    -[CallStatement run] initializeDimensions (in _FindSelectLib)
    -[CallStatement run] adjustQueryHeight (in _FindSelectLib)
    -[CallStatement run] makeQueryRows (in _FindSelectLib)
    -[CallStatement run] deleteAllQueryRows (in _FindSelectLib)
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q0field,q0operator,q0operand1,q0operand2     q0field="" q0operator="" q0operand1="" q0operand2=""
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q1field,q1operator,q1operand1,q1operand2     q1field="" q1operator="" q1operand1="" q1operand2=""
    -[ExecuteStatement run]          showvariables q1field,q1operator,q1operand1,q1operand2
    -[CallStatement run] makeQueryFormula (in _FindSelectLib)
    -[CallStatement run] editQueryRow (in _FindSelectLib)
    PopupButtonObject RUN CODE --> call queryFieldChanged,1
    -[CallStatement run] queryFieldChanged (in _FindSelectLib)
    -[CallStatement run] initializeDimensions (in _FindSelectLib)
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q1field,q1operator,q1operand1,q1operand2     q1field="" q1operator="" q1operand1="" q1operand2=""
    -[ExecuteStatement run]          showvariables q1field,q1operator,q1operand1,q1operand2
    -[CallStatement run] makeQueryFormula (in _FindSelectLib)
    -[CallStatement run] editQueryRow (in _FindSelectLib)
    TextDisplayObject RUN CODE --> call queryRowInsert,1
    -[CallStatement run] queryRowInsert (in _FindSelectLib)
    -[CallStatement run] initializeDimensions (in _FindSelectLib)
    -[CallStatement run] adjustQueryHeight (in _FindSelectLib)
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q2field,q2operator,q2operand1,q2operand2     q2field="" q2operator="" q2operand1="" q2operand2=""
    -[ExecuteStatement run]          showvariables q2field,q2operator,q2operand1,q2operand2
    -[CallStatement run] makeQueryFormula (in _FindSelectLib)
    -[CallStatement run] editQueryRow (in _FindSelectLib)
    PopupButtonObject RUN CODE --> call queryFieldChanged,2
    -[CallStatement run] queryFieldChanged (in _FindSelectLib)
    -[CallStatement run] initializeDimensions (in _FindSelectLib)
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q2field,q2operator,q2operand1,q2operand2     q2field="" q2operator="" q2operand1="" q2operand2=""
    -[ExecuteStatement run]          showvariables q2field,q2operator,q2operand1,q2operand2
    -[CallStatement run] makeQueryFormula (in _FindSelectLib)
    -[CallStatement run] editQueryRow (in _FindSelectLib)
    PopupButtonObject RUN CODE --> call queryOperatorChanged,2
    -[CallStatement run] queryOperatorChanged (in _FindSelectLib)
    -[CallStatement run] initializeDimensions (in _FindSelectLib)
    -[CallStatement run] makeQueryRow (in _FindSelectLib)
    -[ExecuteStatement run]      fileglobal q2field,q2operator,q2operand1,q2operand2     q2field="" q2operator="" q2operand1="" q2operand2=""
    -[ExecuteStatement run]          showvariables q2field,q2operator,q2operand1,q2operand2
    -[CallStatement run] makeQueryFormula (in _FindSelectLib)
    -[CallStatement run] editQueryRow (in _FindSelectLib)

(Note: Some code built into Panorama is protected and will not be recorded.)

See Also

- Client/Server Debug Instrumentation -- using instrumentation with Panorama X server and clients.
- info("runningunderterminal") -- returns true if Panorama was launched under Terminal.app.
- labelize( -- returns the value of a field or variable along with a label. This saves typing when you need to display fields or variables when logging and debugging.
- labelizeformula( -- returns the value of a formula along with the formula itself as a label.
- labelizeinfo( -- returns the value of an info( function, along with the function itself as a label.
- labelizepattern( -- formats a text value using a label and a pattern.
- zlog -- outputs a message to the instrumentation log (if instrumentation is enabled).
- zlogalways -- unconditionally outputs a message to the instrumentation log.
- zlogcoverage -- allows instrumentation coverage to be turned on or off within a procedure.
- zlogdictionary -- outputs a data dictionary to the instrumentation log (if instrumentation is enabled).
- zlogging( -- returns true if zlogging is enabled for the current database and procedure, otherwise false.

History

Version | Status | Notes
10.2 | New | New in this version.