Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala logging line numbers - slf4s/slf4j?

UPDATE: SOLVED!!!
Please see the answer I added below


Does anyone know if there is a way to do logging that outputs real line numbers to the console? I'm trying to get into Scala here, but without being able to get basic stuff like this that I depend on, it's really hard to get much going.

I have set up slf4s to wrap with slf4j - log4j - jcl-over-slf4j. The problem is I get line numbers that do not match at all. The are much higher line numbers than the Scala class even contains. Is this because the line numbers are actually Java-intermediate line numbers?

Is there any EASY way to get set up logging that meets these requirements?:

  1. interoperable, working with both java & scala
  2. as easy to change the logging level of individual packages as easily as log4j
  3. provides ACCURATE line numbers.

Thanks!

Jamie

like image 757
jpswain Avatar asked Jan 29 '11 08:01

jpswain


2 Answers

I have found that logback (by Ceki Gülcü) works great and preserves line numbers too!
(And it works as a replacement for log4j: Awesome!)

import ch.qos.logback._
import org.slf4j._

object Main {

    def logger = LoggerFactory.getLogger("Main")
    var thingy = {
        x:Int =>
        logger.info("x=" + x)
        x + 1
    }
    def main(args: Array[String]) {
        logger.info("Hello.")
        logger.info("Hello again!")

        val myInts : List[Int] = List(-25,1,5,20)

        val myInts2 : List[Int] = myInts.filter { x:Int => x > 0 }

        logger.info("my ints2:" + myInts2)

        val myInts3 = myInts2.map(p =>  p * 2 )
        logger.info("my ints3:" + myInts3)

        logger.info(thingy(1) + "")
    }
}

For anyone struggling to get started with Scala, this is what I did to get the basic skeleton up:

1) Download sbt-launcher.jar and put it someplace like /opt/
I used "sbt-launch-0.7.5.RC0.jar"

2) Create a bash script as a shortcut to the sbt launcher in nano /opt/bin/sbt:

#!/bin/bash
java -jar /opt/sbt-launch-0.7.5.RC0.jar "$@"

(make it executable)

$ sudo chmod ug+x ./sbt

Make sure it's in your path too.

3) Create and configure the sbt project:

$ mkdir ./sc01
$ cd ./sc01
$ sbt
$ mkdir ./project/build</pre>
$ nano ./project/build/Project.scala</pre>

put this in there:

import sbt._

class sc01(info: ProjectInfo) extends DefaultProject(info)
{
    // dependencies
    val logback_core = "ch.qos.logback" % "logback-core" % "0.9.24" % "compile" //LGPL 2.1
    val logback_classic = "ch.qos.logback" % "logback-classic" % "0.9.24" % "compile" //LGPL 2.1
    val log4j_over_slf4j = "org.slf4j" % "log4j-over-slf4j" % "1.6.1"


   // if you are going to have any unmanaged (manually-added) jars
   //    def baseDirectories = "lib"
   //    def extraJars = descendents(baseDirectories, "*.jar")
   //    override def unmanagedClasspath = super.unmanagedClasspath +++ extraJars

    // tasks - easy to define
    lazy val hi = task { println("Hello World"); None }

    // classpath
    //override def mainScalaSourcePath = "src"

}

4) Paste the stuff from above into Main:

$ nano ./src/main/scala/Main.scala

5) I almost forgot! put this in /src/main/resources/logback.xml
(it's required to get the line numbers)

<configuration>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type
     ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %line --- %msg%n</pattern>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

6) $ sbt

Now you should be in the sbt console in your shell:

> update
> compile
> run

Hope this helps.

like image 84
jpswain Avatar answered Nov 11 '22 09:11

jpswain


As you are commenting in Scala logging question, getting precise line number information in Scala is hard.

  • scalac needs at least to be used with -g line or -g vars
  • this feature is very much in discussion for amelioration
  • Why does Scala not just overload the existing infrastructure by saving absolute offsets instead of line numbers in the LineNumberTable?
    Another way of addressing could be by numbering the tokens instead of the actual offsets into source files.
  • While I love the idea of indexing by tokens, this means that any tool capable of using the debug information would need to have access to a full parser.
    Another possibility would be to reformat the file according to some strictly-defined set of rules, and then continue to use line numbering.
  • I started working on improving the debugging experience for Scala programs, and one of the sore-points is indeed line numbers. Ideally there would be support for more than just line numbers. I am looking at JSR 45 (Debugging support for other languages). I am not sure yet if that is enough, but maybe a Scala stratum could use your scheme.
    I think the better way is to provide additional, Scala specific, debugging information in classfile attributes or annotations. As far as I know, JDI does not give access to classfile attributes, nor to annotations, but there are some tricks we could use to get to them. This way we'd preserve existing functionality, and allow tools to do more when they know about Scala attributes.

(Note: Scalate reports having done a similar work in scalate-24 for a different kind of source files)

like image 37
VonC Avatar answered Nov 11 '22 09:11

VonC