Skip to content
neoneo edited this page Jun 9, 2012 · 9 revisions

Debugging is an integral part of developing software, and it should be made as easy as possible. CFlow includes a nice debug output, that makes a few things available for you to gain insight quickly. It includes:

  • The task hierarchy of the request, grouped into the execution phases (start, before, event, after, and end). If an event is canceled or dispatched, the corresponding tasks are displayed as children of the originating task. Laid out from top to bottom, you can follow the order of task execution easily.
  • Execution times of all tasks, making locating bottlenecks easy. Since well-designed tasks are atomic, this gives you a very detailed idea of the performance of your application.
  • Exception details, displayed within the task where the error occurred. Exceptions within threads are displayed if the thread is joined by the page thread later.
  • Clear indication where an event is canceled.
  • Custom messages, with or without some data you want to see displayed.

This output is enabled if you use the debug context object. So in onApplicationStart(), you write:

application.context = new cflow.request.debug.Context();

Custom messages

Often you will want to display intermediate results. To display those results, you put a message on the event. In debug mode, the event object exposes an additional method record(). It accepts two arguments: the data you want to log, and optionally a message. In the debug output, your message will appear at the position where you invoked record(). The data you passed in will be dumped at the same spot.
An advantage of this approach is that you don't have to output those results in your view template, or even stop execution altogether, using <cfabort>. Displaying data in a loop used to be a hassle. This feature ensures that this information is now nicely laid out.

Unfortunately, views have no access to the event object and can therefore not put messages in the debug output. The need for that should be little though, because views shouldn't contain much logic. However, debugging a view will be necessary sometimes, and you may have to resort to old tactics here. As a tip, use <cfexit> instead of <cfabort> when you need to stop the rendering process for some reason. This will leave the debug output available.

Example output

The configuration page includes this example configuration (check back over there if this is new to you):

<?xml version="1.0"?>
<targets>
    <target name="session" defaultcontroller="Session">
        <start>
             <invoke handler="authenticate">
                 <dispatch event="failed" />
             </invoke>
        </start>
        <event type="failed">
             <invoke controller="global.Logger" handler="write" />
             <render view="failed" />
        </event>
    </target>

    <target name="world" defaultcontroller="World">
        <include target="template" />
        <include target="session" />
        <before>
            <invoke controller="global.Logger" handler="write" />
        </before>
        <event type="hello">
            <render view="hello" />
            <dispatch event="goodbye" />
        </event>
        <event type="goodbye">
            <dispatch target="session" event="exit" />
            <render view="goodbye" />
        </event>
    </target>

    <target name="template">
        <start>
            <render view="header" />
        </start>
        <end>
            <render view="footer" />
        </end>
    </target>
</targets>

In the case where access is allowed, the debug output looks something like this.

Example debug output

We see here that the global.Logger controller added a custom message. Since two events are dispatched on the world target, the global.Logger is invoked twice because it is defined in the before phase of the world target.
Notice also that the session.exit event has no associated tasks (conventions are not used).

When access is denied, the debug output looks as follows:

Example debug output

We see that the event is canceled and what happens afterwards, and also what doesn't happen (no before, event, and after phases).

Clone this wiki locally