Debugging Wrapper
The /lib/dbug.hoon agent wrapper adds support to view the state of a Gall agent. It is applied to an existing Gall agent as a single drop-in line, %- agent:dbug.
Before we look at the code, let's consider the functionality it exposes. By supplying %- agent:dbug, an associated +dbug generator can be invoked against the agent state.
For instance, using the %azimuth agent, we can expose the current state of the agent:
> :azimuth +dbug
[ %7
url=~.
net=%default
refresh=~m5
whos={}
nas=[%0 points={} operators={} dns=<||>]
own={}
spo={}
logs=~
sap=[%0 id=[hash=0x0 number=0] nas=[%0 points={} operators={} dns=<||>] owners={} sponsors={}]
]
> :azimuth +dbug %bowl
> [ [our=~zod src=~zod dap=%azimuth]
[wex={} sup={}]
act=3
eny
0v1rn.n49dr.2u8t5.h7be5.6dcq7.9hon5.6m3pr.3hcb8.u7tmv.qddpq.kent7.1ftc7.9tao6.hfsht.4i0c3.ak3t7.t8d8j.nn4eb.b7eh3.4d5pr.t8ftg
now=~2023.2.3..20.03.23..f60e
byk=[p=~zod q=%base r=[%da p=~2023.1.26..02.41.25..926a]]
]
> :azimuth +dbug [%incoming ~]
> no matching subscriptions
> :azimuth +dbug [%state '(lent whos)']
> 0There are four actions exposed by the wrapper via the +dbug generator:
:app +dbugexposes the entire state, just dumping the current agent state.:app +dbug %bowlshows the agent's$bowl. The Gall$bowlconsists of:+$ bowl :: standard app state $: $: our=ship :: host src=ship :: guest dap=term :: agent == :: $: wex=boat :: outgoing subs sup=bitt :: incoming subs == :: $: act=@ud :: change number eny=@uvJ :: entropy now=@da :: current time byk=beak :: load source == == :::app +dbug [%state 'hoon']exposes data in the state, including evaluated Hoon like(lent values).:app +dbug [?(%incoming outgoing) specifics]reveals details about the subscriptions.
The Code
As we examine this code, there are two particularly interesting aspects:
How
/lib/dbug.hoonmodifies an agent's arms by adding functionality over the top of them.How
/gen/dbug.hoonutilizes the modified arms with an elegant and simple invocation.
There is also extensive use of $tank/$tang formatted error messaging.
How the library works
By applying this door builder using %- censig, the +on-poke and +on-peek arms can be modified. (In fact, all of the arms can be modified but most of the arms are pass-throughs to the modified agent.)
+on-poke
+on-pokeThe +on-poke arm has several branches added to it after a check to see whether it is being used through the +dbug generator. If it isn't (as determined by the associated $mark), then the poke is passed through to the base agent.
?. ?=(%dbug mark)
=^ cards agent (on-poke:ag mark vase)
[cards this]The following ?- wuthep handles the input arguments: %state is the most interesting code in this library. The code first checks whether the base agent has a /dbug/state peek endpoint already (in which case it passes it through), otherwise it evaluates the requested Hoon expression against the agent's state (obtained via +on-save:ag).
%state
=? grab.dbug =('' grab.dbug) '-'
=; product=^vase
[(sell product)]~
=/ state=^vase
:: if the underlying app has implemented a /dbug/state scry endpoint,
:: use that vase in place of +on-save's.
::
=/ result=(each ^vase tang)
(mule |.(q:(need (need (on-peek:ag /x/dbug/state)))))
?:(?=(%& -.result) p.result on-save:ag)
%+ slap
(slop state !>([bowl=bowl ..zuse]))
(ream grab.dbug)This branch includes the use of a rare =? tiswut conditional leg change and the reversed =/ tisfas, =; tismic. There is also some direct compilation of $cords taking place:
+sellis a$vasepretty-printer.+slopconses two$vases together as a cell.+slapcompiles a Hoon expression and produces a$vaseof the result.+reamparses a$cordto a Hoon expression.
+on-peek
+on-peekThe +on-peek arm adds several peek endpoints which expose the state (via +on-save:ag) and the subscriptions.
> .^(noun %gx /(scot %p our)/azimuth/(scot %da now)/dbug/subscriptions/noun)
[0 0]How the generator works
The generator explicitly injects the %dbug mark in its return +cask ([mark noun]). This is a valid if uncommon operation, and it works here because the mark is never used as a transforming gate but only as a marker to see whether the arms need to pass through the values. The no-argument input is routed through the %state with an empty $cord.
:- %dbug
?- args
~ [%state '']
[@ ~] ?-(what.args %bowl [%bowl ~], %state [%state ''])
[[@ *] ~] poke.args
==Library authors should consider augmenting developer capabilities by exposing appropriate functionality using a wrapper agent similar to /lib/dbug.
Last updated