When you get a stack trace from exception you get files and line numbers. I need something like this for my reporting, so I could get to the cause very fast.
I am looking in particular for LINE and FILE macro. Is there anything like this in Scala?
There is no such macro neither in Scala nor in Java. Of course the line number information is stored in the bytecode (also for debugging purposes) but there is no API to obtain it.
Stack traces with class names and line numbers are generated via native Throwable.fillInStackTrace(). Logging libraries might also use Thread.getStackTrace().
In both cases it boils down to parse stack trace and find our current location. Note that generating stack trace is time-consuming and should be avoided.
The sourcecode library is based on macros and provides metadata at compile-time.
Example (taken from their page):
object Main extends App {
def log(message: String)(implicit line: sourcecode.Line, file: sourcecode.File) =
println(s"${file.value}:${line.value} $message")
log("foo")
}
This will print:
/Users/jhoffmann/Development/sourcecode/src/main/scala/Main.scala:5 foo
You can use the implicits anywhere in your code.
The is a project to provide a macro capability in Scala.
Perhaps you could approach the project team to discuss what you need
Related
I'm frustrated by unintelligible stacktraces when my Scala.js code throws an exception. I thought I had a solution using a Javascript library (see Getting a scala stacktrace) but it breaks too often.
How do you extract meaning (where the program broke; how it got there -- in terms of the Scala code) from a stacktrace like the following. Or am I doing something wrong to even get an untranslated stacktrace?
Take a look at this code I wrote a while back in my youi framework: https://github.com/outr/youi/tree/e66dc36a12780fa8941152d07de9c3a52d28fc10/app/js/src/main/scala/io/youi/app/sourceMap
It is used to reverse JS stack traces to Scala stack traces. In youi I send the errors to the server so I can monitor browser errors that occur with the complete traceback.
Brief Overview
source-map.js
You need source-map.js to parse the js.map file that Scala.js
generated when it compiled your code. See:
https://github.com/mozilla/source-map
Load the js.map file via Ajax
The SourceMapConsumer needs a js.Object (JSON) of the js.map file. See https://github.com/outr/youi/blob/e66dc36a12780fa8941152d07de9c3a52d28fc10/app/js/src/main/scala/io/youi/app/sourceMap/ErrorTrace.scala#L58 for an example of loading via youi's Ajax features.
Process the Throwable
The trace represents line and columns in the JS file and you can pass
that information to SourceMapConsumer to get the original Scala line
numbers back (see SourceMapConsumer.originalPositionFor). See
ErrorTrace.toCause
(https://github.com/outr/youi/blob/e66dc36a12780fa8941152d07de9c3a52d28fc10/app/js/src/main/scala/io/youi/app/sourceMap/ErrorTrace.scala#L98)
for an example iterating over the Throwable's trace elements.
Handling Errors
Now that you have the capacity to process JavaScript errors and
convert them back to Scala traces, you need to actually receive the
errors. If you want to globally handle uncaught errors set a function
to window.onerror to capture errors. As of this writing, the
function signature in Scala.js isn't ideal for handling all
information, so in youi I use js.Dynamic to set it to what I need
(see:
https://github.com/outr/youi/blob/e66dc36a12780fa8941152d07de9c3a52d28fc10/app/js/src/main/scala/io/youi/app/ClientApplication.scala#L35).
Also, notice that in ErrorTrace it supports multiple incoming types
of errors (ErrorEvent, Throwable, and a more generic scenario).
This is because in JavaScript the errors come in different ways based
on what's happening. This is a fairly complex topic, and why I
created this functionality in youi to simplify things.
Not nearly as brief an overview as I would have liked, but this isn't a simple problem to solve. The source-map GitHub project (https://github.com/mozilla/source-map) has decent documentation and is what I used originally to write my solution (with some added trial and error). If the information I've provided is incomplete I'd recommend reading more there as it should provide the majority of information, and probably better explained.
Is there any way to find classes/objects that extend a certain class in sbt in the sources?
I played around with https://github.com/ruippeixotog/sbt-classfinder but that is only good for Compile and Test it seems.
What I intend to do is:
Find all classes that extends StyleSheet.Standalone (from
https://github.com/japgolly/scalacss/)
"Compile" (*) (object.render[TypedTag[String]] them and put the output in a specific folder
(*) Actually I want to invoke the render method on each of them and put the output (a string) into a x.css file.
I believe that sbt-classfinder does exactly what you have asked for. If you want more from this question, you will need to be more specific about why it didn't work for you or what you want that it does not provide.
You said:
I want to invoke the render method on each [class that extends StyleSheet.Standalone] and put the output (a string) into a x.css file.
The first example in the sbt-classfinder README shows how to find a class "marked with the annotation QuickRun" and execute it, which is fairly close to that and should get you started..
When my scala-js code throws an error, I'd like to send a sensible stacktrace back to my server to put in the logs. By "sensible stacktrace" I mean something that gives the Scala methods, filenames, and line numbers rather than the transpiled javascript code.
I've made good progress by getting the source map and using the Javascript source-map library (https://github.com/mozilla/source-map) to translate each element of the stacktrace from javascript to the corresponding Scala code.
My issue: I need the column number of the javascript code that threw the error but don't see how to obtain it. Printing a StackTraceElement gives a result similar to
oat.browser.views.query.QueryRunView$.renderParamsTable$1(https://localhost:9443/assets/browser-fastopt.js:34787:188)
I need the "188" at the end of the line but don't see how to get it other than calling toString and parsing the result. Looking at the StackTraceElement code, the column number is a private variable with nothing in the API to access it.
Is there another approach to this that I'm completely overlooking? Anything built into scala-js that converts a javascript stacktrace to a Scala stacktrace?
I subsequently found the StackTraceJS library which does what I needed. I combined a ScalaJS facade for it with a facade for JSNlog to come up with a package that meets my needs pretty well. See jsnlog-facade. It logs to the browser console and/or the server, with Scala stack traces. Demo code included.
There is nothing in the public API to access the column number because this is a Java API, and Scala.js cannot add public members to Java APIs.
To work around this issue in the case of StackTraceElement, we export getColumnNumber(): Int to JavaScript. You can therefore use the following code to retrieve the column number:
def columnNumberOfStackTraceElement(ste: StackTraceElement): Int =
ste.asInstanceOf[js.Dynamic].getColumnNumber().asInstanceOf[Int]
Note that this "feature" is undocumented, and might change without notice in a future major version of Scala.js. If it disappears, it will be replaced by something reliable. In the meantime, the above should get you going.
Had to use Logger in one of my applications today, and remembered that I needed to call require Logger first. So I decided to look at the Logger source code to see why debug, info, error, etc. are macros and not simple functions.
From the code, the macros for debug, info, etc (and even their underlying functions) look very simple. Wasn't it possible to simply export them as methods instead of macros?
From the Logger code:
defmacro log(level, chardata_or_fn, metadata \\ []) do
macro_log(level, chardata_or_fn, metadata, __CALLER__)
end
defp macro_log(level, data, metadata, caller) do
%{module: module, function: fun, file: file, line: line} = caller
caller =
compile_time_application ++
[module: module, function: form_fa(fun), file: file, line: line]
quote do
Logger.bare_log(unquote(level), unquote(data), unquote(caller) ++ unquote(metadata))
end
end
From what I can see, it would've been just simpler to make them into functions instead of macros.
It's probably because of the __CALLER__ special form, that provides info about the calling context, including file and line, but is only available in macros.
Turns out, another reason is so that the calling code can be stripped out during compile time for the logging levels that the application doesn't want.
From the ElixirForum discussion:
It is to allow the code to just entirely not exist for logging levels that you do not want, so the code is never even called and incurs no speed penalty, thus you only pay for the logging levels that you are actively logging.
and
It's so the entire Logger call can be stripped out of the code at compile time if you use :compile_time_purge_level
I have a use case where I need to create a class based on user input.
For example, the user input could be : "(Int,fieldname1) : (String,fieldname2) : .. etc"
Then a class has to be created as follows at runtime
Class Some
{
Int fieldname1
String fieldname2
..so..on..
}
Is this something that Scala supports? Any help is really appreciated.
Your scenario doesn't seem to make sense. It's not so much an issue of runtime instantiation (the JVM can certainly do this with reflection). Really, what you're asking is to dynamically generate a class, which is only useful if your code makes use of it later on. But how can your code make use of it later on if you don't know what it looks like? For example, how would your later code know which fields it could reference?
No, not really.
The idea of a class is to define a type that can be checked at compile time. You see, creating it at runtime would somewhat contradict that.
You might want to store the user input in a different way, e.g. a map.
What are you trying to achieve by creating a class at runtime?
I think this makes sense, as long as you are using your "data model" in a generic manner.
Will this approach work here? Depends.
If your data coming from a file that is read at runtime but available at compile time, then you're in luck and type-safety will be maintained. In fact, you will have two options.
Split your project into two:
In the first run, read the file and write the new source
programmatically (as Strings, or better, with Treehugger).
In the second run, compile your generated class with the rest of your project and use it normally.
If #1 is too "manual", then use Macro Annotations. The idea here is that the main sub-project's compile time follows the macro sub-project's runtime. Therefore, if we provide the main sub-project with an "empty" class, members can be added to it dynamically at compile time using data that the macro sees at runtime. - To get started, Modify the macro to read from a file in this example
Else, if you're data are truly only knowable at runtime, then #Rob Starling's suggestion may work for you as it did me. I'll share my attempt if you want to be a guinea pig. For debugging, I've got an App.scala in there that shows how to pass strings to a runtime class generator and access it at runtime with Java reflection, even define a Scala type alias with it. So the question is, will your new dynamic class serve as a type-parameter in Slick, or fail to, as it sometimes does with other libraries?