内容


在 WebSphere sMash 中使用 Groovy 记录日志

概述

WebSphere sMash 中容易产生问题的地方之一就是如何为 WebSphere sMash 中的 Groovy 类设置日志级别。本文将阐明有关这一主题的内容,并鼓励其他人扩展他们的日志使用,而不是仅限于 logger.INFO{} 调用。

我的当前项目使用 WebSphere sMash 作为数据服务层。它为超过 55 个不同类型的数据源提供访问点。大多数这些数据源来自第三方应用程序,我们通常无法掌控这些应用程序,并且它们其中的一个或多个经常会停止运行,或者出现与数据有关的问题。日志功能在监测这类资源方面扮演了重要角色。通过有效地使用 Java™ 日志提供的各种日志级别,包括对特定类设置日志过滤的细粒度控制,我们的支持团队能够快速识别问题的根源。

在 WebSphere sMash 中使用 Groovy 记录日志

在深入讨论之前,让我们先看一看在 WebSphere sMash 环境中如何使用 Groovy 实现日志功能。底层日志基础架构是由 Java 日志工具提供的。每个日志条目可以应用 7 个严重性级别,下面以其重要程度的降序方式显示:SEVERE、WARNING、INFO、CONFIG、FINE、FINER 和 FINEST。还有两个其他的元级别:ALL (与 FINEST 同义)和 OFF(禁用日志)。

WebSphere sMash 中的标准 Groovy 日志是通过在一个静态类(称为 logger)中对匹配的日志级别进行方法调用实现的,传递一个闭包,其中包含要记录的信息。下面显示了一个日志调用例子:

 logger.INFO{ "This is my logging entry" }

这将在日志处理器中生成一个条目,其中包括时间戳、源 package.class 和方法,以及记录的消息本身。WebSphere sMash 中有三种预定义的日志处理器。每个处理器都有一个默认的最低日志级别设置,如表 1 所示。

表 1. 预定义的日志处理器
处理器默认日志级别输出到:
ConsoleHandlerINFOStandard Out
LogHandlerINFO/logs/error-0.0.log
TraceHandlerALL/logs/trace-0.0.log

采用这种默认配置,可以看到 INFO 及以上级别的的所有日志记录都包含在标准的日志处理器文件 error-0.0.log 中,而 ALL 日志条目被写入跟踪日志文件。我们在项目中遇到的主要问题在于无法从普通日志中获得足够多的信息,而在跟踪日志中接收到太多的输出。这两种日志都无法提供我们所需的应用程序支持。注意,应用程序的大部分日志条目都被设置为 FINEST 到 FINE 级别。

Project Zero 网站 上的现有文档表明,如要修改日志级别,需要在 /config/logging/levels 映射中创建条目并重启应用程序。这样做通常是无效的,并且新的级别设置显然被忽略了。一旦您了解了所有日志部分如何组合在一起,那么这个问题的解决办法是显而易见的。

设置 Groovy 日志环境

WebSphere sMash 项目过去自动在 /config 目录中提供 logging.properties 文件。出于某些原因,它们停止包含这个文件,而选择使用默认实现。由于这一变化,有关日志的困惑和挫败进一步加深。这个文件对于定制日志环境至关重要,因此首先要做的是将它添加回项目中。在该文件内,您将定义要使用的日志处理器和它们的默认日志级别。还可以修改更多的设置,比如日志格式和输出文件名,但是这些不是讨论的重点。该文件的最后一项内容是最顶层的父记录器(logger)级别。这是应用于所有类的默认级别,除非指定了更具体的过滤规则,我们稍后就会这样做。清单 1 显示了修改后的 /config/logging.properties 文件。

清单 1. 修改后的 logging.properties 文件
 //-- File: /config/logging.properties 
 .level = INFO 

 handlers = zero.core.logging.ConsoleHandler     zero.core.logging.LogHandler 

 zero.core.logging.ConsoleHandler.level           = ALL 
 zero.core.logging.ConsoleHandler.formatter       = zero.core.logging.LogFormatter 
 zero.core.logging.ConsoleHandler.exceptionFormat = NONE 

 zero.core.logging.LogHandler.level               = ALL 
 zero.core.logging.LogHandler.pattern             = logs/error-%u.%g.log 
 zero.core.logging.LogHandler.encoding            = UTF-8 
 zero.core.logging.LogHandler.limit               = 1048576 
 zero.core.logging.LogHandler.count               = 10 
 zero.core.logging.LogHandler.append              = true 
 zero.core.logging.LogHandler.formatter           = zero.core.logging.LogFormatter 
 zero.core.logging.LogHandler.exceptionFormat     = NONE

大部分这些值是直接从默认的 WebSphere sMash logging.properties 文件获取的,该文件包含在本文的 下载 部分。您可能注意到,我们已经完全删除了对 TraceHandler 的引用。我们不希望在我们的应用程序中看到该输出。另一项相关设置是每个处理器的基本日志级别设置为 ALL。这允许灵活地为任何类过滤器分配任意的日志级别,而不存在外部限制。您不能设置低于处理器的基本日志级别的日志级别过滤器。父过滤器 (.level) 被设置为 INFO,因此只有 INFO 及以上级别的日志将被默认输出到处理器。这正是您希望看到的。在理论上,您不再需要编辑该文件。

注意:logging.properties 文件必须位于顶级项目。如果拥有大量依赖项目并将该文件放到较低级别的项目中,那么将无法准确地找出该文件,并且应用程序将默认使用标准的内部 WebSphere sMash logging.properties 文件。

此时,您需要在应用程序配置(/config/zero.config)中增加一些定制过滤器级别。清单 2 中的代码块实际上未执行任何操作,但是为您提供了快速修改过滤规则的基本方法。

清单 2. 默认的日志配置设置
 //-- File: /config/zero.config 
 /config/logging/levels += { 
    "public"                      : "INFO", 
    "app"                         : "INFO", 
    "app.scripts.myapp.someclass" : "FINER"
 }

使用这种配置,您声明了 public 和 app 树下的所有日志事件的日志级别为 INFO。您为 /app/scripts 下的一个特殊类添加了一个人为造成的的异常,以记录所有 FINER 和更高级别的日志事件。从这里开始,通过修改前两项就可以全面修改所有日志。

对于我们的项目的开发工作站和开发测试服务器,我们将 public 和 app 条目设置为 ALL。对于我们的集成、准备乃至生产环境,我们都将这些设置保持在 INFO 级别,除非出现问题。我们或做出适用于所有情形的过滤器修改,或为特定包或类添加定制规则。

这种方法非常奏效,但是当修改 zero.config 文件时,您必须重启应用程序,这也意味着要手动登录到服务器。这将产生破坏作用且耗费时间,因此,为了简化工作,可以创建一些定制日志服务来帮助进行日志诊断。

高级日志过滤器操作

要动态修改日志级别,需要一个支持类和一个对应的 REST 服务。日志支持类包含的方法可用于查看当前过滤器、增加或更新过滤器及其日志级别,以及测试给定的日志级别。本类中包含的大多数方法都很普通,因此让我们重点关注添加新 logger 过滤器的方法,如清单 3 所示。

清单 3. 添加新日志过滤器
 //-- File: /apps/scripts/ibm/kayman/admin/logging.groovy 
 import java.util.logging.Level 
 import java.util.logging.Logger 

 //----------------------------------------------------------------------- 
 // Adds/updates a logging filter to the specified level. 
 // Valid levels are: "OFF", "SEVERE", "WARNING", "INFO", 
 //                   "CONFIG", "FINE", "FINER", "FINEST", "ALL"
 //------------------------------------------------------------------------ 
 def setFilter( filter, level ) { 
    def _logger = Logger.getLogger( filter,      
"zero.core.logging.messages") 
    def ll = zget("/config/logging/levels") 
    if ( ll == null ) { 
        ll = [:] 
    } 
    if ( isValidLevel(level) ) { 
        logger.INFO{"Setting ${filter} == ${level}"} 
        _logger.setLevel( Level.parse(level) ) 
        ll.put(filter, level) 
        zput("/config/logging/levels", ll) 
        return ll 
    } else { 
      throw new Exception("Invalid level requested for filter 
 ${filter}: ${level}") 
    } 
 }

要修改日志过滤器,不仅仅是要修改 config 的级别映射。当您执行这个操作来维持对当前过滤器的简单引用时,这些设置仅仅在应用程序启动时使用。相反,您必须访问所涉及的类的 logger 实例。获得该类的 logger 实例后;或者更好,您设置了一个过滤器字符串,那么您可以将其更新到所需的级别。获取 logger 实例后将自动为该类创建一个新 logger(如果不存在的话)。由于您无法实际删除 logger 实例,您可以禁用它,只需将其级别设置为 OFF,或者设置为其下一个匹配父 logger 的级别。这个方法的其余部分是更新 /config/logging/levels 值,以保持对已定义过滤器的逻辑引用。

与这个类相对的 REST 服务包含 GET、GETs、POST 和 DELETE 事件。这些事件是相似的,因此我们将仅展示 POST 条目,如清单 4 所示。以防意外,我们强烈建议您对该资源进行保护。

清单 4. POST 条目
 //-- File: /apps/resources/kayman_logging.groovy 
 //--------------------------------------------------------------------------- 
 //-- POST handler 
 //--------------------------------------------------------------------------- 
 def onCreate() { 
    def filter = zget("/request/params/filter") 
    def level =  zget("/request/params/level") ?: "INFO"
    if ( filter ) { 
        invokeMethod("ibm.kayman.admin.logging", "setFilter", filter, level) 
    } else { 
        throw new Exception('Missing required filter parameter') 
    } 
 }

当使用 Poster 插件做出 POST 调用后,如图 1 所示,新的过滤器将被添加到所需的级别。

图 1. 使用 Poster 进行 POST 调用
使用 Poster 进行 POST 调用
使用 Poster 进行 POST 调用

命令行日志过滤器检查

在最后一步,我们添加了一个简单的命令行查询命令。该命令行接口(CLI)位于 /app/tasks/logging.groovy,使您能够查看现有的日志过滤器并对类过滤器字符串执行一个简单的查询。

清单 5. 命令行访问日志配置
 //-- File: /apps/tasks/logging.groovy 
 //--------------------------------------------------------------------------- 
 // Task to set revision of Project 
 //--------------------------------------------------------------------------- 
 import zero.json.Json 

 //--------------------------------------------------------------------------- 
 def onCliTask() { 
    def args = zget("/event/args") 
    if ( args ) { 
        switch( args[0] ) { 
        case "list": 
    	       showFilters() 
            break 
        case "test": 
            invokeMethod("ibm.kayman.admin.logging", "runTests", args[1]) 
    	       break 
    	   default: 
            syntax() 
            break 
        } 
    } else { 
        syntax() 
    } 
 } 

 //--------------------------------------------------------------------------- 
 def showFilters() { 

 System.out.println( zero.json.Json.encode( 
 invokeMethod("ibm.kayman.admin.logging", "getFilters", null), true) ) 
 } 

 //--------------------------------------------------------------------------- 
 def syntax() { 
    System.out.println """
 Syntax: 
 zero logging list  - Show current logging filters and their level 
    test "filter"  - Run a simple test on the provided filter string 
     (eg "app.scripts.ibm.mytest") 
             
"""
 } 

 //--------------------------------------------------------------------------- 
 // EOF 
 //---------------------------------------------------------------------------

从命令行中运行这些命令将产生与图 2 类似的输出。

图 2.运行日志命令的输出
运行日志命令的输出
运行日志命令的输出

假设这些 CLI 调用在上面的 Poster 测试后立即运行,其中我们添加了一个过滤器,您应该会在列表中看到该过滤器,对吗?答案是否。CLI 命令始终在其自己的进程中运行,因此您只看到 /config/logger/levels 设置中定义的默认条目。最后一个命令测试一个随意的类名,确定它的计算的日志级别,然后对级别进行测试。

结束语

本文阐释了有关在 WebSphere sMash 中使用 Groovy 进行日志记录的一些隐晦的理解。WebSphere sMash 及其 Dynamic Scripting Pack 拥有巨大的潜力,在 IBM 内部被广泛用于解决各种应用程序需求。它可以快速、方便地解决一些小问题,并且可以根据公司的需求进行扩展,包括中小型项目。未来的 WebSphere sMash 文章将介绍如何创建基于 Dojo 的前端应用程序来管理日志级别、监视 WebSphere sMash 应用程序和性能,以及在部署时轻松修改 config 设置以满足特定的服务器环境。


下载资源


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=772714
ArticleTitle=在 WebSphere sMash 中使用 Groovy 记录日志
publish-date=11072011