Make async stacktraces less verbose (#21091)
* Name iterators something human readable
Remove intermediate async procs from stacktraces
Clean async traceback message from reraises message
* Remove unused import/variable
* Fix failing tests
Don't add {.stackTrace: off.} to anonymous procs (They already don't appear in stacktrace)
* Fix failing tests in pragma category
Now check that the nim is a routine type first so we don't run into any assertion defects
* Hide stack trace pragma in docs and update doc tests
User doesn't need to know if something won't appear so this more becomes verbose noise
If this is a bad idea we can always add a `when defined(nimdoc)` switch so we don't add {.stackTrace: off.} to the Future[T] returning proc for docs
This commit is contained in:
parent
91ce8c385d
commit
d88f46df38
6 changed files with 33 additions and 63 deletions
|
|
@ -619,7 +619,9 @@ proc isHideable(config: ConfigRef, n: PNode): bool =
|
||||||
# xxx compare `ident` directly with `getIdent(cache, wRaises)`, but
|
# xxx compare `ident` directly with `getIdent(cache, wRaises)`, but
|
||||||
# this requires a `cache`.
|
# this requires a `cache`.
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkExprColonExpr: result = n[0].kind == nkIdent and n[0].ident.s in ["raises", "tags", "extern", "deprecated", "forbids"]
|
of nkExprColonExpr:
|
||||||
|
result = n[0].kind == nkIdent and
|
||||||
|
n[0].ident.s.nimIdentNormalize in ["raises", "tags", "extern", "deprecated", "forbids", "stacktrace"]
|
||||||
of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"]
|
of nkIdent: result = n.ident.s in ["gcsafe", "deprecated"]
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,29 +329,21 @@ proc `$`*(stackTraceEntries: seq[StackTraceEntry]): string =
|
||||||
if leftLen > longestLeft:
|
if leftLen > longestLeft:
|
||||||
longestLeft = leftLen
|
longestLeft = leftLen
|
||||||
|
|
||||||
var indent = 2
|
|
||||||
# Format the entries.
|
# Format the entries.
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
let (filename, procname) = getFilenameProcname(entry)
|
let (filename, procname) = getFilenameProcname(entry)
|
||||||
|
|
||||||
if procname == "":
|
if procname == "" and entry.line == reraisedFromBegin:
|
||||||
if entry.line == reraisedFromBegin:
|
break
|
||||||
result.add(spaces(indent) & "#[\n")
|
|
||||||
indent.inc(2)
|
|
||||||
elif entry.line == reraisedFromEnd:
|
|
||||||
indent.dec(2)
|
|
||||||
result.add(spaces(indent) & "]#\n")
|
|
||||||
continue
|
|
||||||
|
|
||||||
let left = "$#($#)" % [filename, $entry.line]
|
let left = "$#($#)" % [filename, $entry.line]
|
||||||
result.add((spaces(indent) & "$#$# $#\n") % [
|
result.add((spaces(2) & "$# $#\n") % [
|
||||||
left,
|
left,
|
||||||
spaces(longestLeft - left.len + 2),
|
|
||||||
procname
|
procname
|
||||||
])
|
])
|
||||||
let hint = getHint(entry)
|
let hint = getHint(entry)
|
||||||
if hint.len > 0:
|
if hint.len > 0:
|
||||||
result.add(spaces(indent+2) & "## " & hint & "\n")
|
result.add(spaces(4) & "## " & hint & "\n")
|
||||||
|
|
||||||
proc injectStacktrace[T](future: Future[T]) =
|
proc injectStacktrace[T](future: Future[T]) =
|
||||||
when not defined(release):
|
when not defined(release):
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,8 @@ proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimN
|
||||||
template createCb(retFutureSym, iteratorNameSym,
|
template createCb(retFutureSym, iteratorNameSym,
|
||||||
strName, identName, futureVarCompletions: untyped) =
|
strName, identName, futureVarCompletions: untyped) =
|
||||||
bind finished
|
bind finished
|
||||||
|
|
||||||
var nameIterVar = iteratorNameSym
|
var nameIterVar = iteratorNameSym
|
||||||
proc identName {.closure.} =
|
proc identName {.closure, stackTrace: off.} =
|
||||||
try:
|
try:
|
||||||
if not nameIterVar.finished:
|
if not nameIterVar.finished:
|
||||||
var next = nameIterVar()
|
var next = nameIterVar()
|
||||||
|
|
@ -151,6 +150,10 @@ proc asyncSingleProc(prc: NimNode): NimNode =
|
||||||
result[0][0] = quote do: Future[void]
|
result[0][0] = quote do: Future[void]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
if prc.kind in RoutineNodes and prc.name.kind != nnkEmpty:
|
||||||
|
# Only non anonymous functions need/can have stack trace disabled
|
||||||
|
prc.addPragma(nnkExprColonExpr.newTree(ident"stackTrace", ident"off"))
|
||||||
|
|
||||||
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
||||||
error("Cannot transform this node kind into an async proc." &
|
error("Cannot transform this node kind into an async proc." &
|
||||||
" proc/method definition or lambda node expected.", prc)
|
" proc/method definition or lambda node expected.", prc)
|
||||||
|
|
@ -209,7 +212,7 @@ proc asyncSingleProc(prc: NimNode): NimNode =
|
||||||
# -> {.pop.}
|
# -> {.pop.}
|
||||||
# -> <proc_body>
|
# -> <proc_body>
|
||||||
# -> complete(retFuture, result)
|
# -> complete(retFuture, result)
|
||||||
var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
|
var iteratorNameSym = genSym(nskIterator, $prcName & " (Async)")
|
||||||
var procBody = prc.body.processBody(retFutureSym, futureVarIdents)
|
var procBody = prc.body.processBody(retFutureSym, futureVarIdents)
|
||||||
# don't do anything with forward bodies (empty)
|
# don't do anything with forward bodies (empty)
|
||||||
if procBody.kind != nnkEmpty:
|
if procBody.kind != nnkEmpty:
|
||||||
|
|
@ -251,9 +254,10 @@ proc asyncSingleProc(prc: NimNode): NimNode =
|
||||||
# friendlier stack traces:
|
# friendlier stack traces:
|
||||||
var cbName = genSym(nskProc, prcName & NimAsyncContinueSuffix)
|
var cbName = genSym(nskProc, prcName & NimAsyncContinueSuffix)
|
||||||
var procCb = getAst createCb(retFutureSym, iteratorNameSym,
|
var procCb = getAst createCb(retFutureSym, iteratorNameSym,
|
||||||
newStrLitNode(prcName),
|
newStrLitNode(prcName),
|
||||||
cbName,
|
cbName,
|
||||||
createFutureVarCompletions(futureVarIdents, nil))
|
createFutureVarCompletions(futureVarIdents, nil)
|
||||||
|
)
|
||||||
outerProcBody.add procCb
|
outerProcBody.add procCb
|
||||||
|
|
||||||
# -> return retFuture
|
# -> return retFuture
|
||||||
|
|
|
||||||
|
|
@ -503,7 +503,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="asyncFun1-procs-all">
|
<div id="asyncFun1-procs-all">
|
||||||
<div id="asyncFun1">
|
<div id="asyncFun1">
|
||||||
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun1"><span class="Identifier">asyncFun1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">int</span><span class="Other">]</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span>
|
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun1"><span class="Identifier">asyncFun1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">int</span><span class="Other">]</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">stackTrace</span><span class="Other">:</span> <span class="DecNumber">false</span><span class="Other">,</span>
|
||||||
|
<span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span>
|
||||||
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
||||||
|
|
@ -515,8 +516,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="asyncFun2-procs-all">
|
<div id="asyncFun2-procs-all">
|
||||||
<div id="asyncFun2">
|
<div id="asyncFun2">
|
||||||
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun2"><span class="Identifier">asyncFun2</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span>
|
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun2"><span class="Identifier">asyncFun2</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">stackTrace</span><span class="Other">:</span> <span class="DecNumber">false</span><span class="Other">,</span> <span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span>
|
||||||
<span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -527,8 +528,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="asyncFun3-procs-all">
|
<div id="asyncFun3-procs-all">
|
||||||
<div id="asyncFun3">
|
<div id="asyncFun3">
|
||||||
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun3"><span class="Identifier">asyncFun3</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span>
|
<dt><pre><span class="Keyword">proc</span> <a href="#asyncFun3"><span class="Identifier">asyncFun3</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">stackTrace</span><span class="Other">:</span> <span class="DecNumber">false</span><span class="Other">,</span> <span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span>
|
||||||
<span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
<span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">forbids</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'"
|
errormsg: "'anotherGCSafeAsyncProc (Async)' is not GC-safe as it calls 'asyncGCUnsafeProc'"
|
||||||
cmd: "nim c --threads:on $file"
|
cmd: "nim c --threads:on $file"
|
||||||
file: "asyncmacro.nim"
|
file: "asyncmacro.nim"
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -67,51 +67,22 @@ import re
|
||||||
const expected = """
|
const expected = """
|
||||||
b failure
|
b failure
|
||||||
Async traceback:
|
Async traceback:
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
|
tasync_traceback\.nim\(\d+?\) tasync_traceback
|
||||||
asyncmacro\.nim\(\d+?\)\s+?a
|
tasync_traceback\.nim\(\d+?\) a \(Async\)
|
||||||
asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue
|
tasync_traceback\.nim\(\d+?\) b \(Async\)
|
||||||
## Resumes an async procedure
|
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?aIter
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?b
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?bNimAsyncContinue
|
|
||||||
## Resumes an async procedure
|
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?bIter
|
|
||||||
#\[
|
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?a
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?aNimAsyncContinue
|
|
||||||
## Resumes an async procedure
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?aIter
|
|
||||||
asyncfutures\.nim\(\d+?\)\s+?read
|
|
||||||
\]#
|
|
||||||
Exception message: b failure
|
Exception message: b failure
|
||||||
|
|
||||||
|
|
||||||
bar failure
|
bar failure
|
||||||
Async traceback:
|
Async traceback:
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
|
tasync_traceback\.nim\(\d+?\) tasync_traceback
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?waitFor
|
asyncdispatch\.nim\(\d+?\) waitFor
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?poll
|
asyncdispatch\.nim\(\d+?\) poll
|
||||||
## Processes asynchronous completion events
|
## Processes asynchronous completion events
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?runOnce
|
asyncdispatch\.nim\(\d+?\) runOnce
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
|
asyncdispatch\.nim\(\d+?\) processPendingCallbacks
|
||||||
## Executes pending callbacks
|
## Executes pending callbacks
|
||||||
asyncmacro\.nim\(\d+?\)\s+?barNimAsyncContinue
|
tasync_traceback\.nim\(\d+?\) bar \(Async\)
|
||||||
## Resumes an async procedure
|
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?barIter
|
|
||||||
#\[
|
|
||||||
tasync_traceback\.nim\(\d+?\)\s+?tasync_traceback
|
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?waitFor
|
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?poll
|
|
||||||
## Processes asynchronous completion events
|
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?runOnce
|
|
||||||
asyncdispatch\.nim\(\d+?\)\s+?processPendingCallbacks
|
|
||||||
## Executes pending callbacks
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?fooNimAsyncContinue
|
|
||||||
## Resumes an async procedure
|
|
||||||
asyncmacro\.nim\(\d+?\)\s+?fooIter
|
|
||||||
asyncfutures\.nim\(\d+?\)\s+?read
|
|
||||||
\]#
|
|
||||||
Exception message: bar failure
|
Exception message: bar failure
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue