Chapter 6. Debugging

by Doug Gault

At some point during the process of writing or maintaining an APEX application you will need to step into the world of debugging. APEX 4 has quite extensively enhanced debugging capabilities compared to its predecessors. This chapter will introduce you to the nuances and esoterics of debugging in APEX. While a certain amount of knowledge regarding debugging is assumed, the debugging mechanisms available in APEX 4 are different enough to merit a full ground-up discussion.

Note

This chapter specifically addresses the tools that APEX 4 provides for debugging and does not discuss external or third-party tools.

Principles of Code Instrumentation

While it may seem odd to start off a chapter on APEX Debugging with a discussion about what makes good code instrumentation, it's actually very important. In any development environment, the ability to quickly and easily see what your program is doing during execution is a critical component of debugging—especially when using a framework like APEX where a large portion of the core code is beyond your capacity to change.

Proper code instrumentation has a set of precepts that should be followed. They include the following:

Exists in every environment: Code instrumentation should be available in all environments, from Development to Production. Inserting instrumentation code in a development environment and then removing it again before migrating to production not only takes away your ability to diagnose issues in production, but also changes the core code, potentially introducing changes in functionality.

Easy to enable and disable: The instrumentation should be easy for the programmer (and in certain cases, for the user) to enable and disable. Often code instrumentation is disabled by default and only turned on when there is a problem to diagnose.

Always on: You should not need to re-compile any code to turn on instrumentation. This is especially important in a Production environment where on-the-fly code changes are often locked down very tightly. Instead, instrumentation should be enabled via a parameter or by adding a value to a table.

Lightweight: The instrumentation should be "non-intrusive" in terms of the load it introduces to the process that it is measuring. The difference between timings when instrumentation is enabled and disabled should be minimal, if measurable at all.

Integrated: Instrumentation should take advantage of any and all functionality that is built in to its native environment—especially any functionality that will make problems easier to diagnose using other tools within the environment.

As we examine APEX 4's debugging features in greater depth, you'll see that APEX adheres to these precepts quite closely. We'll also discuss how you can extend instrumentation into your own code to provide even more granular coverage than what APEX provides by itself.

Note

The remainder of the chapter discusses APEX debugging directly, but I challenge you to think about the aforementioned precepts and see how they are implemented in APEX, and how they may be implemented in your own code.

Debugging Basics

To understand how debugging works, we need to take a quick tour of the core APEX engine. While this might seem like an unnecessary review for many people, it's important due to changes in the way APEX 4 manages and logs debug information.

Page Processing and Rendering

An APEX application is basically a group of pages that are linked together via buttons, hyperlinks, tabs, etc. When a user navigates through the application, submits data, or requests to view an APEX page, there are actually two phases that the APEX engine goes through to provide the correct information back to the user:

ACCEPT (Processing): This phase acts upon the request made by the user and, if appropriate, runs any defined validations, computations, processes and branches. This includes setting session state and manipulating the underlying database tables.

SHOW (Rendering): This phase executes all appropriate code to render the page that was identified by the branch taken in the Processing phase. Page rendering may also contain computations, processes and branches, as well as the visual components that make up the page to be rendered.

The reason these phases are important to debugging is that APEX breaks down the logging of debug information into these same component parts. When the application server tier connects to the Oracle database that contains the APEX installation, it grabs a connection from the database connection pool and uses that to service the user's APEX request. You see this sequence in Figure 6-1.

Simplified APEX request/response

Figure 6-1. Simplified APEX request/response

Phase one (ACCEPT) of servicing the user's requests is to process the current page and the user's input. Because the state of the connection from the pool cannot be guaranteed to match the requirements of the user's APEX session, the first thing that APEX does is to alter the session, setting the desired NLS parameters and session settings. Figure 6-2 shows this portion of phase one processing.

Once the database session is in the proper state, APEX then begins checking to see if the APEX session is still valid, whether the user has authorization to run the page, retrieving session state from the APEX data dictionary tables, setting session state that may have been altered by the user, and then running the page processing components as defined in the metadata.

The last steps of the processing is to decide which programmatic branch to take, which in turn decides which page will then be rendered and sent to the user. APEX always takes the first branch whose condition evaluates to true.

APEX page phases

Figure 6-2. APEX page phases

Phase two (SHOW) is to render the page identified by the branching section of Phase one. Because it is possible for page rendering to be called directly via a URL, this phase also walks through the process of altering the database session, retrieving the APEX session state from the metadata tables, and executing any required security checks. Figure 6-2 also shows phase two processing.

Once everything is set, APEX then walks through the process of rendering the page as defined in the APEX metadata and presenting that page to the user via the application server. Once the application server sees that the original request has been fully satisfied, it returns the Oracle database connection back to the connection pool to be reused.

The two phases can be mapped directly to the page definition screen as indicated in Figure 6-3. Furthermore, each step is timed. Time is measured from the beginning of the current step to the beginning of the subsequent step. When debugging is turned on, these times are saved into the APEX Dictionary along with the step detail.

Mapping the phases to the APEX page definition

Figure 6-3. Mapping the phases to the APEX page definition

The two-phase process of ACCEPT and SHOW iterates as the user navigates through and uses an APEX application. At some point, you may run into issues in development where you want to see exactly what is happening during the execution of either one, or both, of these phases. This is where APEX Debugging comes in.

APEX Debugging indicates to APEX that it should emit information about exactly what it's doing during each of these phases. Unlike earlier versions, APEX 4 does not emit the debug information into the page being processed or rendered, but instead stores the full debug information in a set of tables in the APEX schema.

The 4.0 approach is superior in that the debugging information persists beyond the lifetime of the rendered page so that you can view and analyze multiple runs of a single page, comparing and contrasting their debug output to see how changes you may have made might have affected the processing or performance.

Enabling Debug

Turning interactive debugging on is a very straightforward process and can be done in one of two ways: via the Developer Toolbar or via the URL. The Developer Toolbar will be visible if you are running an application while you are also logged in to the application's parent workspace as a developer. Figure 6-4 shows the Developer Toolbar and highlights the Debug button, which toggles Debug mode on and off.

APEX Developer Toolbar highlighting the Debug button

Figure 6-4. APEX Developer Toolbar highlighting the Debug button

You may also enable Debug mode by setting the DEBUG component of the APEX URL to YES. Following is both the URL syntax and an example of using the debug component to enable debug:

http://server/apex/f?p=App:Page:Session:Request:Debug:ClearCache
:ItemNames:ItemValues

http://server/apex/f?p=100:1:23929384838429::YES:::

However, it is important to note that the ability to use either of these methods is controlled by an attribute in the application definition. Editing the application properties and navigating to the Properties region on the Definition tab will allow you to turn the ability to interactively debug on or off. By default the attribute is set to disallow interactive debugging.

Figure 6-5 shows the Properties region and indicates the debugging attribute that should be changed in order to allow interactive debugging.

The Properties region of the application definition where interactive debugging is enabled or disabled

Figure 6-5. The Properties region of the application definition where interactive debugging is enabled or disabled

Note

The debugging attribute only enables and disables interactive debugging. Programmatic debugging, discussed later in this chapter, is still possible even when the debugging attribute is set to NO.

While it may be slightly confusing, once debugging is enabled via either the Developer Toolbar or the URL, the page will refresh but you will notice nothing externally different about the page per se. Just remember that APEX 4 stores the debug information in its data dictionary tables and does not emit it into the page being debugged.

There are two visual clues that will help you recognize when debug mode is active. If the Developer Toolbar is visible, the text of the debug button will now be changed toNo Debug, as shown in Figure 6-6. Even if the Developer Toolbar isn't visible, the URL will contain YES in the debug position.

Developer Toolbar with debug enabled

Figure 6-6. Developer Toolbar with debug enabled

Debug Information

Once Debug mode is turned on and you have executed the steps you wish to debug, such as running a report or submitting a page, you will then want to view the debug information that was captured during your session. There are a couple of different places where you can do this.

Developer Toolbar

It's probably most common to want to view the debug information for the page you're currently running immediately after turning debug on. To do this, we again use the Developer Toolbar and click the View Debug button. A pop-up screen will appear which lists all of the page views for the page you are currently running. Figure 6-7 shows an example. The pop-up screen presents a high level overview of all the "Views" (or debug sessions) that have been captured for the current page. This is actually an interactive report with a filter set to show only views for the current page in the current application. You can alter the filters to show whatever combination you wish.

From this screen you can click on the View Identifier link to drill down into each view and see the detailed steps that APEX took to process and render the page. Figure 6-8 shows the detailed view for View ID 134.

View Debug pop-up window showing all debug views for Page 1

Figure 6-7. View Debug pop-up window showing all debug views for Page 1

Example detailed view of a debug session for Page 1 in Application 106, View ID 134

Figure 6-8. Example detailed view of a debug session for Page 1 in Application 106, View ID 134

From the simple high-level view shown in Figure 6-8 we can actually see some interesting things. We can see the timeline of debug views that have been created for this page by looking at the Timestamp column, the duration of each view by looking at the Seconds column, and the number of detailed debug entries for each view by looking at the Entries column.

Examining this particular example, we can see that three out of the four views processed in well under one second, while the fourth (View ID 132) took approximately 140 seconds to complete. This brings us to the discussion of a slight anomaly in the data presented in this overview report.

Remember that there are two phases involved in processing a user request: ACCEPT and SHOW. The APEX debugging engine stores these two phases as separate "views" in the debug data. Drilling down into Views 131, 132 and 134 by clicking on the View Identifier link shows us that each of these represents the SHOW phase of page processing. View 132, on the other hand, represents the ACCEPT phase.

We know this by looking at the first line of the debug output, where we see either the word SHOW or ACCEPT.

Looking back at the overview report, there is no way to know by viewing only the overview data which views represent a SHOW phase and which represent an ACCEPT phase. While this is slightly annoying and unintuitive, don't be too disturbed by it. We'll see later that we have access directly to the detail data via an APEX Data Dictionary view and there are things we can do there to identify one from the other.

The details page shows the data in two formats. First is the histogram graph across the top of the page. In this histogram the bars represent the duration of each step in relation to the single step with the largest duration. The second is the actual report that shows the details of what was executed during the phase execution.

Hovering over any of the bars in the histogram with your mouse (as shown in Figure 6-9) will show information about the step represented by that bar. Clicking on that bar will scroll the screen so that the detail line represented by the bar will come into view in the window.

View Detail Histogram showing hover hint

Figure 6-9. View Detail Histogram showing hover hint

The detail report is, again, an interactive report allowing you to create filters and manipulate the data in many different ways. The first row of the report, when sorted by Elapsed time or Row, will identify the base information about the current view, including the phase, application number, page number, workspace, request, and session. This will help you identify exactly what you are looking at. The subsequent lines show the individual steps taken to complete the phase being executed.

The detail report also has a column labeled Graph that mirrors the histogram that appears at the top of the page. This visual clue will help you scroll down the detail report and easily identify those steps that took the most time during the phase execution.

The actual detailed steps that appear will vary from page to page and also between the ACCEPT and SHOW phases. However, they will generally conform to the broad sections outlined earlier in Figure 6-2.

Navigation between the different detail views can be achieved via the navigation region at the top of the detail page as presented in Figure 6-10. If you know the View ID, you can simply type it in the Page View Identifier field at the top of the detail view page and click the Set button. If you want to return to the high-level view page, click the Select Page View Identifier button.

The Debug View Navigation region

Figure 6-10. The Debug View Navigation region

Clicking the Reset button will return the current report to its default settings, resetting any filters you may have implemented.

Application Utilities

Another place to view debug information is via the application utilities. These can be reached by clicking the large Utilities icon on the main application edit page (as shown in Figure 6-11) or by clicking the small Utilities icon in the quick menu in the upper right of any Application Builder page (as shown in Figure 6-12).

Utilities icon on the Application edit page

Figure 6-11. Utilities icon on the Application edit page

Utilities icon from the Quick Links menu

Figure 6-12. Utilities icon from the Quick Links menu

Clicking either icon will take you to the Application Utilities page. From here, select the Debug Messages icon (as indicated in Figure 6-13).

The Debug Messages icon

Figure 6-13. The Debug Messages icon

You will be presented with a high level report identical to the one you see when accessing the data from the Developer Toolbar. The difference is that the report initially shows all views for all pages in the current application. Using the Interactive Report Capabilities, you can filter the debug views to display only the ones you're interested in.

Drilling down will take you to the detail report, this time without the histogram across the top. Apart from this small change, all of the data is the same that you would see via the Developer Toolbar.

Navigation in this version of the report is slightly different. Here you would use the APEX breadcrumbs to navigate between the Debug and Debug Message Data pages to select the desired views as shown in Figure 6-14.

Breadcrumbs for the Debug Messages utilities

Figure 6-14. Breadcrumbs for the Debug Messages utilities

Another change to the utilities based Debug view is the addition of the Purge Debug Messages button. This button allows both workspace administrators and developers to purge underlying debug data for the currently selected application based on certain criteria. The available criteria are

Purge all messages: This option will purge all data for the selected app that currently resides in the underlying debug tables.

Purge messages by age: This option allows you to select a time frame for which to purge, from 1 day to 4 weeks.

Purge current session messages: This option allows the purge of messages for the currently active user session.

Purge by View Identifier: This option allows the purge of messages related to a specific View ID.

Warning

When purging data be aware of what other developers are working on within the workspace and application. It is possible to accidently purge data that may be important to other developers.

Benefits of Debug Mode

There are a few benefits to Debug mode that are worth mentioning, as they help make debugging some of the more complex pieces of APEX a little easier. These benefits are particularly apparent when working with graphs and charts, or when developing interactive reports.

Graphs and Charts

APEX 4 uses AnyChart 5.1 (http://www.anychart.com) as its graphing and charting engine. While the APEX team has done a wonderful job of hiding the behind-the-scenes complexity of how charting works, there are times when you may need to dig into the details of how charts are being rendered.

As you learned in chapter 2, everything you change on the Chart Attributes page of a given chart's definition ends up creating an XML document that determines how the chart will be drawn. You can, if you wish, edit the XML manually to make changes that are not available via the Chart Attribute options.

Although you can get a good feel for the XML that will be generated, you cannot guarantee what that XML will look like until run time. To be able to view the full run time XML, prior versions of APEX required you to use third-party, browser-based debugging tools. APEX 4, however, has made things much easier.

When Debug mode is on, each chart will contain a link that will allow you to view the XML that was generated to drive it. Figure 6-15 shows a line chart with the Show XML link visible in the lower left-hand corner.

Chart in Debug Mode with Show XML link

Figure 6-15. Chart in Debug Mode with Show XML link

Clicking this link will display the full runtime XML that was generated to drive the chart. This is useful for debugging manual changes you may have made to chart XML, or to view how the data has been emitted into the XML from the series queries you have defined. Figure 6-16 shows an example of the generated XML.

Generated runtime XML for a chart

Figure 6-16. Generated runtime XML for a chart

Interactive Reports

While Interactive Reports give an amazing amount of power to the end user, debugging them can be a bit challenging due to the fact that APEX basically rewrites the query behind the scenes based on the user's column selections, filters, and more. Enabling debugging on an Interactive Report page will emit the SQL that is generated for the current incarnation of the Interactive Report into the debug data.

Note

Once an Interactive Report is rendered to the page, any changes made to the filters, sorting, column selection, etc. are done via AJAX calls. Therefore these changes are not tracked by debug mode unless the entire page is refreshed. To refresh an entire page, you can either toggle Debug mode off and then back on, or you can force a page refresh using your browser.

Consider the two debug snippets shown in Figures 6-17 and 6-18. Both snippets are from the same interactive report.

Debug data for the default version of an interactive report

Figure 6-17. Debug data for the default version of an interactive report

Figure 6-17 shows the detail debug data for an Interactive Report region prior to a user having made any changes to the report. You can tell the following from the figure:

  • Line 35 indicates the start of the region.

  • Line 38 lists the columns that will be displayed.

  • Line 40 shows the base SQL statement.

  • Line 41 shows the value of the APXWS_MAX_ROW_CNT bind variable, as it will be used in the SQL statement.

Debug data for the altered version of an interactive report

Figure 6-18. Debug data for the altered version of an interactive report

Figure 6-18 shows the detailed debug data for the same Interactive Report region after a user has made changes to the report, as indicated in Figure 6-19. The changes indicate that we are filtering the ASSIGNED_TO and grouping by the STATUS.

  • Line 35 indicates the start of the region.

  • Line 38 lists the columns that will be displayed.

  • Line 40 shows the base SQL statement.

  • Line 41 shows the value of the APXWS_EXPR_1 bind variable, as it will be used in the SQL statement.

  • Line 42 shows the value of the APXWS_MAX_ROW_CNT bind variable, as it will be used in the SQL statement.

With this debug data you have enough information to not only troubleshoot, but also examine the potential performance of the query that was generated.

The filters applied to the altered report

Figure 6-19. The filters applied to the altered report

APEX Debugging API

Not only does APEX provide you with a method to interactively debug your application pages, it also provides a full API that allows you to instrument your own code and even turn on debugging programmatically. In this section we'll examine the APIs and see how they can be put to use in an application context.

APEX_DEBUG_MESSAGE

The core debugging API exists in the form of the APEX_DEBUG_MESSAGE package. This package is fairly undocumented and, at the time of writing, does not appear in the API reference nor does any mention of it appear in the APEX Developers Guide. Following is brief documentation of the individual procedures that appear in the API. We'll discuss their usage further in later sections.

ENABLE_DEBUG_MESSAGES Procedure

This procedure allows the developer to programmatically enable debugging in the context of the current phase of page processing.

Syntax

procedure enable_debug_messages (p_level in number default 7);

Parameters

p_level: Level of debug messages to log

Usage Notes

Level 1 is the most important.

Level 7 is the least important.

Setting p_level to 3 would log any message at level 1, 2 and 3.

Enabling Debug programmatically is not limited by the application level setting that disallows interactive debugging. Therefore, even if the application is set to disallow interactive debugging, programmatic debugging will still work as expected.

The earliest points in an APEX page where debugging can be programmatically enabled are as follows:

PAGE RENDERING: You may create a Branch of type Branch to PL/SQL Procedure with a processing point of On Load: Before Header making sure that the sequence number of the process is the lowest in the set.

PAGE PROCESSING: You may create a Process of type PL/SQL Anonymous Block with a processing point of On Submit – Before Computations and Validations making sure that the sequence number of the process is the lowest in the set.

When debugging is programmatically enabled via the API, APEX will not emit the debug message that indicates the phase (i.e., SHOW or ACCEPT). Therefore it is good practice to use the LOG_MESSAGE procedure to output a message immediately after debug that will help you to identify the phase. For example, the following code snippet could be placed in an On Load page process to programmatically enable debug and immediately emit a message indicating the phase:

apex_debug_message.enable_debug_messages(p_level => 7);
apex_debug_message.log_message('S H O W --- Programmatically enabled'),

Once turned on programmatically, debugging will remain on until it is either turned off programmatically or via the Developer Toolbar, if available.

DISABLE_DEBUG_MESSAGES Procedure

This procedure allows the developer to programmatically disable debugging in the context of the current phase of page processing.

Syntax

procedure disable_debug_messages;

Usage Notes

DISABLE_DEBUG_MESSAGE will turn off debugging no matter how it was enabled.

Disabling debug in the middle of a phase will cause the actions that follow to be omitted from the debug information.

The latest points in an APEX page where debugging can be programmatically disabled are as follows:

PAGE RENDERING: Occurs on load, after the footer, making sure that the sequence number of the process is the highest in the set.

PAGE PROCESSING: Occurs on submit, after computations and validations, making sure that the sequence number of the process is the highest in the set.

REMOVE_SESSION_MESSAGES Procedure

This procedure allows the developer to programmatically remove any debug messages associated with a specific user session.

Syntax

procedure remove_session_messages(p_session in number default null);

Parameters

p_session: The session for which to purge debug data

REMOVE_DEBUG_BY_APP Procedure

This procedure allows the developer to programmatically remove any debug messages associated with a specific application.

Syntax

procedure remove_debug_by_app (p_application_id in number);

Parameters

p_application: The application ID for which to purge debug data

REMOVE_DEBUG_BY_AGE Procedure

This procedure allows the developer to programmatically remove all debug messages for a specific application where the message timestamp is prior to N days before today.

Syntax

procedure remove_debug_by_age (
    p_application_id  in number,
    p_older_than_days in number);

Parameters

p_application_id – The application ID for which to purge debug data

p_older_than_days – Number of days prior to today, beyond which all history will be deleted.

REMOVE_DEBUG_BY_VIEW Procedure

This procedure allows the developer to programmatically remove any debug messages for a specific application and identified as belonging to a specific debug view.

Syntax

procedure remove_debug_by_view (
    p_application_id  in number,
    p_view_id        in number);

Parameters

p_application_id: The application id for which to purge debug data

p_view_id: APEX debug view ID for which detailed debug data will be deleted

LOG_MESSAGE Procedure

This procedure allows the developer to emit debug messages from within either APEX anonymous blocks or stored packages and procedures called from APEX.

Syntax

procedure log_message (
    p_message in varchar2 default null,
    p_enabled in boolean  default false,
    p_level   in number   default 7);

Parameters

p_message: Message to be logged up to 4000 characters

p_enabled: Whether to log the message regardless of whether Debug mode is enabled. Pass one of the following values:

TRUE: Message will be logged regardless of debug mode.

FALSE: Message will only be logged if debug mode is enabled.

p_level: Identifies the level of the log message.

Usage Notes

Level 1 is the most important.

Level 7 is the least important.

When using within stored PL/SQL program units that might be called outside of the context of APEX, always set P_ENABLED to FALSE. Failing to do so will result in an error, as the APEX SECURITY GROUP ID will not be set.

LOG_LONG_MESSAGE Procedure

This procedure allows the developer to emit debug messages larger than 4000 characters from within either APEX anonymous blocks or stored packages and procedures called from APEX.

Syntax

procedure log_long_message (
    p_message in varchar2 default null,
    p_enabled in boolean  default false,
    p_level   in number   default 7);

Parameters

p_message: Message to be logged up to 32767 characters.

p_enabled: Whether to log the message regardless of whether Debug mode is enabled.

TRUE: Message will be logged regardless of debug mode.

FALSE: Message will only be logged if debug mode is enabled.

p_level: Identifies the level of the log message.

Usage Notes

Level 1 is the most important.

Level 7 is the least important.

Logging will be split into 4000 byte chunks.

When using within stored PL/SQL program units that might be called outside of the context of APEX, always set P_ENABLED to FALSE. Failing to do so will result in an error, as the APEX SECURITY GROUP ID will not be set.

LOG_PAGE_SESSION_STATE Procedure

This procedure allows the developer to emit session state information into the debug messages table for a given page in the current application.

Syntax

procedure log_page_session_state (
    p_page_id in number default null,
    p_enabled in boolean  default false,
    p_level   in number   default 7);

Parameters

p_page_id: Identifies the page within the current application and workspace context.

p_enabled: Whether to log the message regardless of whether Debug mode is enabled.

TRUE: Message will be logged regardless of debug mode.

FALSE: Message will only be logged if debug mode is enabled.

p_level: Identifies the level of the log message.

Usage Notes

Level 1 is the most important.

Level 7 is the least important.

Each item from the indicated page and its current value in session state will be emitted to the debug messages table.

Programmatic Debugging

As you can see, the APEX_DEBUG_MESSAGE API provides the facilities necessary to enable and disable Debug mode programmatically. And as mentioned in the preceding documentation, the ability to use programmatic debugging is not affected by the application level setting. This means that, even if you have a standard which dictates that applications are deployed into production with debugging disabled, you still have the ability to capture debug information.

Figure 6-20 shows the capture of debug information for a single page in an application that displays a simple report. The debug information was captured interactively by using the Developer Toolbar.

Debug data gathered interactively

Figure 6-20. Debug data gathered interactively

Figure 6-21 shows a branch created to gather debug information programmatically. The branch was created at the earliest possible point on the page. The branch does not in fact redirect to another page, but instead simply programmatically enables debugging. Figure 6-22 shows the resulting debug data.

Definition of a Branch which programmatically enables debug

Figure 6-21. Definition of a Branch which programmatically enables debug

Debug data gathered programmatically

Figure 6-22. Debug data gathered programmatically

While it may be more natural to think that a Page Process might be the best place to turn on programmatic debugging, there is some method to the madness of choosing a Branch instead. No matter what its sequence number, Page Processes always execute after Branches and Computations. Therefore if you want to capture information about Branches and Computations in your debug output, you must turn Debug mode on before these items are processed by APEX.

The ability to create a Branch of type Branch to PL/SQL Procedure at process point On Load: Before Header that actually does not branch anywhere is perfect for our purposes. As long as its sequence number is lower than any other branch, programmatic debugging will capture all logged messages for any Branch, Computation or Process that follows it.

When debugging is turned on via the API, even at the earliest point possible, APEX will have already completed some of the steps involved in rendering or processing the page.

If you compare the interactive data to the data that was gathered programmatically, you'll notice there are a number of things that just don't get captured in the programmatic version. This shouldn't concern you too much as what is missing is directly related to core APEX code and not code for which you will likely be seeking to gather information.

However, one of the more important things that gets left out is the first line of debug information which indicates the phase. This is easily remedied by following the ENABLE_DEBUG_MESSAGE call with a call to LOG_MESSAGE, as shown earlier in Figure 6-21.

The same is true for the PROCESS phase as for the SHOW phase demonstrated above. When enabling debugging programmatically, there will be some things that get missed. In most circumstances, the missing data isn't significant enough to be concerned about; however, if you want to make sure you get all the data relating to a page, you're likely to want to enable debug as part of the page phase that is directly before the one you wish to capture.

For example, if you wish to capture all the details about Page Processing for a page, turn debugging on during that page's SHOW phase. Alternatively, if you wish to capture all information regarding a page's SHOW phase, enable debug as part of the processing phase of the page that branches to the page in question. If debug mode is already enabled prior to reaching the desired phase, even if it was enabled programmatically, the entire phase's information will be captured.

Instrumenting Your Own Code

While having access to the debug information APEX emits by default is helpful, there will inevitably be times when you'll need deeper insight into what may be going on in code that you have written.

The APEX Debugging API provides methods to expand the depth of information being gathered. This is especially useful when you're trying to understand what is happening within PL/SQL that might be part of a Branch, Computation, or Process.

Logging Custom Messages

The LOG_MESSAGE and LOG_LONG_MESSAGE procedures are quite simple in signature; however, they provide an amazing amount of flexibility and functionality when it comes to gathering information about what's going on within your application.

The most straightforward use case would be one in which you might want to emit simple messages which mark the steps a piece of PL/SQL might be executing. For instance, marking the purpose of a simple code construct, like a loop, as in Listing 6-1.

Example 6-1. Simple Code Demarcation Using LOG_MESSAGE

BEGIN
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START - INSERTING 10000 RECORDS...'),
--
FOR I IN 1..10000 LOOP
    INSERT INTO PERF_TEST (guid1, guid2, guid3, created_on)
    VALUES (SYS_GUID, SYS_GUID, SYS_GUID, SYSDATE);
END LOOP;
--
END;

Enabling debug mode and running the page would produce the output as shown in Figure 6-23.

Using LOG_MESSAGE to emit a line into the debug information

Figure 6-23. Using LOG_MESSAGE to emit a line into the debug information

However to ad real value it behooves you to mark not only the beginning, but also the end of each significant step as in Listing 6-2.

Example 6-2. Marking the Beginning and End of a Block of Code

BEGIN
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START - INSERTING 10000 RECORDS...'),
--
FOR I IN 1..10000 LOOP
    INSERT INTO PERF_TEST (guid1, guid2, guid3, created_on)
    VALUES (SYS_GUID, SYS_GUID, SYS_GUID, SYSDATE);
END LOOP;
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>END - INSERTING 10000 RECORDS...'),
--
END;

Remember that execution timing is measured from the beginning of the current step to the beginning of the subsequent step. These step boundaries coincide with the point at which a debug message is logged. Therefore surrounding a code block with calls to LOG_MESSAGE provides the extra benefit of capturing an accurate timing of all the code that ran between those two messages, as shown in Figure 6-24.

Surrounding code blocks with LOG_MESSAGE calls to capture an accurate timing

Figure 6-24. Surrounding code blocks with LOG_MESSAGE calls to capture an accurate timing

You have to be careful about your usage of the LOG_MESSAGE procedure, though. For instance, injecting a LOG_MESSAGE call in the middle of the loop would first create a huge number of log entries that you would be unlikely to want to wade through, and second, would potentially impact performance as you would be executing the full code path of the LOG_MESSAGE procedure 10,000 times.

That is where the p_level parameter comes in handy. Consider Listing 6-3. Here we've done exactly what was just warned against, but notice that the value for the level of the outer calls is at a higher level than that of the inner calls.

Example 6-3. Using P_LEVEL to designate the message level

BEGIN
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START - INSERTING 10000 RECORDS...', P_LEVEL=>5);
--
FOR I IN 1..10000 LOOP
    --
    APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START RECORD '||I, P_LEVEL=>7);
    --
    INSERT INTO PERF_TEST (guid1, guid2, guid3, created_on)
    VALUES (SYS_GUID, SYS_GUID, SYS_GUID, SYSDATE);
    --
    APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'END RECORD '||I, P_LEVEL=>7);
    --
END LOOP;
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'END - INSERTING 10000 RECORDS...', P_LEVEL=>5);
--
END;

Now when we choose to enable debugging programmatically, we can use the p_level parameter to decide to what level of message we wish to log. Calling ENABLE_DEBUG_MESSAGES with p_level set to 5 would only log the messages outside the loop. However, enabling debug with a message level of 7 would log both outside and inside the loop. Using this mechanism you can manage the level at which messages are logged and what level of log message you wish to capture.

Warning

Using Interactive Debugging from either the Developer Toolbar, or by manipulating the URL will always initiate logging to capture messages level 7 and above.

Lastly, using the p_enabled parameter of LOG_MESSAGE allows you to dictate that a message is important enough to always be logged, whether or not debugging has been enabled. Listing 6.4 shows the same code but injects a LOG_MESSAGE call in the top of the block that will always be written to the APEX Dictionary, regardless of the state of debugging.

Example 6-4. Using P_ENABLED to Always Log a Message

BEGIN
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'THIS MESSAGE IS ALWAYS LOGGED...', P_ENABLED=>TRUE, P_LEVEL=>3);
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START - INSERTING 10000 RECORDS...', P_LEVEL=>5);
--
FOR I IN 1..10000 LOOP
    --
    APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'START RECORD '||I, P_LEVEL=>7);
    --
    INSERT INTO PERF_TEST (guid1, guid2, guid3, created_on)
    VALUES (SYS_GUID, SYS_GUID, SYS_GUID, SYSDATE);
    --
    APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'END RECORD '||I, P_LEVEL=>7);
    --
END LOOP;
--
APEX_DEBUG_MESSAGE.LOG_MESSAGE( P_MESSAGE =>'END - INSERTING 10000 RECORDS...', P_LEVEL=>5);
--
END;

Logging Session State

There are many instances when trying to debug a page where it would be beneficial to know specifically what was in session state. The LOG_PAGE_SESSION_STATE procedure will provide you exactly that information.

The API will emit information into the DEBUG logs, which shows the session state for each item on the designated page. Like the LOG_MESSAGE procedure, the LOG_PAGE_SESSION_STATE procedure lets you dictate what log level will be associated with the emitted log records, and allows you to decide whether to override the debug setting and always log the session state.

You can call the LOG_PAGE_SESSION_STATE procedure without passing any parameters and it will log the session state for the currently processing page at debug message level 7, but it will only do so if debugging is enabled.

Figure 6-25 show an example of the output of debug information that contains session state information. The session state information is specifically contained in rows 2 through 6 in the report.

Debug information containing session state information

Figure 6-25. Debug information containing session state information

The data contains a row for each item that appears on the page, whether visible to the user or not, and contains the item name, length, and value. While it may seem odd that the items are rendered not in the order that they appear on the screen, but in alphabetical order by item name, this is due to the fact that many of the new APEX Themes are DIV based and it is not necessarily possible to identify where they appear on the page.

You can also emit more than just the current page's session state, but to do this you will need to make an API call for each page you wish to include. Figure 6-26 shows an example including session state for Page 9 and Page 7.

Debug information including session state information for 2 separate pages

Figure 6-26. Debug information including session state information for 2 separate pages

The Data Behind Debugging

As mentioned before, APEX Debug data is now kept in a set of data dictionary tables so that it can be examined and compared to other runs of the same page. In this section we'll look at the underlying tables and view, the lifetime of the data in them, and how the data differs between when captured interactively as opposed to programmatically.

Tables and View

Debug data is stored as metadata in the core APEX schema and is split across two tables: WWV_FLOW_DEBUG_MESSAGES and WWV_FLOW_DEBUG_MESSAGES2. The data is exposed to the developer via a single APEX Data Dictionary View: APEX_DEBUG_MESSAGES.

Warning

Don't try to query the tables directly. Focus on the view. You don't want to waste your time trying to sort out whether your debug data is contained in one table or spread across them both. Always query the view.

While it may seem odd that there are two underlying tables, APEX uses this two-table setup in a number of places to keep a finite duration of data around. The table into which data is actually inserted is switched every two weeks. When the switch occurs from one table to the other, APEX truncates the table that it's switching to. This means that at a minimum it will have no data (i.e., no debug information has been gathered) or potentially up to 4 weeks of data. Figure 6-27 gives a visual depiction of this idea.

The view and underlying tables that hold APEX Debug information

Figure 6-27. The view and underlying tables that hold APEX Debug information

You may feel that having at most 4 weeks of data available to you at any one time might be too limiting, and I would have to agree with you. If you want to keep more than that amount of data, you'll have to take matters into your own hands. Doing this is actually quite straightforward.

First, you'll need to create a local version of the debug data table that you control. The simplest way to do this would be the following:

CREATE TABLE MY_DEBUG_MESSAGES
AS
SELECT * FROM APEX_DEBUG_MESSAGES
WHERE 'X' = 'Y'

This will create the table without bringing any of the rows over. Then you'll want to copy only the rows from the APEX_DEBUG_MESSAGES VIEW over to your new table, but to make this something that can be run over and over, you'll only want to copy the rows that don't already exist in the table. Luckily the PAGE_VIEW_ID column gives us something unique to compare against. The following SQL statement will copy only the information that does not already exist in the table:

INSERT INTO MY_DEBUG_MESSAGES
SELECT *
FROM APEX_DEBUG_MESSAGES
WHERE PAGE_VIEW_ID NOT IN
  (SELECT DISTINCT PAGE_VIEW_ID FROM MY_DEBUG_MESSAGES);

To automate this process, you can include the above SQL statement into a stored procedure and set it up to run regularly as a database-scheduled job. And to make sure that you are always looking at the latest information, you can create a view that joins the data in your table with the data in the APEX view, as follows:

CREATE OR REPLACE VIEW MY_DEBUG_MESSAGES_V
AS
  SELECT *
  FROM my_debug_messages
UNION
  SELECT *
  FROM APEX_DEBUG_MESSAGES
  WHERE page_view_id NOT IN
    (SELECT DISTINCT page_view_id FROM my_debug_messages);

Now you have everything you need to duplicate the screens and reports that APEX provides you as part of the debugging interface. In fact, you can actually replicate it 100 percent by simply examining the code behind the APEX pages.

Note

If you're not already aware, you can load the APEX core applications up into a workspace and examine the code and SQL statements that make them tick. Most of the core code of APEX is held in the wrapped packages in the APEX_040000 schema, but most of the APEX magic is there for you to examine.

Examining the Debug Data

Now that we know where the Debug data is kept, let's have a look at exactly what is being kept. Table 6-1 lists each column and gives a description of the data it contains.

Table 6-1. Descriptions for the Columns of the APEX_DEBUG_MESSAGES View

Column Name

Description

PAGE_VIEW_ID

Page View Identifier which is a unique sequence generated for each page view recorded with debugging

MESSAGE_TIMESTAMP

Timestamp in GMT that the message was saved

ELAPSED_TIME

Elapsed time in seconds from the beginning of the page submission or page view

EXECUTION_TIME

Time elapsed between the current and the next debug message

MESSAGE

Text of the debug message

APPLICATION_ID

Application Identifier, unique across all workspaces

PAGE_ID

Page Identifier within the specified application

SESSION_ID

APEX Session Identifier

APEX_USER

Username of the user authenticated to the APEX application

MESSAGE_LEVEL

Level of debug message, ranging from 1 to 7

WORKSPACE_ID

APEX Workspace Identifier, unique within an instance

Most of the columns in the view are pretty self explanatory, but the relationship between the MESSAGE_TIMESTAMP, ELAPSED_TIME, and EXECUTION_TIME merits some discussion.

The MESSAGE_TIMESTAMP is very straightforward; it's merely the accurate timestamp of when the debug message was entered into the underlying debug message tables. To get a clear picture of the order in which things happened during a page SHOW or ACCEPT, simply order the rows ascending by the MESSAGE_TIMESTAMP.

The EXECUTION_TIME is calculated as the difference between the current Timestamp and the Timestamp from the subsequent record. So, in essence, it shows how much time had elapsed between the two records being inserted. You can see this calculation in the definition of the APEX_DEBUG_MESSAGE view. The view uses the LEAD and PARTITION functions to calculate the difference between the two timestamps.

The ELAPSED_TIME is something different entirely. This column is supposed to show the elapsed time since the beginning of the page submission or the page view. While logic might dictate that you should be able to perform some arithmetic using the Timestamp and the calculated execution time to arrive at the elapsed time, you'd be wrong to do so. APEX actually uses yet another mechanism (a function call in this case) to calculate the elapsed time since the beginning of this phase. Because the function call actually takes some time (even if it's microseconds), the timing of the elapsed time is always just a little off from what you might expect. Don't get hung up on this. They are usually within such a small tolerance that it's fairly unmeasurable unless the task you are tracking is huge.

And in any account, what you really should be paying attention to is EXECUTION_TIME. If you want to find what you need to performance-tune within your page, pay attention to the thing with the largest execution time.

Using Debug Data for More Than Debugging

The fact that you have direct access to the data, and now know how to keep the data around for longer than the natural four-week cycle that is built in to APEX, means that you can begin to use this data for more than just debugging. The overall information that is available makes this data perfect for performing longer-term analysis and performance tracking.

For instance, using programmatic debugging, you could choose to collect and keep performance information about your most important application pages. You may not want to keep information for every page view, but you could easily write logic that captures n% of all page views. Then using the information contained in your long-term debug tables you can track the performance over time. You could even begin to spot and map trends in performance, potentially identifying when a critical process might trend outside its window of acceptability.

Another potential use is to compare data before and after making a change to a page. If the main structure of the page hasn't changed, but instead the driving query behind it, then you would be able to easily write code to compare, line for line, whether the new version of the page ran faster or slower than a previously captured version.

If a page calls stored PL/SQL code that is also instrumented using the APEX Debugging API, you then have insight into the performance trends of the business logic that you've written in PL/SQL.

The bottom line is, you have this data for whatever purposes you wish, and the better instrumented your code, the more detail you have at your disposal.

Debugging Dynamic Actions

Because the Dynamic Actions framework is actually implemented as JavaScript that is processed in the browser, debugging dynamic actions is approached a bit differently. APEX still uses Debug mode to determine whether or not the Dynamic Actions framework should emit data and you can still enable debugging in all the same ways that have been discussed. However, instead of inserting data into the underlying debug messages tables, the Dynamic Actions framework emits message to the browser's JavaScript console.

The information that appears in the JavaScript console takes the following form:

Dynamic Action Fired: [Dynamic Action Name](Specific Action Fired])

Figure 6-28 shows an example of using the FireBug JavaScript console in Firefox to view the debug information.

The FireBug JavaScript console containing Dynamic Action debug messages

Figure 6-28. The FireBug JavaScript console containing Dynamic Action debug messages

While this doesn't give you any detail about what the dynamic action code is doing, it does give you a visual indicator that the dynamic action code is firing. For a bit more information you can use FireBug's console menu to also capture any XMLHttpRequests, as shown in Figure 6-29.

Choosing to show XMLHttpRequests in the console

Figure 6-29. Choosing to show XMLHttpRequests in the console

After this is turned on, you'll not only see the dynamic actions that fire, but also the calls to WWV_FLOW.SHOW that indicate XMLHttpRequests (or AJAX calls) as shown in Figure 6-30. You'll notice that the AJAX calls being made actually show up before the debug message from the dynamic action to which they belong. Don't be confused by this. It's merely a function of when APEX has chosen to emit the debug message.

Console containing XMLHttpRequests and Dynamic Action debug messages

Figure 6-30. Console containing XMLHttpRequests and Dynamic Action debug messages

Clicking on the arrow beside the POST will expand the detail of the AJAX call and will expose the Header, Post, Response, and the JSON object as seen in Figure 6-31. Because the Dynamic Actions are generated code based on what you declared within the APEX builder, the POST section will only be partially useful. You'll be able to see what field initiated the transaction and what APP and PAGE were involved, but the other data will likely be unfamiliar and mean nothing to you. However, the data contained in the Response and JSON tabs actually represent data that was returned by the AJAX call and was used by the dynamic action.

In the example shown in Figure 6-31, the data that was passed back is being used to set the available values in a select list. Each JSON object contains two attributes, "d" and "r", which relate to the select list's display and return value respectively.

Expanding the POST to see its content

Figure 6-31. Expanding the POST to see its content

If you really want to get into the details of what is happening during a dynamic action, you'll need to get into the depths of JavaScript debugging, which is beyond the scope of this chapter. But hopefully what has been presented will give you a method for at least knowing whether the defined dynamic actions are firing when expected and bringing back the data they should.

What Debug Doesn't Capture

APEX's debugging mechanism is exemplary and does an amazing job of letting you know exactly what is going on during page rendering and processing. But there are some things that it just does not capture. In this last section we'll discuss what gets missed and how you can make up for the limitations.

AJAX Calls

AJAX by its very nature is initiated from within JavaScript that is being run in the browser. This means that, from the APEX point of view, the page rendering has already been completed and all APEX debug messages that can be logged have been.

Therefore, any AJAX call that runs as part of the page is not captured by APEX Debugging. This is true for AJAX calls that may be handwritten by the developer and for those that might be included as part of a plug-in or dynamic action.

You can, however, instrument Application or Page level On-Demand PL/SQL processes using the debugging API. When doing this, you must include a call to ENABLE_DEBUG_MESSAGES at the beginning of the on-demand process and should also include a call to DISABLE_DEBUG_MESSAGES at the end.

The debugging information will be captured and related to the page from which the process was called. It will not appear within the context of the page SHOW or ACCEPT phases, but instead will be created under its own unique view identifier and only contain messages that you specifically emit using the LOG_MESSAGE procedure.

The same is true for the PL/SQL portion of APEX Plug-in code. You can simply instrument the render phase of a plug-in by using the LOG_MESSAGE FUNCTION without enabling debug messages specifically. Then, when debugging is turned on either programmatically or interactively, the messages will be included in the page's SHOW phase debug messages.

Instrumenting any AJAX callback functions within a plug-in needs to be handled the same way you handled on-demand processes. You must include the call to enable and disable debugging specifically.

FLASH Charts

FLASH charts are an interesting subject when it comes to debugging. We've already talked about the fact that when debugging is enabled, a FLASH chart will expose a link that allows you to view the XML that was used to render it. But there is more going on behind the scenes.

When a page that includes a FLASH chart is rendered by APEX, it isn't actually including the FLASH as part of the SHOW phase. APEX actually emits the FLASH object inclusion code, which you can view in the chart's region definition's Region Source. At this point the APEX engine is done and it is the browser that does the rest of the work.

The FLASH object inclusion code is interpreted by the browser, which loads the Flash object. Once the FLASH object is loaded, it in turn makes another call back to a special part of the APEX engine that runs the queries related to the chart series, assembles the XML used to drive the chart, and then renders based on what is returned.

So both the load of the base chart object and the call to generate the XML happen outside of the APEX engine and therefore do not get logged in to the APEX debug data.

To debug these steps, you once again need to depend on tools in the browser as opposed to the APEX debug metadata. The FireBug plug-in to Firefox allows you to use its NET tab to see the call that is used to load the FLASH object and the call to APEX_UTIL.FLASH that generates and returns the XML. Examining the timings for the later of the calls will indicate how long the round trip to retrieve the XML data took and will indicate whether you have a potential performance problem in the chart series queries that drive your chart.

Reports

You would think that reports are fairly straightforward in terms of debugging, as they are merely queries that are run by the APEX engine. This is true up to a certain point; we already talked about the challenges with Interactive Reports due to the fact that they use heavy JavaScript and AJAX to provide the interactivity.

The same problem can surface in classic reports if you have chosen to use Partial Page Refresh. When Partial Page Refresh is turned on for a classic report, JavaScript and AJAX are used to navigate through the pagination of a report, and because the page is not being re-drawn, the actions are not captured via debug.

As with any AJAX and JavaScript, you again must rely on browser tools to help you understand what is going on. When you paginate through a report that uses PPR, you'll see a call to the "f" procedure as an XMLHttpRequest. The POST of the call will indicate information about the page and the rows to be retrieved, and the RESPONSE will contain the HTML for the new set of rows that were returned. Again, looking at the timing of this call will give you some indication of performance problems that might be occurring when fetching the data set.

Summary

I hope you've seen how useful APEX debugging can be when trying to troubleshoot your applications, and I hope I've given you some food for thought as to how debug data could potentially be used for performance analysis and trending. As APEX continues to develop as a product, I am sure that there will be more alterations and extensions to the APIs allowing for more and more granular messages to be captured. Keep an eye on the APEX core documentation for new releases, as many of these alterations and extensions often go unannounced and unnoticed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset