-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add trace
functionality
#244
base: hkmc2
Are you sure you want to change the base?
Conversation
bettern calling msg
need to fix: avoid "toString()"
d6a43aa
to
124f84d
Compare
124f84d
to
23cbac2
Compare
… current block is set * add tests this make sure the indents are correct
Obviously you shouldn't pollute every single diff test block with a useless call to |
There is no need to use |
Thanks, I just realized that I could have done this better without polluting every single diff test block by using I originally wrote this to reset indentation at the beginning of every diff test block because if a previous block throws an error at a higher indent level, blocks after that will start the trace log at a wrong level (this is because functions are instrumented when they are declared in blocks with flag
Thanks I see, I will also make the change to remove unnecessary |
I have made the changes to cleanup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, great work.
Some remarks, though:
-
I actually preferred the way without
finally
, as it's much less invasive and likely to add much less runtime overhead. Can we move back to it? Before a block that contains tracing, inJSBackendDiffMaker
you could always justhost.send
a nodeJS command to manually reset the indent, as inhost.send("globalThis.Predef.TraceLogger.indent = 0")
-
I'd prefer it if tracing was disabled in non-tracing blocks, even when the block's execution involves functions that were instrumented. You could simply add a Boolean flag to
Predef.TraceLogger
(or set the indent to -1, tho I don't like sentinel values) which is alwaysfalse
unless we're tracing. -
I don't like the "
calling
"/"return
" pair. Repetitive but not very easy to parse visually. Have you considered using something like the following syntax?f(1,1)(-2) //│ > CALL g(-2) //│ > | CALL g(-1) //│ > | => 42 //│ > => 42 //│ = 44
…ion level in the output logs)
… blocks calling functions defined in traced blocks will show trace by adding an `enabled` flag to predef.tracelogger
Thanks for your suggestions and instructions! I have pushed the changes to avoid |
:traceJS | ||
:re | ||
h(3) | ||
//│ ═══[RUNTIME ERROR] Error: Function 'plus' expected 2 arguments but got 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any idea why we're not seeing the trace up to the runtime error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because when the ReplHost encounters an error, only the error messages are kept in its replies (
mlscript/hkmc2/jvm/src/test/scala/hkmc2/ReplHost.scala
Lines 197 to 205 in 9986302
final case class Error(syntax: Bool, message: Str) extends Reply { | |
override def map(f: Str => Reply): Reply = this | |
override def toString(): Str = | |
if syntax then | |
s"[syntax error] $message" | |
else | |
s"[runtime error] $message" | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that would be great, if you don't mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I have pushed a commit to address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
One last tweak, though: can we get the runtime error message after the output? Currently, it appears out of logical order:
//│ ═══[RUNTIME ERROR] Error: Function 'plus' expected 2 arguments but got 1
//│ CALL h(3)
//│ | CALL g(3)
//│ | | CALL g(2)
//│ | | | CALL g(1)
//│ | | | | CALL g(0)
It should be:
//│ CALL h(3)
//│ | CALL g(3)
//│ | | CALL g(2)
//│ | | | CALL g(1)
//│ | | | | CALL g(0)
//│ ═══[RUNTIME ERROR] Error: Function 'plus' expected 2 arguments but got 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I have pushed the change. I also added the missing ">" at the start of each line of the output, so that now it's:
//│ > CALL h(3)
//│ > | CALL g(3)
//│ > | | CALL g(2)
//│ > | | | CALL g(1)
//│ > | | | | CALL g(0)
//│ ═══[RUNTIME ERROR] Error: Function 'plus' expected 2 arguments but got 1
@@ -108,6 +108,10 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: | |||
// Otherwise, it is considered a simple runtime error. | |||
raise(ErrorReport(msg"${message}" -> N :: Nil, | |||
source = Diagnostic.Source.Runtime)) | |||
if traceJS.isSet then | |||
output("All outputs:") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's with this weird "All outputs" thing? Why would the logging output preceding an error only appear when traceJS.isSet
? I don't understand how you make this sort of decisions. Is there a relevant rationale, from the point of view of the user of the system?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PS: Implementation or historical details are not relevant rationales.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you were not thinking about the fact that the output is useful even when no tracing is ongoing. Indeed, that's the output of printing stuff, which is currently being silenced when errors occurs (very annoying).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I previously chose to only show all outputs when traceJS
is set because I found out that in most of the tests, "all output"s are just the duplicates of the error messages:
But indeed I now see that the output is useful even when no tracing is ongoing, I think maybe I can just not print out the lines showing duplicated messages and "undefined"? Or maybe I can another flag which controls whether to print all output when error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe I can another flag which controls whether to print all output when error?
No, please! Not another flag. Again, I ask you to think about the semantics of what we're implementing here. How could adding a flag like this that controls low-level details in surprising ways be any good?
Rather, you should figure out why the runtime error appears part of the retrieved output. I believe errors are actually guarded by some invisible unicode characters. Just check how this part of the code works and simply fix it. It's not very complicated at all, as far as I remember.
And of course we should also not print the final undefined
. I'm confident you can figure it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I have just pushed the changes to filter error messages and final undefined
in the retrieved output for ReplHost.Error
. Following the implementation in ReplHost.scala
I realized that uncaught errors are not guarded by special invisible characters, so I just filter them using the index of substring "Uncaught " (here and here); And others are filtered out by using the invisible character
TODO:avoid obscure tracing outputs like here, which is caused by thetoString()
methods, which are called to compose tracing messages.cleanupThe to avoid obscure tracing outputs and non-termination caused by
toString()
, I currently useutil.inspect
to show the argument and return result info in the tracing messages.