1

In Java we can use AspectJ to add logging transparently to Java classes (or probably use other byte code instrumentation tools). Now I wonder how to add logging transparently to Scala functions.

I would like a tool to transform a function foo

def foo(x:Int) = x + 1

to something like that:

def foo(x:Int) = { 
   log.trace("Enter foo with x = " + x) // added automatically
   val r = x + 1
   log.trace("Exit foo with r = " + r) // added automatically  
   r
}

How would you add logging transparently to Scala functions?

2
  • 2
    You tried AspectJ and had some problems with it? To my knowledge, AspectJ works not only with source, but with bytecode, and Scala compiles to the same bytecode that java does. Commented May 6, 2013 at 11:16
  • No, I did not try it. You are right AspectJ does work with the byte code but I am afraid it will have difficulties to work with Scala. Commented May 6, 2013 at 11:40

1 Answer 1

2

AspectJ will work just fine with Scala code. You'll just need to follow the Scala name mangling rules (i.e. def > becomes def $gt) and so on.

Suppose you have

class Foo {
  def foo(x: Int) {
  }
  def bar() { }
}

To add logging, you can use the Java AspectJ syntax, adding

"org.aspectj" % "aspectjweaver" % "1.7.2",
"org.aspectj" % "aspectjrt" % "1.7.2"

To your build.sbt. Moving on, you can have the following aspect:

@Aspect
public class MonitorAspect {

    @Pointcut(value = "execution (* your.package.Foo.*(..))")
    public void methodsInFoo() {}

    @Before("methodsInFoo()")
    public void enter(JoinPoint jp) {
        // log
    }

    @After("methodsInFoo()")
    public void exit(JoinPoint jp) {
    }
}

The final piece will be the META-INF/aop.xml, which defines the work for the load-time weaver:

<aspectj>

    <aspects>
        <aspect name="your.package.MonitorAspect"/>
    </aspects>

    <weaver options="-XnoInline">
        <include within="your.package.*"/>
    </weaver>

</aspectj>

Finally, start your JVM with -javaagent:$PATH_TO_ASPECTJWEAVER.JAR and you're all set.


In your case, it may be worth thinking about using higher-order functions. If you are using logging as just an example, and if you're actually doing something before and after some inner function, you should consider using HOFs.

def logged[U](f: => U): U = {
    log.info("Before")
    val ret = f
    log.info("After")
    ret
}

Here, you have the logged function that takes another function f, deals with the logs and does whatever f does.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.