Today we're going to talk again about debugging your agent's inner workings, but this time through the use of debug output instead of the step-by-step debugger. This is generally where you want to go to check up on what's happening behind the scene if your agent's output is not helping enough. The following contains scary exhaustive lists of obscure words, but fear not, the good news is that you won't need to remember any of them!


In the SDK, the queryserver's output can be seen in the Output tab when the agent is running, next to Conversation.
When running the Agent in the console, you can find the same data under Monitoring and ControlView Component Logs, then checking the latest Queryserver logfile.

  The level of debug is highly customizable; you can pick and choose the outputs important to you, whether you want to know what's happening to your datasources, how the scoring is done exactly, why the agent is taking so long to startup, the order in which the domains and packages are being compiled, how your supercomplex routine ends up in a loop, what's happening with the notifications....

 There are various ways of setting the debug level:
- In the SDK, your agent's properties have a field called Debug, which takes the argument "tag1 tag2 tag3...."
- In the SDK when the agent is running, you can change the level at any time using the command "!d tag1 tag2 tag3..."
- For a console agent, you can change it in the config file under Query Server:
 <debug>tag1 tag2 tag3...</debug>

- For a running console agent, there is also a way - see at the end of this post for more details!

So what exactly would you put in this TAGS list?
Well the easiest approach is to use the preset debug levels. They are numbered from 0 to 9, 0 outputing nothing and 9 outputting per minute the equivalent of the whole contents of the Library of Alexandria.
By default, the SDK uses level 5 which is a good compromise but still quite verbose, while console Agents are usually set to 1 or 2 due to the amount of traffic they can get.

Here are, for future reference, the tags associated with each level:

      1 =  platforminfo domainerror matchingtestupdate extrainfo qddpevents qdmrevents qdmisc externalcomp dispatcherrunlevel miscloadingerrors preloadingagentfailed idsapiaccess

      2 =  1 + platforminfoex plugins miscloadinginfo queryprocessor bestmatchoverall predicatereloading qduserevents qdmessages qddns sourceblocker1

      3 =  2 + datasourcebasic queryconstruction querytimings gatewaynotfound gatewayfailure gatewaydbnotfound gatewayblocked externalext executionrephrase scriptexe1 threadid sourceblocker2 matcherlow agentpreloaded miscloadingdetails

      4 =  3 + userprofile domainallstats match moreenum

      5 =  4 + datasourceaverage conditiontreebasic userprofileex keepallmaybeyoumeant scriptexe2 timedactions matcheraverage

      6 =  5 + conditiontreeaverage matchpossible contextbasic presentationfeed

      7 =  6 + datasourcedetailed conditiontreedetailed patternexplosionbasic tokengrouping compilationrephrase scriptexe3 xslttrransform1

      8 =  7 + patternexplosiondetails matcherhigh sourceblocker3

      9 =  8 + displayallunify currentcommand patternexplosionfull xslttrransform2

 

For the global setting, using such a number can be quite enough to define how much general output you want to see, but let's say you have a problem with your datasources and want to see what happens with them without getting too distracted with the rest. Well you could call the command : "!d 1 datasourcebasic" which resets the main debug level to 1, then adds "datasourcebasic" on top of it. Note that the tags are cumulative, so if you were to call it again with: "!d datasourceaverage", your debug would then contain all of 1 + datasourcebasic + datasourceaverage. On the other hand, calling a numbered level resets to that level, so "!d currentcommand 1" is the same as "!d 1".

Now, you've noticed that if you're only interested in datasources, you still have to list a number of tags to achieve the level of debug you want. Here comes another helper: the tag groups! Much like the numbered levels, these help you by setting a bunch of tags at once:

      platform            = platforminfo platforminfoex

      miscloading     = miscloadinginfo miscloadingerrors miscloadingdetails

      init                     = plugins conditiontreebasic conditiontreeaverage conditiontreedetailed dispatcherrunlevel

      up                      = userprofile userprofileex

      domain              = domainerror domainallstats

      context              = contextbasic

      pattern              = patternexplosionbasic patternexplosiondetails patternexplosionfull

      matching          = bestmatchoverall match keepallmaybeyoumeant matchpossible displayallunify matchingtestupdate matcherlow matcheraverage matcherhigh

      conditions       = conditiontreeaverage conditionsbasic conditionsdetailed patternsbasic patternsdetailed

      script                = extrainfo moreenum currentcommand

      gateway           = gatewaynotfound gatewayfailure gatewaydbnotfound gatewayblocked

      sourceblocker = sourceblocker1 sourceblocker2 sourceblocker3

      xslttrransform  = xslttrransform1 xslttrransform2

      rephrase           = executionrephrase compilationrephrase

      qdbase             = qddpevents qdmrevents

      qdsmart            = qdbase qduserevents qdmessages qddns up querytimings

      qdall                  = qdsmart qdthread

      datasource       = datasourcebasic datasourceaverage datasourcedetailed

      external             = externalcomp externalext

      thread_id          = threadid


 Another practical example: let's say you don't want too much information in your log window, and decide to set the debug level to 2. It just so happens that this poses a problem with the Comprehension Info tab, as that tab requires special debug outputs (notably matcheraverage, found in debug level 5) to be able to present you with the rephrasing rules details and scores reliably. Normally, you would keep the debug level 5 and feel sorry for all the virtual paper being wasted and the virual forests becoming extinct, but now you know better! All you need to do is to change the setting to "1 matching rephrase", or even "1 executionrephrase matcheraverage" to be super conservative.

 

A few words about performance.

As you can imagine, outputting so much data to the screen or to a file takes up resources, so whenever performance is a concern, you want to be conservative about the level of debug. Here are two ways to help without hurting:

- if your agent has a good-size codebase, starting it up can take a bit of time depending what it loads. So in the SDK where you require numerous restarts, you don't want to add on top of that the cost of outputting huge quantities of debug output you don't need at start up.

Lo and behold! the  'debug-startup' option is your new friend. It tells the queryserver what debug level to adopt until it's fully started. In the SDK you use it by adding "--debug-startup FLAGS" to the Extra Options field in the agent's properties. **

 

- For a console agent already running and live, as noted before you want a pretty terse debug level due to the traffic, but you may need to change it on the fly to investigate a particular issue. For this, Buddyscript has a built-in procedure called SetDebugLevel()

+ setdebuglevel TAGS=AnythingStrong {MACRO_PROTECTED_MATCHING}

  - Changing the debug level to TAGS...

  call SetDebugLevel(TAGS)

 

However make sure you turn it back once you're done investigation! One safe way of implement in it is with the following code:

 

variable G_CHANGED_DEBUG_LEVEL = false

 

+ setdebuglevel TAGS=AnythingStrong {MACRO_PROTECTED_MATCHING}

  - Changing the debug level to TAGS...

  G_CHANGED_DEBUG_LEVEL = true

  call SetDebugLevel(TAGS)

 

procedure ABEndSessionProc()

  if G_CHANGED_DEBUG_LEVEL

    call SetDebugLevel("2")

 

This is assuming that your 'config' debug level is 2.

 

And that's it! Next time you have an issue for us to look at and we ask you to send us the log with debug level set to 'currentcommand' (this one outputs the whole execution of the code), you'll know why and how.

Thanks for reading the blog and come back soon!

 

** an even better friend in that regard is the command "!ddlreload" in the conversation window, that doesn't restart the agent but only reloads the domains and packages that changed since the last reload. Be advised though that it won't always reload everything correctly, so a restart once in a while is recommanded.

Type "?" to get a list of all those useful and lesser-known commands.