当我在Scalatra中“停止()”时如何记录警告?

时间:2018-04-05 16:08:14

标签: scala scalatra

在我的Scalatra路线中,我经常使用halt()快速失败:

val user: User = userRepository.getUserById(params("userId"))
    .getOrElse {
        logger.warn(s"Unknown user: $userId")
        halt(404, s"Unknown user: $userId")
    }

如示例所示,我还想在这些情况下记录警告。但我想避免halt()和记录器之间的代码重复。简单地做起来会更加清洁:

val user: User = userRepository.getUserById(params("userId"))
    .getOrElse(halt(404, s"Unknown user: $userId"))

以交叉方式记录所有“HaltExceptions”的最佳方式是什么?

我考虑过:

1)覆盖路线中的halt()方法:

override def halt[T](status: Integer, body: T, headers: Map[String, String])(implicit evidence$1: Manifest[T]): Nothing = {
    logger.warn(s"Halting with status $status and message: $body")
    super.halt(status, body, headers)
}

除了奇怪的方法签名之外,我不太喜欢这种方法,因为我可能会错误地调用真实halt()而不是重写方法,例如,如果我在路线外停止。在这种情况下,不会记录任何警告。

2)使用trap()记录所有错误响应:

trap(400 to 600) {
    logger.warn(s"Error returned with status $status and body ${extractBodyInSomeWay()}")
}

但我不确定这是最好的方法,特别是因为它向_statusRoutes Map添加了201个路由(范围内每个整数的一个映射...)。我也不知道如何在这里提取身体?

3)在Jetty中启用某种响应日志记录以获取特定的状态代码吗?

这样做的最佳方法是什么?我是否正确接近这个?

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是在servlet过滤器中进行,如下所示:

package org.scalatra.example

import javax.servlet._
import javax.servlet.http.HttpServletResponse

class LoggingFilter extends Filter {

  override def init(filterConfig: FilterConfig): Unit = ()
  override def destroy(): Unit = ()

  override def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain): Unit = {
    chain.doFilter(request, response)

    val status = response.asInstanceOf[HttpServletResponse].getStatus
    if (status >= 400 && status <= 600) {
      // Do logging here!
    }
  }
}

在Bootstrap课程中注册此过滤器(或者甚至可以在web.xml中注册):

package org.scalatra.example

import org.scalatra._
import javax.servlet.ServletContext

class ScalatraBootstrap extends LifeCycle {
  override def init(context: ServletContext): Unit = {
    context.addFilter("loggingFilter", new LoggingFilter())
    context.getFilterRegistration("loggingFilter")
      .addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/*")

    // mount your servlets or filters
    ...
  }
}

在我看来,Scalatra应该提供一种基本上更容易陷阱的方法。事实上,在renderHaltException中有一个名为ScalatraBase的方法,它看起来可以通过一键覆盖此方法来添加日志记录: https://github.com/scalatra/scalatra/blob/cec3f75e3484f2233274b1af900f078eb15c35b1/core/src/main/scala/org/scalatra/ScalatraBase.scala#L512

但是我们实际上无法做到这一点,因为HaltException是包私有的,只能在org.scalatra包内访问。我想我应该公开HaltException