The Logging API

    日志 API 提供了一组构件来帮助你实现高效的日志记录策略。

    你的应用可以定义 Logger 实例来发送日志信息。每个 Logger 有一个名字,它会出现在日志信息中,该名字是用于配置层级关系的。

    Logger 根据它们的名字会有一个层级继承结构。如果一个 logger 的名字后面加个点后是另外一个 logger 名字的前缀,那么我们就说第一个 logger 是第二个 logger 的祖先。例如,名为 “com.foo” 的 logger 是名为 “com.foo.bar.Baz” 的 logger 的祖先。所有的 logger 都继承自根 logger。Logger 继承机制的一个好处就是,如果你想配置一组 logger,那你只需要配置它们的共同祖先即可。

    Play 应用有一个默认的 logger,叫 “application”。当然,你也可以创建你自己的 logger。Play 库使用的 logger 名叫 “play”,还有一些第三方库会自己命名 logger。

    日志级别是用来区分日志消息的严重性的。当你写日志请求时,你需要指定严重程度,它会出现在产生的日志消息里。

    以下是一组可用的日志级别,以严重性的降序列出。

    • OFF - 关闭日志,不作为消息分类。
    • ERROR - 运行时错误,或不可预料的情况。
    • WARN - 用在一些不建议使用的 API 提示上,或是其它一些不可预料但又算不上错误的运行时情况。
    • INFO - 用在你感兴趣的运行时事件上,比如应用启动和关闭时。
    • DEBUG - 系统工作流程上的一些细节信息。
    • TRACE - 大部分细节信息。

    日志 API 允许日志请求打印到一个或多个叫做 appender 的目标输出。appender 在配置中指定,可选的有:控制台,文件,数据库或其它输出。

    appender 和 logger 组合可以帮助你路由及过滤日志信息。例如,你可以使用一个 appender 打印有用的信息用于分析,用另一个 appender 打印错误信息,用于运维团队的监控。

    首先导入 Logger 类及其伴生对象:

    Logger 对象是默认的 logger,名为 “application”。你可以使用它来打印日志:

    1. / Log some debug info
    2. Logger.debug("Attempting risky calculation.")
    3. try {
    4. // Log result if successful
    5. Logger.debug(s"Result=$result")
    6. } catch {
    7. case t: Throwable => {
    8. // Log error with message and Throwable.
    9. Logger.error("Exception with riskyCalculation", t)
    10. }
    11. }

    使用 Play 默认的日志配置,上面的语句会产生类似下面的控制台输出:

    也许你想在所有地方都用默认 logger,但这种使用方式并不好。用一个不同的名字创建你自己的 logger,这样配置起来会更灵活,可以过滤你的日志输出,并且精确知道日志的来源。

    你可以使用 Logger.apply 工厂方法来创建一个新 logger,它需要一个名字作为参数:

    1. val accessLogger: Logger = Logger("access")

    一个常用的策略是,为每个类配置一个不同的 logger,并且用类名来命名它。你可以使用另一个工厂方法,它接受一个类作为参数:

    高效地使用 logger 可以帮助你达到许多目标:

    1. import scala.concurrent.Future
    2. import play.api.Logger
    3. import play.api.mvc._
    4. trait AccessLogging {
    5. val accessLogger = Logger("access")
    6. object AccessLoggingAction extends ActionBuilder[Request] {
    7. def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    8. block(request)
    9. }
    10. }
    11. }
    12. object Application extends Controller with AccessLogging {
    13. val logger = Logger(this.getClass())
    14. def index = AccessLoggingAction {
    15. try {
    16. val result = riskyCalculation
    17. Ok(s"Result=$result")
    18. } catch {
    19. case t: Throwable => {
    20. logger.error("Exception with riskyCalculation", t)
    21. InternalServerError("Error in calculation: " + t.getMessage())
    22. }
    23. }
    24. }

    这个例子使用了 来定义 AccessLoggingAction,它会把日志打印到一个名为 “access” 的 logger。 控制器使用了这个 action,并且它使用了自己的 logger 来记录该应用里的事件。在配置中,你就可以将这些 logger 路由到不同的 appender,例如访问日志和应用日志。

    如果你只想为指定 action 打印请求数据,那么上面的设计就足够了。想要打印所有的请求,则最好使用过滤器

    详见。