Using the Debug service

The Debug service sets property breakpoints: it watches one property of one node and acts when the value meets a condition.

It is separate from the Overwatch service because the two do different kinds of thing. Overwatch reports on a running application. A breakpoint intervenes in one — it can halt the process in an attached debugger at the assignment that changed a property, or run a console command when it changes. That is why it has its own configuration key, ServiceDebugEnabled, and why its commands use the debug.* prefix rather than overwatch.*.

Note

ServiceDebugEnabled is independent of ServiceOverwatchEnabled: the debug commands are available with the Overwatch service switched off, and can be switched off while Overwatch runs.

The one part that does depend on Overwatch is the screenshot action, which captures through whichever service owns the framebuffer. With Overwatch disabled, that action reports that no capture source is available, and debug.breakpointscreenshot then has nothing to return. The other five commands are unaffected. To capture the frames leading up to a breakpoint instead, attach capture.stop with debug.breakcommand and let the capture service ring hold the run-up.

debug.breakprop <path> <property> <op> <value|$"..."> [once] [hitcount:N] [actions]
                                                                 Add a property breakpoint.
debug.breakpoints                                            Get property breakpoints
                                                                 as JSON.
debug.removebreakpoint <id>                                  Remove a breakpoint by ID.
debug.enablebreakpoint <id> <0|1>                            Activate or deactivate a
                                                                 breakpoint.
debug.breakcommand <id> <command>                            Run a console command when
                                                                 a breakpoint triggers.
debug.clearbreakpoints                                       Remove all breakpoints.
debug.breakpointscreenshot                                   Fetch the capture a
                                                                 breakpoint took.

A performance watcher runs once per frame. A breakpoint instead rides a Kanzi property notification handler, which fires inside the assignment that changed the value. With the break action and a debugger attached, execution therefore stops on the code that wrote the property. That is what makes a breakpoint useful for finding who set a value rather than only that something set it.

<op> is one of eq, neq, below, above, beloweq, aboveeq, or the equivalent symbol (==, !=, <, >, <=, >=). float and int properties accept all of them; bool, string, Vector2, Vector3 and Vector4 accept eq and neq only. Vector values are comma-separated with exactly one number per component — 1,0,0 for a Vector3. A missing or extra component is rejected rather than read as 0, and so is a number outside the property type’s range: an int target beyond 32 bits, or a float target that is not finite.

The property name can be unqualified: Opacity resolves to Node.Opacity. Because a node path can contain spaces, debug.breakprop parses its arguments from the right — the property, operator and value are always single tokens, so whatever precedes them is the path, unquoted. A value that is not a single plain token is written as one $"..." literal (see below):

debug.breakprop /Screen/RootPage/Viewport 2D/Image Opacity below 0.5 break

Quoting the path is unnecessary for that reason, but debug.breakprop accepts it — it strips one layer of matching single or double quotes, the same way overwatch.props does, so a path copied from a command that needed quotes works here too. An unbalanced quote stays in place rather than being guessed at, so the resulting Node not found names exactly what you asked for.

Warning

Quotes do not delimit the value — write a $"..." literal instead. debug.breakprop /A/B Text eq "Hello" creates a breakpoint whose target is the seven-character string "Hello", quotes included. It is listed as armed and never fires, with no error, because any string is a valid target for a string property. Write a one-word target unquoted. Write any other target – one with a space, a line break, a tab or quotes, or one that spells an operator such as eq – as a $"..." string literal, which is decoded as JSON, as overwatch.setprop reads one (Setting any text: the string literal):

debug.breakprop /A/B TextConcept.Text eq $"Hello world" log
debug.breakprop /A/B TextConcept.Text eq $"line 1\nline 2" log

A literal is never read as the operator, once, hitcount:N or an action, so it is always the target. A path can also be given as one literal; the MCP add_breakpoint tool and the Web UI’s breakpoint form write the target and the path that way when they need to.

overwatch.setprop is not the precedent here despite appearances: it does not use this quote stripping at all, it uses a different argument reader that treats a leading quote as running to the end of the line. So overwatch.setprop "/A/B Opacity 5 reports a missing property name, where debug.breakprop keeps the quote in the path. The two commands agree on unquoted spaced paths and disagree on malformed quoting.

You can give actions as one comma-separated token or as separate words, and one breakpoint can carry several either way — log,screenshot and log screenshot are the same request. The separate-word form takes at most three trailing arguments in total, counting once and hitcount:N: ... 0.5 log screenshot once hitcount:3 is four and is rejected with the usage line, while the comma-packed ... 0.5 log,screenshot once hitcount:3 is three and parses. Pack the actions into one token when a breakpoint needs both modifiers as well. They run in a fixed order, with break last, so every diagnostic is in place before execution stops.

Note

The graphics API call logging actions - gfxlog and gfxframe, and the legacy gllog, gldump, glframe and glframedump spellings - are not available, because this Kanzi baseline has no call logging to drive. debug.breakprop recognizes all six names and rejects them with that explanation, rather than reporting them as an unknown action.

Action

Effect

break

Traps into an attached debugger. Without one, this is skipped and logged — raising a trap with nothing to catch it would terminate the application.

log

Logs the triggering value and leaves the application running. A tracepoint.

On a property that changes every frame, such as an animated one, this fills the log buffer and evicts everything else in it. Pair it with hitcount:N or once.

screenshot

Captures the default framebuffer on the next render, fetched with debug.breakpointscreenshot. Breakpoint captures have their own slot, so they never consume an overwatch.screenshot result. The slot holds one capture: while an image is waiting to be fetched, a later breakpoint’s screenshot is skipped rather than replacing it, and the log says which breakpoint’s capture is being kept. Fetching frees the slot. The frame that caught the condition first is the one worth keeping, and a capture discarded unread would be invisible.

command

Runs a console command. Attach the command with debug.breakcommand, which enables this action; it cannot be given to debug.breakprop, whose argument order has no room for free text. The command runs after the property write has returned, so any command can be a breakpoint command, nodetree.* and overwatch.dispatchmessage included. See When a breakpoint’s command runs.

hitcount:N triggers on every Nth matching change rather than every one, and once deactivates the breakpoint after its first trigger, leaving it listed but inert. N must be a non-negative whole number, and the target value must be readable as the property’s type and within its range — both are rejected outright, with a response that names the offending component and the accepted form, rather than quietly becoming 0 or wrapping, which would leave the listing showing a condition the breakpoint is not testing. The target is parsed once, when the breakpoint is created, and that parsed value is what every later property write is compared against.

debug.breakprop is stricter than overwatch.setprop about two values. It rejects inf and nan: exact equality never matches nan, and a breakpoint waiting on infinity is almost always a typo; to catch a property actually going infinite, use above 3.4e38. It also rejects a number too small to store, such as 1e-1000, which would become 0 while the listing still showed what you typed.

To break the tenth time a layout width is written, and stop there:

debug.breakprop /Screen/RootPage/Grid LayoutWidth above 100 once hitcount:10 break

To log every write of a state without stopping, and capture what the screen looked like:

debug.breakprop /Screen/RootPage Focused eq true log,screenshot

Note

The property needs no value beforehand. Registering the breakpoint creates the node’s property storage entry for it, so you can break on a property nothing has written yet and catch the first write to it — often the write worth catching.

The node itself must exist, because there is nothing to register the handler on otherwise. If no property type can be resolved for the name at all, the breakpoint is still created but reported with "notification": false, and never fires. debug.breakpoints shows the same flag, and the Monitor Web UI labels such a breakpoint Dormant — check the name against overwatch.props, then remove and add it again.

Note

The node path is resolved against every enumerated view root, matching each root’s own canonical path, so every path overwatch.nodes reports round-trips — including on a host with several roots, such as a service-hosted application with one view adapter per client. A path that names no node returns Node not found rather than silently answering for the first root. overwatch.props and overwatch.setprop share the same resolver.

When a breakpoint’s command runs

The condition is evaluated inside the property write, and the log, screenshot and break actions run there. The command action does not: it is queued on the Kanzi UI thread, like a command from a console, and runs after the write has returned, once the application handles its queued tasks.

That is what makes any command safe to run from a breakpoint. A command run inside the write would run while the node being written, and any parent going through its children, are still in the middle of a call. A command that changes the node tree, such as a nodetree.* command or ui 0, or that runs application logic, such as overwatch.dispatchmessage, could then destroy the node under its own write.

  • The command sees the application after the write: reading the property gives the new value.

  • When a breakpoint triggers several times before the queue is handled, its command runs once for each trigger, in the order of the triggers.

  • A command that writes the watched property again triggers the breakpoint again, and its command runs in the next frame, not inside the first one. Such a breakpoint repeats once per frame until its condition no longer holds; use once or hitcount:N to stop it.

  • The command’s output goes to the application log rather than to a client, as Breakpoint #<id>: ran '<command>' (result <n>) -> <output>.

Available commands

Command

Description

debug.breakprop

Adds a property breakpoint. Usage: debug.breakprop <path> <property> <op> <value> [once] [hitcount:N] [actions]

debug.breakpoints

Gets property breakpoints as JSON. notification: false marks a breakpoint that cannot fire.

debug.removebreakpoint

Removes a property breakpoint. Usage: debug.removebreakpoint <id>

debug.enablebreakpoint

Activates or deactivates a breakpoint, resetting its hit count when activating. Usage: debug.enablebreakpoint <id> <0|1>

debug.breakcommand

Attaches a console command to a breakpoint and enables its command action. Usage: debug.breakcommand <id> <command>. The command runs after the property write that triggered the breakpoint has returned; see When a breakpoint’s command runs.

debug.clearbreakpoints

Removes all property breakpoints.

debug.breakpointscreenshot

Fetches the screenshot a breakpoint’s screenshot action captured, and frees the single capture slot for the next breakpoint. debug.breakpoints reports the slot’s state as none, pending, ready or failed.

See also

Using the Overwatch service

Using the Capture service

Using the Monitor Web UI

Configuring Kanzi Monitor