我可以使用此功能:
scala> object LOGGER {
| def warning(msg: String)(implicit className:String) = {
| className
| }
| }
defined object LOGGER
scala> class testing {
| lazy implicit val className = this.getClass.getName
| def test = LOGGER.warning("Testing")
| }
defined class testing
scala> val obj = new testing()
obj: testing = testing@11fb4f69
scala> obj.test
res51: String = testing <=======
scala> class testing2 {
| lazy implicit val className = this.getClass.getName
| def test = LOGGER.warning("Testing")
| }
defined class testing2
scala> val obj2 = new testing2()
obj2: testing2 = testing2@2ca3a203
scala> obj2.test
res53: String = testing2 <=====
我也尝试在object LOGGER
中使用Thread.currentThread.getStackTrace,但无法在testing
函数中打印调用类warning
。
还有其他方法吗?
答案 0 :(得分:3)
一种方法是DymamicVariable
import scala.util.DynamicVariable
object LOGGER {
val caller = new DynamicVariable[String]("---")
def time = new Date().toString
def warning(msg: String) = println(s"[${caller.value} : $time] $msg")
}
trait Logging {
def logged[T](action: => T) = LOGGER.caller.withValue(this.getClass.getName)(action)
}
class testing extends Logging {
def test = logged {
//some actions
LOGGER.warning("test something")
//some other actions
}
}
val t = new testing
t.test
将打印类似
的内容[测试:11月25日星期三11:29:23 MSK 2015]测试一些东西
或者不是在Logging
中混合就可以直接使用
class testing {
def test = LOGGER.caller.withValue(this.getClass.getName) {
//some actions
LOGGER.warning("test something")
//some other actions
}
}
另一个更强大,但更复杂的支持方法是构建一些简单的macro
您可以在其他来源中定义,最好在其他子项目中定义
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
class LoggerImpl(val c: Context) {
import c.universe._
def getClassSymbol(s: Symbol): Symbol = if (s.isClass) s else getClassSymbol(s.owner)
def logImpl(msg: Expr[String]): Expr[Unit] = {
val cl = getClassSymbol(c.internal.enclosingOwner).toString
val time = c.Expr[String](q"new java.util.Date().toString")
val logline = c.Expr[String](q""" "[" + $cl + " : " + $time + "]" + $msg """)
c.Expr[Unit](q"println($logline)")
}
}
object Logger {
def warning(msg: String): Unit = macro LoggerImpl.logImpl
}
现在您无需更改测试类:
class testing {
def test = {
//some actions
Logger.warning("something happen")
//some other actions
}
}
看到所需的输出。
Thsi可能是运行时堆栈内省的非常有效的替代方法
答案 1 :(得分:0)
我在我的自定义类加载器项目中使用这种技术来获取堆栈中第一个类的名称,而不是在我的包中。一般的想法是从UrlClassloader复制的。
String callerClassName="";
StackTraceElement[] stackTrace=Thread.currentThread().getStackTrace();
for (int i=1; i < stackTrace.length; i++) {
String candidateClassName=stackTrace[i].getClassName();
if(!candidateClassName.startsWith("to.be.ignored") &&
!candidateClassName.startsWith("java")){
callerClassName=candidateClassName;
break;
}
}
这种方法有它的缺点,因为它只获取类的名称,而不是实际的类,甚至更好的对象。