What is L-Debug (Lasso 9)

L-Debug is a debug stack for Lasso. It allows you to set up tracers that provide a clear overview of your applications logic to quickly observe what has happened where, when and why.

What use is it to me?

L-Debug allows you to visualise your applications' processes, monitor performance and identify poorly performing components. Visualising your applications processes can provide a quick clear overview of what's going on and help you develop at a more rapid pace.

You can leave your debugging code in place with minimal performance overhead. It can be reactivated at any point — helping you quickly solve problems that may arrise.

What is it again?

L-Debug a debug stack, it's simple to install and easy to use. You can throw objects at it to render, insert markers, time tasks and use it to understand and resolve problems. It records the sequence of events and once the task has completed outputs them in a clear and searchable interface.

Features

What's new

What's gone


Installation

  1. To install simply export to your Lasso startup folder.
    cd $LASSO9_HOME/LassoStartup (or your correct path) 
  2. svn export https://github.com/zeroloop/l-debug/trunk/debug.type.lasso
  3. Check the files permissions match the startup folders. 
  4. Restart Lasso

Basic Usage

As a security precaution L-Debug is disabled by default. When disabled it simply ignores anything passed to it and will not output any results. 

L-Debug is activated like so:

debug->activate

To re-emphasise — without the above you will not see any results. It's also important to note that you will need to implement your own security around activation.

Once activated, you can start to pass data to the debug stack. Note that the L-Debug behaves slightly differently to standard Lasso types — we'll explore that later. To get things rolling:

debug('hello world')

OK, so it's not all that original or useful - but it's a start. Let's stack up a few more complex items;

debug(array('Monday','Tuesday','Wednesday'))

Things now start to get a touch more interesting. L-Debug traverses the objects it's passed and renders then accordingly. Let's crank up the complexity:

   

local(map = map)

#map->insert('item1'=array('one','two','three','four'='isPair'))

#map->insert('item2'=array('a','b','c'))

#map->insert('item3'=map('x'='y'))

debug(#map);   

L-Debug copes comfortably complex types — making them much easier to read and brake down logically.

Custom Labels

Objects added to the stack can be given custom labels. This is useful if you want to know exactly what the object you're looking at is. You can label an object by passing L-Debug a pair, the first element is used as the label:

local(myArray = array('one','two','three')

debug('myArray label' = #myArray)


Practical Usage

L-Debug's productivity boost really comes into play when used with OOP (Object Oriented Programing). It can be used with included and flat files without issue - although you may find it difficult to apply some of the concepts contained in this document.

Entire blocks of code

Our brains tend to cope with information better when it is grouped logically in to manageable chunks. You've already seen how L-Debug groups complex Lasso types into a readable form — we're now going to do the same for blocks of code.

L-Debug has the ability to open new blocks of tracers that are self identifying. Any errors that occur within these blocks will automatically be inserted into the stack. 

The basic syntax is:

debug => {

        // your code goes here

}

Any debug calls within the the above block will now be placed within the current debug block. This greatly improves readability when compared to a typical programming debug stack (single lines of data). Errors are handled automatically.

debug => {

        debug('Initialised')

        debug('done')

}

Within a real method it may look something like this:

define myTask(task::string) => debug => {

        match(#task) => {

                case('delete')

                        debug('Deleting Record')

                 case('loop')

                           debug('Looping')

                          loop(5) => {

                           debug(loop_count = 'Loop')

                  }

            }

}

myTask('delete')

myTask('loop')


Working with Types

We can use also use the same technique we used above for Lasso types:

define myType => type {

    public oncreate => debug => {

                    self->init

    }

    public init => debug => {

                    debug('Initialised')

          }

    public tagThatBreaks => debug => {

                  strng('I don\'t work')

          }

}

local(myType = myType)

#myType->tagThatBreaks

Rapid development

...documentation to come

Automated timing

Automatic timers are handled whenever you use the debug => {} syntax or open / close blocks. They're automatically inserted into the timer stack and are viewable once the page has completed loading.

Error reporting

Lasso 9 now includes the error_stack method — which is a welcomed addition to debugging. The error_stack reports each file and line processed in order to arrive at the current error. When dealing with errors this enables us to hopefully navigate to the first location and correct the problem. Just like the default error.lasso file L-Debug also returns the error stack for any error that occurs. One of the things L-Debug brings to the table is reporting of nested errors or suppressed errors.

Errors are automatically inserted into the stack:

define cleanString(string='') => debug => {

                  return #string->replace(' ','')

}

cleanString(123)

We will still be aware of the error even if it was suppressed:

define cleanString(string='') => {

    protect => {

debug => {

         return #string->replace(' ','')

                }            

    }

}

cleanString()

And if we definitely don't want to know about it:

define cleanString(string='') => {

    debug => {

              protect => {

         return #string->replace(' ','')

                  }            

    }

}

cleanString()

When and where you should suppress and handle errors is a topic that isn't covered by this document.


Syntax style

For best performance it suggested that you use the method approach — although it supports both styles. It also allows for a greater flexibility when building or automating debug stacks. Here are some comparisons — all are valid and you can choose the style that suites you best.

->method syntax

-param syntax

debug->open(tag_name)

debug(tag_name,-open)

debug->close

debug(-close)

debug->sql('SELECT * FROM table')

debug('SELECT * FROM table',-sql)

Daisy Chaining

L-Debug supports daisy chaining commands:

debug->open('My Thing') & close

// Or something more complex

debug->open('My SQL Statement') & sql('SELECT * FROM test') & close

Timer Stack

L-Debug contains a integrated timer stack for overall page timing. It can be access by clicking the total page processing time about the search box. Blocks are automatically included and items can be inserted by using the ->timer method. 

debug->timer('Done this')

sleep(500)

debug->timer('And this')


Member Tags & Parameters

Below is an outline of the various debugging options that are available. They each serve a different purpose, but generally they alter how the current input is displayed once in the debug stack. Some parameters can be used in conjunction, for example both of these result in "Test" being wrapped in it's own debug block.

debug->open('Test') & close

debug('Test',-open,-close);

Here's the full list of public tags:

Member Tag

Description

->this

Same as calling debug('item to trace')

->open

Opens a new debug block (input set as a -title by default)

->close

Closes the current debug block

->error

Sets the current input as an error

->sql

Sets the current input as a SQL statement

->html

Sets the current input as HTML

->xml

Sets the current input as XML

->code

Sets the current input as plain text / code

->timer

Insert the current input into the overall timer stack

(generally the content is not added to standard stack)

->time

Inserts either the process time of the current page

or if a date_mSec value is supplied the seconds since

->header

Sets the current input to be a sectionlarge header

->found

Inserts the current found count

->title

Sets the current input to be a section title

->async

Returns debug stack triggers a wait state

->signal

Sends signal to resume.

->withErrors

If an error exists it is also inserted into the the stack

 


Alternative Modes

L-Debug currently has two one alternative mode built into it. Console mode - which logs rendered text output to the Lasso console (using log_critical). 

debug->activate('console')

Useful Snippets

You'll probably want to save these to use as insertable templates within your preferred IDE.

debug => {

        // your code

}

debug_dev => {

        // your code

}


The L-Debug Interface

The various check boxes allow you to toggle what is displayed in the debug stack below. The three un-checked boxs (Variables, Client Header & Custom Tags) show each of these values from the current page. The thread processing time, and time including milliseconds is displayed on the right.

You can also filter your results based on keyword. This allows you to effectively search the debug stack without having to scroll up or down. The below stack is normally 5-6 pages long, here's how it looks filtered:


What's Next?

Give it a go! Hopefully it will save you some time and prove useful in those stressful situations.

If you find any bugs, or have any ideas for improvement or comments then please do share.

www.L-Debug.org

© www.L-Debug.org - Ke Carlton 2010 (www.zeroloop.com)