用于日志记录的Scala反射

用于日志记录的Scala反射,scala,Scala,在Scala中,是否可以获取包含代码的成员/函数的名称?e、 g.为了完成以下代码: def someFunc() { Log(s"error $x occurred in function ${SomeScalaAPI.enclosingFunction}") } 这将产生一个字符串: “函数someFunc中出现错误X” 不诉诸法律?我想假设,因为异常知道它们发生在哪里,所以可以通过一些Scala或Java反射api获得这些信息。。或者,通过一个聪明的编译时宏 谢谢 您可以用java来

在Scala中,是否可以获取包含代码的成员/函数的名称?e、 g.为了完成以下代码:

def someFunc() {
  Log(s"error $x occurred in function ${SomeScalaAPI.enclosingFunction}")
}
这将产生一个字符串:

“函数someFunc中出现错误X”

不诉诸法律?我想假设,因为异常知道它们发生在哪里,所以可以通过一些Scala或Java反射api获得这些信息。。或者,通过一个聪明的编译时宏


谢谢

您可以用java来实现:

java.lang.Thread.currentThread.getStackTrace()(1).getMethodName
例如:

scala> def aa = {println(java.lang.Thread.currentThread.getStackTrace()(1).getMethodName)}
aa: Unit

scala> aa
aa
但它不适用于函数-仅适用于方法:

scala> val zz = aa _
zz: () => Unit = <function0>

scala> zz()
aa

scala> val zzz = () => println(java.lang.Thread.currentThread.getStackTrace()(1).getMethodName)
zzz: () => Unit = <function0>

scala> zzz()
apply$mcV$sp
结果:

 call(param = 2)
  call(param = 1)
   call(param = 0)
   call = 0
  call = 0
 call = 0
 call2(param2 = 666)
 call2 = 666
 call3(param2 = 666)
 call3 = scala.NotImplementedError: an implementation is missing

它使用
println
而不是记录器(可修复),并且需要宏库。所有参数/错误都会自动打印,这可能不是您想要的,但如果没有日志准备库,您可以将其用作模板。

是时候使用一些宏魔术了:

import language.experimental.macros

import reflect.macros.blackbox.Context

case class Location(filename: String, line: Int, column: Int, enclosingMethod : Option[String])

object PositionMacro {
  def currentLocation: Location = macro impl

  def impl(c: Context): c.Expr[Location] = {
    import c.universe._
    val pos = c.macroApplication.pos
    val owner = c.internal.enclosingOwner //Old, deprecated way: c.enclosingMethod.symbol
    val enclosingMethod = Some(owner).filter(_.isMethod).map(_.fullName)
    c.Expr(q"Location(${pos.source.path}, ${pos.line}, ${pos.column}, ${enclosingMethod})")
  }
}
您可以这样使用它:

def test(): Unit = {
  println(s"Called from ${PositionMacro.currentLocation}")
}

test()
// Called from Location(C:\Users\sschwets\AppData\Local\Temp\scratchPad.sc9.tmp,9,41,Some(A$A22.A$A22.test))
我将以下内容添加到我的
build.sbt
文件中:

scalaVersion := "2.11.4"

libraryDependencies +=
  "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"

注意:这是我第一个使用Scala 2.11界面和准引号的宏。它对我来说很好,但可能会格式化你的硬盘,清空你的银行账户,宠坏你的孩子,激怒你的猫,或者和你的妻子/丈夫/什么的私奔。所以请小心

如果您使用log4j,可以使用多种设置来设置日志记录,包括方法名称:谢谢,但我总是喜欢我自己的日志记录,而不是装订日志记录者的所有怪癖(例如,在您提到的链接“同步和其他问题”)和任意日志记录级别。我想知道api log4j使用什么来实现它。。如果Scala没有其他东西,这可能会有所帮助。愚蠢的问题-这不就是捕获定义aa的方法吗?最好有一个实用函数,它可以获取调用它的方法的名称。愚蠢的回答:)-
java.lang.Thread.currentThread.getStackTrace()(2.getMethodName
(这里是2而不是1)我认为它将捕获任何包含对aa的调用的匿名函数,而不是根据所述的包含它们的方法。我将研究宏。是的,它会,你可以使用
$
(正如它们命名为apply$mcV$sp)过滤它们,这不是最好的方法,但在
scala.mirror
中没有找到任何类似的方法实际上我已经编写了Similar宏-。它打印每个函数调用,该类用@trace注释标记。这不完全是你想要的,但很接近。投票给你的注意力捕捉者。好啊代码也很好。
scalaVersion := "2.11.4"

libraryDependencies +=
  "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"