Debugging¶
q)) extra right parens mark suspended execution/s 'myerror Signal error, cut back stack :r exit suspended function with r as result \ abort execution and exit debugger .Q.bt dump backtrace & current frame information .Q.trp extends Trap At to collect backtrace -e \e error-trap mode
Errors¶
Uncaught errors are printed as follows (without the comments). Since V3.5.
q)2+"hi"
'type / error string
[0] 2+"hi" / stack frame index and source code
^ / caret indicates the primitive that failed
This will be augmented with file:line and function name, if such information is available.
q)myfun"hi" / myfun defined in test.q and loaded with \l
'type
[1] /kdb+3.5/test.q:5: myfun:{2+x} / note the full path name
^
Nested anonymous lambdas will inherit their enclosing function's name with the @
suffix.
q)f0:{{("hi";x+y)}[x*2;"there"]}
q)f0[2]
'type
[2] f0@:{("hi";x+y)}
^
q)\
A name error (global used as local) bytecode compiler error has location info.
q){a::1;a:1}
'a
[0] {a::1;a:1}
^
Debugger¶
Usually when an error happens inside a lambda the execution is suspended and you enter the debugger, as indicated by the additional )
following the normal
q)
prompt.
q)f:{g[x;2#y]}
q)g:{a:x*2;a+y}
q)f[3;"hello"]
'type
[2] g:{a:x*2;a+y}
^
q))
The debug prompt allows operating on values defined in the local scope.
q))a*4
24
You can use `
and .
freely to navigate up and down the stack.
q))` / up
[1] f:{g[x;2#y]}
^
q))`
[0] f[3;"hello"]
^
q)). / down
[1] f:{g[x;2#y]}
^
q))
In a debugger session, .z.ex
and .z.ey
are set to the failed primitive and its argument list.
q)).z.ex
+
q)).z.ey
6
"he"
Signal¶
'err
will signal err
from the deepest frame available, destroying it.
q))'myerror
'myerror
[1] f:{g[x;2#y]}
^
q))
Resume¶
When execution is suspended, :e
resumes with e
as the result of the failed operation. e
defaults to null ::
.
q)read0`:test.q
"/ test script"
"a:b:0"
"func:{1+x}"
"a:func`a"
"b:1"
q)\l test.q
'type
[3] <full path to file>/test.q:3: func:{1+x}
^
q)):42 / result of 1+x
q)a
42
q)b
1
Note that resume does not return from enclosing function
q){0N!"x+1 is ",string x+1;x}`asd
'type
[1] {0N!"x+1 is ",string x+1;x}
^
q)):17
"x+1 is 17"
`asd
Abort¶
Use \
to exit the debugger and abort execution.
q))\
q)
Debuggers may nest if an expression entered into a debug prompt signals an error. Nesting level is indicated by appending further parentheses to the q))
prompt. Each \
exits a single debug level.
q)){x+y}[a;y]
'type
[5] {x+y}
^
q)))x
6
q)))\ / exit the inner debugger
q))\ / exit the outer debugger
q)
Stack frames¶
Backtrace¶
.Q.bt[]
will dump the backtrace to stdout at any point during execution or debug.
It will highlight the current stack frame with >>
. (Since V4.0 2020.03.17.)
q)g:{a:x*2;a+y}
q)f:{{.Q.bt[];x*2}x+1}
q)f 4
[2] f@:{.Q.bt[];x*2}
^
[1] f:{{.Q.bt[];x*2}x+1}
^
[0] f 4
^
10
q)g[3;"hello"]
'type
[1] g:{a:x*2;a+y}
^
q)).Q.bt[]
>>[1] g:{a:x*2;a+y}
^
[0] g[3;"hello"]
^
The debugger itself occupies a stack frame, but its source is hidden.
Where¶
Debugger command &
displays current frame information.
(Since V4.0 2020.03.17.)
q))&
'type
[1] g:{a:x*2;a+y}
^
Context¶
The debugger restores the original namespace and language (q or k) setting for each frame.
View calculations and system commands, including \l
, correspond to individual debug stack frames.
.d1 ).Q.bt`
>>[3] t0.k:8: va::-a
^
[2] t1.q:8: vb::va*3
^
[1] t1.q:7: vc::vb+2
^
[0] 2+vc
^
Trap¶
.Q.trp[f;x;g]
extends trap at
(@[f;x;g]
) to collect backtrace. Along with the error string, g
gets called with the backtrace object as a second argument. You can format it with .Q.sbt
to make it legible.
q)f:{`hello+x}
q) / print the formatted backtrace and error string to stderr
q).Q.trp[f;2;{2@"error: ",x,"\nbacktrace:\n",.Q.sbt y;-1}]
error: type
backtrace:
[2] f:{`hello+x}
^
[1] (.Q.trp)
[0] .Q.trp[f;2;{2@"error: ",x,"\nbacktrace:\n",.Q.sbt y;-1}]
^
-1
q)
.Q.trp
can be used for remote debugging.
q)h:hopen`::5001 / f is defined on the remote
q)h"f `a"
'type / q's ipc protocol can only get the error string back
[0] h"f `a"
^
q) / a made up protocol: (0;result) or (1;backtrace string)
q)h".z.pg:{.Q.trp[(0;)@value@;x;{(1;.Q.sbt y)}]}"
q)h"f 3"
0 / result
,9 9 9
q)h"f `a"
1 / failure
" [4] f@:{x*y}\n ^\n [3..
q)1@(h"f `a")1; / output the backtrace string to stdout
[4] f@:{x*y}
^
[3] f:{{x*y}[x;3#x]}
^
[2] f `a
^
[1] (.Q.trp)
[0] .z.pg:{.Q.trp[(0;)@enlist value@;x;{(1;.Q.sbt y)}]}
^
Errors thrown by parse
show up in .Q.trp
with location information.
q).Q.trp[parse;"2+2;+2";{1@.Q.sbt 2#y}];
[3] 2+2;+2
^
[2] (.q.parse)
Error trap modes¶
At any point during execution, the behavior of Signal ('
) is determined by the internal error-trap mode:
0 abort execution (set by Trap: @ or .)
1 suspend execution and run the debugger
2 collect stack trace and abort (set by .Q.trp)
Mode 2 (dump stack trace) is now default for loading scripts non-interactively (e.g. with -q
).
During abort, the stack is unwound up to the nearest trap (@
or .
or .Q.trp
). The error-trap mode is always initially set to 1 for console input and to 0 for sync message processing.
\e
sets the mode applied before async and HTTP callbacks run. Thus, \e 1
will cause the relevant handlers to break into the debugger, while \e 2
will dump the backtrace either to the server console (for async), or into the socket (for HTTP).
q)\e 2
q)'type / incoming async msg signals 'type
[2] f@:{x*y}
^
[1] f:{{x*y}[x;3#x]}
^
[0] f `a
^
q)\e 1
q)'type
[2] f@:{x*y}
^
q)) / the server is suspended in a debug session
Keywords
Q is an embedded domain-specific language. Many of its keywords are defined as lambdas or projections, and can suspend as described.
Display,
show
Q for Mortals 3: ยง10.2 Debugging