summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@gmail.com>2017-11-25 14:55:57 +0000
committerAndreas Rumpf <rumpf_a@web.de>2017-12-28 09:21:22 +0100
commit9ca6afe73af8c187ea7786f7563ecc537ec31f51 (patch)
tree88837ccb10c86febd9d9ab985eedf6b25d55cfeb
parentf73015ad9ec6e977ca4b643ea9b03e164aeac431 (diff)
downloadNim-9ca6afe73af8c187ea7786f7563ecc537ec31f51.tar.gz
Refine the async tracebacks.
-rw-r--r--lib/pure/asyncfutures.nim36
-rw-r--r--tests/async/tasync_traceback.nim17
2 files changed, 41 insertions, 12 deletions
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index d78c6bcb7..d8385a9cb 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -256,16 +256,31 @@ proc processEntries(entries: seq[StackTraceEntry]): seq[StackTraceEntry] =
     result.add(entry)
     i.inc
 
+proc getHint(entry: StackTraceEntry): string =
+  ## We try to provide some hints about stack trace entries that the user
+  ## may not be familiar with, in particular calls inside the stdlib.
+  result = ""
+  case ($entry.procName).normalize()
+  of "cb0":
+    if cmpIgnoreStyle($entry.filename, "asyncmacro.nim") == 0:
+      return "Resumes an async procedure"
+  of "processpendingcallbacks":
+    if cmpIgnoreStyle($entry.filename, "asyncdispatch.nim") == 0:
+      return "Executes pending callbacks"
+  of "poll":
+    if cmpIgnoreStyle($entry.filename, "asyncdispatch.nim") == 0:
+      return "Processes asynchronous completion events"
+
 proc injectStacktrace[T](future: Future[T]) =
   when not defined(release):
-    const header = "Async traceback\n---------------\n"
+    const header = "Async traceback:\n"
 
     let originalMsg = future.error.msg
     if header in originalMsg:
       return
 
     let entries = getStackTraceEntries(future.error).processEntries()
-    future.error.msg = "\n" & header
+    future.error.msg = originalMsg & "\n" & header
 
     # Find longest filename & line number combo for alignment purposes.
     var longestLeft = 0
@@ -274,19 +289,26 @@ proc injectStacktrace[T](future: Future[T]) =
       if left.len > longestLeft:
         longestLeft = left.len
 
+    const indent = "  "
     # Format the entries.
     for entry in entries:
       let left = "$#($#)" % [$entry.filename, $entry.line]
-      future.error.msg.add("$1$2 $3\n" % [
+      future.error.msg.add("$#$#$# $#\n" % [
+        indent,
         left,
-        spaces(longestLeft - left.len + 2), $entry.procName])
+        spaces(longestLeft - left.len + 2),
+        $entry.procName
+      ])
+      let hint = getHint(entry)
+      if hint.len > 0:
+        future.error.msg.add(indent & "└─" & hint & "\n")
 
     future.error.msg.add("Exception message: " & originalMsg & "\n")
     future.error.msg.add("Exception type: ")
 
-    # For debugging purposes TODO...
-    for entry in getStackTraceEntries(future.error):
-      future.error.msg.add "\n" & $entry
+    # # For debugging purposes
+    # for entry in getStackTraceEntries(future.error):
+    #   future.error.msg.add "\n" & $entry
 
 proc read*[T](future: Future[T] | FutureVar[T]): T =
   ## Retrieves the value of ``future``. Future must be finished otherwise
diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim
index dc9226617..c69721f39 100644
--- a/tests/async/tasync_traceback.nim
+++ b/tests/async/tasync_traceback.nim
@@ -1,6 +1,13 @@
 discard """
   exitcode: 0
-  output: ""
+  output: '''
+b failure
+Async traceback:
+  tasync_traceback.nim(49) tasync_traceback
+  tasync_traceback.nim(47) a
+  tasync_traceback.nim(44) b
+Exception message: b failure
+Exception type:'''
 """
 import asyncdispatch
 
@@ -40,7 +47,7 @@ proc a(): Future[int] {.async.} =
   return await b()
 
 let aFut = a()
-# try:
-discard waitFor aFut
-# except Exception as exc:
-#   echo exc.msg
+try:
+  discard waitFor aFut
+except Exception as exc:
+  echo exc.msg