首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 第二书店 程序员
您的位置:middleware->使用XSLT挖掘WEBLOGIC诊断数据

使用XSLT挖掘WEBLOGIC诊断数据2008-02-21 来自:lizhe1985  [收藏到我的网摘]

来源:dev2dev

摘要

  WebLogic诊断框架(WebLogic Diagnostic Framework,WLDF)是BEA WebLogic Server 9.0中引入的一个功能强大的子系统。在WLDF的帮助下,您可以监控和记录运行中的WebLogic Server域的一切行为。

  一些标准工具可以从诊断档案库中提取采集的数据和事件,但无法通过该数据构建合成图。

  在本教程中,我将介绍如何使用XSLT重新格式化诊断数据并通过WLDF诊断数据生成分层HTML报表。

简介

  WebLogic诊断框架(WebLogic Diagnostics Framework,WLDF)提供了一组可通过WebLogic服务器和资源(包括部署在服务器上的应用程序)生成信息的组件,管理员和IT管理人员可以使用这些组件分析他们的服务器操作环境。有关WLDF的入门知识,请参阅Rebecca Sly撰写的WebLogic Diagnostics Framework(WLDF)简介(Dev2Dev, 2006)。

  遗憾的是,WLDF自带的标准工具基本上无法通过所采集的数据构建合成图。本教程将解决这个问题。我将介绍如何对这些数据执行各种有用的转换:

将诊断数据重新格式化为逗号分隔值文件。这样便可以方便地将文件导入电子表格工具。
重新组合原始事件数据的结构,使之成为分层结构并将该数据作为HTML报表呈现。结合WLD诊断上下文,这种方式可用于展示多个WebLogic Server实例之间的事件流。
  我所介绍的技巧可通用于基于WebLogic Server 9.0或更高版本的任何系统。

前提条件

  本文针对的读者为高级WebLogic用户。文章并未介绍WebLogic诊断框架的基本知识。有关这一方面的内容,请阅读以下文章:

WebLogic Diagnostics Framework(WLDF)简介(中文版,Dev2Dev,2006年8月)——Dev2Dev文章,作者为Rebecca Sly
Explore the Power of WebLogic Diagnostic Framework——Dev2Dev网上交流会,作者为Sunila Srivatsan
Configuring and Using the WebLogic Diagnostics Framework——WLDF文档

  同样,本文也不是关于XSLT的教程,但是即便对XSLT的语法一无所知也没有关系。您可以直接使用本文所提供的脚本,无需理解其详细运行原理。

流程概述

  我将使用一些样式表来处理诊断数据。每个处理步骤从概念上说都相当简单,图1显示了处理的总体流程。



  图1.总体流程

  如图1所示,WebLogic Server将收集到的度量和事件数据存储在它的诊断档案库中。然后可以使用WLST将这些数据导出到XML文件中;我已经将事件数据导出到events.xml文件中,并将收集到的度量(也称作采集到的数据)导出到harvest.xsl文件中。本教程将提供一些样式表,用于将这些导出数据转化为逗号分隔值(CSV)格式(exportToCSV.xsl),将两个导出数据文件合二为一(merge.xsl),以根据事件树(eventsToTree.xsl)的结构构建XML文件,并通过事件树(treeToHTML.xsl)生成HTML报表。

  好了,下面我们开始详细介绍这些步骤。

步骤1:系统检测

  首先,配置WLDF可以检测应用程序代码信息,使程序能生成事件数据并定期从MBean采集度量数据。如图2所示,WebLogic Server将这些信息存储在它的诊断档案库中。



  图 2. WebLogic Server将WLDF数据存储在它的诊断档案库中。下文将介绍如何实现这一目的。

在应用程序中添加一个weblogic-diagnostics.xml文件
  若要指定检测,需要在应用程序的META-INF目录中添加一个weblogic-diagnostics.xml文件。确保包含足够的委托监控程序或自定义监控程序,诊断位置类型为around,操作为TraceElapsedTimeAction。这些监控程序将记录完成特定操作完所需的时间。我们稍后需要使用这些数据构建事件树。下面这个示例可用于捕捉各种servlet和EJB操作。

<?xml version="1.0" encoding="UTF-8"?>

<wldf-resource xmlns="http://www.bea.com/ns/weblogic/90/diagnostics">
<instrumentation>
<enabled>true</enabled>

<wldf-instrumentation-monitor>
<name>Trace_Servlet_Around_Service</name>
<action>TraceElapsedTimeAction</action>
<location-type>around</location-type>
<pointcut>execution(* +javax.servlet.Servlet service(+javax.servlet.ServletRequest, +javax.servlet.ServletResponse))</pointcut>
</wldf-instrumentation-monitor>

<wldf-instrumentation-monitor>
<name>Trace_EJB_Session_Business_Methods</name>
<action>TraceElapsedTimeAction</action>
<location-type>around</location-type>
<pointcut>execution(* +javax.ejb.SessionBean * (...))
AND NOT execution(* * __WL* (...))
AND NOT execution(* * ejbCreate (...))
AND NOT execution(* * ejbRemove ())
AND NOT execution(* * ejbActivate ())
AND NOT execution(* * ejbPassivate ())
AND NOT execution(* * setSessionContext (...))
</pointcut>
</wldf-instrumentation-monitor>

<wldf-instrumentation-monitor>
<name>Trace_EJB_Session_Home_Methods</name>
<action>TraceElapsedTimeAction</action>
<location-type>around</location-type>
<pointcut>execution(* +javax.ejb.EJBHome * (...))
AND execution(* *Impl * (...))
</pointcut>
</wldf-instrumentation-monitor>

<wldf-instrumentation-monitor>
<name>Trace_EJB_Stub_Calls</name>
<action>TraceElapsedTimeAction</action>
<location-type>around</location-type>
<pointcut>call(* +wldfexample.SessionEJBRemote * (...))
AND NOT call(* *_EOImpl* * (...))
</pointcut>
</wldf-instrumentation-monitor>

</instrumentation>
</wldf-resource>
  可以看出,我比较偏爱使用自定义的切入点(pointcut)指定监控程序,而不是依赖于各种标准委托监控程序。这样,通过指定要捕捉的事件便可以更加精准进行控制。比如说,最后一个监控程序只跟踪已经部署的EJB(wldfexample.SessionEJBRemote)的EJB stub。

在域中添加一个系统诊断模块

  系统诊断模块中必须启用检测,而且系统诊断模块的目标必须是应用程序WebLogic Server实例,只有这样才能应用weblogic-diagnostics.xml文件中所指定的检测。这是一个特性;它允许我们在不修改应用程序的情况下启用或禁用检测,还允许根据需要在指定的服务器上启用或禁用检测。

  如果更改了系统诊断模块的目标,或者更改了是否启用检测,则需要重新部署应用程序以使修改生效。只有完全重新部署应用程序后才会执行AOP weaving(代码插入)处理并更改检测。除了通过WebLogic控制台停止和启动应用程序外,还需要使用以下操作之一:

使用WLST redeploy()命令。
取消应用程序的目标实例,应用修改,然后重新指定应用程序的目标实例。
重启服务器。

  无论何时需要修改weblogic-diagnostics.xml文件,都需要完全重新部署应用程序。

  可以使用WebLogic控制台 创建一个系统诊断模块。其结果是在域的config/diagnostics目录中生成一个文件,该文件的内容类似于以下示例:

<?xml version='1.0' encoding='UTF-8'?>
<wldf-resource xmlns="http://www.bea.com/ns/weblogic/90/diagnostics"
xmlns:sec="http://www.bea.com/ns/weblogic/90/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wls="http://www.bea.com/ns/weblogic/90/security/wls"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/90/diagnostics http://www.bea.com/ns/weblogic/920/diagnostics.xsd">
<name>MySystemDiagnosticModule</name>
<instrumentation>
<enabled>true</enabled>
</instrumentation>
<harvester>
<enabled>true</enabled>
<sample-period>10000</sample-period>
<harvested-type>
<name>weblogic.management.runtime.WorkManagerRuntimeMBean</name>
<harvested-attribute>CompletedRequests</harvested-attribute>
<harvested-attribute>PendingRequests</harvested-attribute>
<harvested-attribute>StuckThreadCount</harvested-attribute>
<harvested-instance>com.bea:ApplicationRuntime=WLDF,Name=default,ServerRuntime=AdminServer,Type=WorkManagerRuntime</harvested-instance>
</harvested-type>
<harvested-type>
<name>weblogic.management.runtime.JTAStatisticsRuntimeMBean</name>
<harvested-attribute>TransactionCommittedTotalCount</harvested-attribute>
<harvested-attribute>TransactionRolledBackTotalCount</harvested-attribute>
<harvested-instance>com.bea:Name=JTARuntime,ServerRuntime=AdminServer,Type=JTARuntime</harvested-instance>
</harvested-type>
</harvester>
<watch-notification></watch-notification>
</wldf-resource>

  除了启用检测之外,我还指定应该采集各种MBean属性。稍后,我们将处理其中一些采集数据。

诊断上下文

  WLDF中还有一个有趣的特性是其他工具中所没有的,即创建和传播诊断上下文的功能。诊断上下文将惟一地识别特定请求,并通过同步调用将其传递给其他WebLogic Server实例。诊断上下文含有一个惟一的ID(比如说,583c10bfdbd326ba:-43487c71:112bda0af31:-7ff4-00000000000001b7)。您可以使用这个ID跟踪服务器之间的事件流。

  与诊断上下文有关的还有一个请求dyeing(染色)的概念。DyeInjectionMonitor可用于筛选根据请求特征(用户标识、协议类型、IP地址,等等)记录的事件。这种强大的方法可专注于特定的事件,但是本文并没有使用这一特性。有关这一方面的更多信息,请参阅 WebLogic文档。

  诊断上下文只增加了非常小的处理开销:从本质上说,产生的开销即生成惟一ID并将其分发给每个请求。我认为这些开销是可以忽略的。但是,由于WLDF的运行原则是“付出只使用”,因此只有满足以下任意一点时才会生成诊断上下文:

启用了DyeInjectionMonito。
启用了检测。
通过控制台的诊断 /上下文页面专门为服务器启用了诊断上下文。

  生成诊断上下文的行为在WebLogic Server 9.2中已得以合理化,因此需要遵循上述规则。如果您使用的是WebLogic Server 9.0或9.1,那么可能需要通过控制台启用诊断上下文,并且这一操作将覆盖任何入站上下文,因此在做此修改时应该谨慎,最好只在接收初始请求的服务器上应用。

使用WLST从诊断档案库提取数据
  WebLogic将诊断数据存储在各个服务器的本地诊断档案库上。



  图 3. WLST用于从诊断档案库导出数据

  诊断档案库中存储的事件和采集的度量数据为二进制格式。 如图3所示,可以使用WebLogic脚本工具(WebLogic Scripting Tool,WLST)将数据导入XML格式,一般使用 exportDiagnosticData 或 exportDiagnosticDataFromServer 命令。比如说:

exportDiagnosticData(storeDir="/work/domain/servers/server1/data/store/diagnostics",
logicalName="EventsDataArchive", exportFileName="server1-events.xml")

  我将使用两种类型的数据,事件数据(logicalName="EventsDataArchive")和采集到的度量数据(logicalName="HarvestedDataArchive")。exportDiagnosticData和exportDiagnosticDataFromServer命令都有允许筛选数据的选项,按时间或完整的 WLDF查询 进行筛选。您应该使用这些筛选选项限制导出XML文件的大小。这一点特别重点,因为我们将使用的Java XSLT实现并不支持较大的输入文件。下面这个示例将根据特定诊断上下文ID进行筛选:

exportDiagnosticData(storeDir="/work/domain/servers/server1/data/store/diagnostics",
logicalName="EventsDataArchive", exportFileName="events.xml",
query="CONTEXTID='583c10bfdbd326ba:58f87d21:1126b53f6ec:-7ff3-0000000000000c2a'")

  当尝试使用exportDiagnosticData多次从同一WLST流程访问不同服务器上的档案文件时应该注意,该命令存在一个小问题:第二次使用该命令时,它将继续引用已打开的原始档案文件。要解决这个问题,可以使用单独的WLST流程访问各个档案库。

  从导出的XML数据中可以看出,XML符合一个抽象模式,该模式建模的模型中含有一组DataRecord元素(该元素的各列都由ColumnData值组成)。XML文件头部的DataInfo元素含有各列和它们的Java类型的名称。这些列与本文所讨论的事件和采集到的数据文件稍微有所不同。

如何运行XSLT样式表

  现在,我们已经导出了一些XML文件。在开始开发第一个XSLT样式表之前,我们先看看下面这个Jython脚本,该脚本可以与样式表一起处理XML文档。

import sys

from java.io import FileReader, PrintWriter
from java.lang import System
from javax.xml.transform import TransformerFactory, Transformer
from javax.xml.transform.stream import StreamSource, StreamResult

def transform(source, stylesheet, result, parameters):
transformer = TransformerFactory.newInstance().newTransformer(stylesheet)

for (p, v) in parameters: transformer.setParameter(p, v)

transformer.transform(source, result)

if __name__ == '__main__':
args = sys.argv[1:]
parameters = []

while args and args[0].startswith('-'):
try:
i = args[0].index('=')
except ValueError:
parameters.append((args[0], ""))
else:
parameters.append((args[0][1:i], args[0][i+1:]))

args = args[1:]

if len(args) == 1: source = StreamSource(System.in)
elif len(args) == 2: source = StreamSource(FileReader(args[1]))
else: raise "Usage: <jython|wlst> process.py -<parameter>=<value> <stylesheetfile> [inputfile]"

stylesheet = StreamSource(FileReader(args[0]))
result = StreamResult(PrintWriter(System.out))

transform(source, stylesheet, result, parameters)

stylesheet.reader.close()
source.reader and source.reader.close()
result.writer.close()

  您可以直接从Jython中调用这个脚本,但是由于WLST附带在WebLogic Server 9中,因此我将演示如何使用WLST启用这个脚本。首先,设置您的环境(比如source setDomainEnv.sh)。然后使用以下命令运行process.py:

java weblogic.WLST process.py stylesheet.xsl input.xml > output.xml

  输出将保存在stdout中,因此我们使用shell重定向将其发送到output.xml文件中。您也可以使用shell管道操作符将多个process.py流程连接到一起。如果已经安装了Jython,那么使用Jython代替java weblogic.WLST可以获得更快的启动时间。

  有的样式表需要通过参数来控制它们的行为。process.py允许我们使用以下命令指定样式表参数:

java weblogic.WLST process.py -myparameter=value stylesheet.xsl input.xml > output.xml  如果使用的是Microsoft Windows shell,那么需要引用参数,比如: "-myparameter=value"。

合并数据

  第一个样式表的功能仅仅是合并从两个诊断档案库中导出的数据,如图4所示。



  图 4. merge.xsl样式表用于合并两个导出文件中的数据。

  这种合并多个WebLogic Server实例中的数据的方法很实用。首先,从各个服务器中提取数据,使用WLST筛选出符合条件的数据;然后创建一个合并文件,以便于使用样式表进行下一步处理。

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:e="http://www.bea.com/ns/weblogic/90/diagnostics/accessor/Export">

<xsl:output method="xml"/>

<xsl:variable name="TIMESTAMP" select="count(//e:ColumnInfo[e:Name='TIMESTAMP']/preceding-sibling::*) + 1"/>

<xsl:param name="document2"/>
<xsl:param name="offset" select="0"/>

<xsl:template match="e:DiagnosticData">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>

<xsl:variable name="d2" select="document($document2)" />

<xsl:for-each select="$d2/e:DiagnosticData/e:DataRecord">
<xsl:copy>
<xsl:apply-templates select="@*" mode="d2"/>
<xsl:apply-templates mode="d2"/>
</xsl:copy>

<xsl:text>
</xsl:text>
</xsl:for-each>

</xsl:copy>
</xsl:template>

<xsl:template match="e:ColumnData[$TIMESTAMP]" mode="d2">
<xsl:copy>
<xsl:value-of select=". + $offset"/>
</xsl:copy>
</xsl:template>

<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="node()|@*" mode="d2">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

  该样式表接收两个参数:document2是与其主要输入文档合并的文档名称;offset是可选的时间偏移量,单位为毫秒。如果指定了offset,则它的值将添加到document2的所有时间信息中。当托管WebLogic Server 实例的系统的时间不完全同步时,这个参数将非常有用。

  下面这个示例将使用样式表合并两个事件数据导出文件:

java weblogic.WLST process.py -document2=server2-events.xml merge.xsl server1-events.xml > events.xml  这种方法可用于合并两个事件数据或两个采集度量文件。但是却无法将一个事件数据文件和一个采集度量文件合并在一起,因为这些文件的列结构不同。

生成逗号分隔值文件

  第二个样式表将更加有用。它能够将导出文件转换为逗号分隔值格式的文件,以便导入Microsoft Excel或其他电子表格工具。该流程如图5所示。



  图 5. exportToCSV.xsl样式表可以将诊断导出文件转换为逗号分隔值文件。

  该样式表没有参数。

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:e="http://www.bea.com/ns/weblogic/90/diagnostics/accessor/Export">

<xsl:output method="text"/>

<xsl:template match="e:DiagnosticData">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="e:DataInfo"/>

<xsl:template match="e:DataRecord">
<xsl:variable name="record" select="."/>

<xsl:for-each select="/e:DiagnosticData/e:DataInfo[1]/e:ColumnInfo">
<xsl:variable name="p" select="position()"/>
<xsl:value-of select="$record/e:ColumnData[$p]"/>
<xsl:if test="$p != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>

<xsl:text>
</xsl:text>
</xsl:template>

<!-- Work around known issue in Java 5 (Sun bug 6413803 inherited
from XALAN-2230) which means that the xsl:stripspace directive
doesn't work with XML name spaces. We explicitly trim text nodes.
-->
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>

</xsl:stylesheet>

  下面这个示例将使用该样式表生成CSV文件:

java weblogic.WLST process.py eventsToCSV.xsl events.xml > events.csv

生成事件树文件

  接下来我们需要使用一些技巧。导出数据文件含有各事件的信息,但是却没有记录事件之间的关系。通过使用时间信息,我们可以重新构造事件树,这样便可以了解代码各部之间的调用关系。如图6所示。



  图 6. eventToTree.xsl样式表用于将诊断导出文件转换为事件树文件。

  要构建事件树,我们将使用TraceElapsedTimeAction动作所记录的before和after事件之间的时间差。该时间差存储在after事件的事件有效载荷中。我们将抛弃不含有效载荷的事件,只留下after事件。通过从after事件时间信息减去有效载荷时间,我们可以算出开始时间信息,注意要转换为同样的单位(事件时间信息的单位为毫秒,而有效载荷时间的单位为纳秒)。

  我们通过开始和结束时间信息可以获得被监控方法的时间跨度。通过分析各时间跨度之间的包含关系,我们可以构建出事件树。

  WLDF控制台扩展 可以在服务器中生成类似的表示单个请求流动的事件树。由于控制台扩展的浏览方式非常快捷,我们的方法拥有一些优势:

通过使用merge.xsl合并多个诊断档案库中的事件,我们可以跟踪请求在多个服务器之间流动的情况。
结果将捕捉并保存到HTML报表中,以便发布和分发。

  我们只使用时间范围计算事件树,不会在其关系中使用诊断上下文。这样,样式表将极具通用性,但是事件也可能会被错误地标为其他事件的原因。要避免这一点,我们可以根据诊断上下文进行筛选。为此,可以在导出诊断档案库时指定适当的WLDF查询,或者提供含有一列使用上下文参数的诊断上下文的样式表。在实际情况中,我们可以首先找出想要的诊断上下文(方法是将所有诊断数据提取到一个CSV文件中),将其导入电子表格,然后查找不正常的(也可以是典型的)事务。

  样式表期望使用事件数据导出文件作为输入,并接收一个可选参数Contexts,该参数是数据源中包含的一列诊断上下文。如果没有指定上下文,那么TraceElapsedTimeAction记录的所有事件都将包括在内。

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:exslt="http://exslt.org/common" xmlns:e="http://www.bea.com/ns/weblogic/90/diagnostics/accessor/Export">

<xsl:output method="xml" indent="yes"/>

<xsl:variable name="RECORDID" select="count(//e:ColumnInfo[e:Name='RECORDID']/preceding-sibling::*) + 1"/>
<xsl:variable name="TIMESTAMP" select="count(//e:ColumnInfo[e:Name='TIMESTAMP']/preceding-sibling::*) + 1"/>
<xsl:variable name="CONTEXTID" select="count(//e:ColumnInfo[e:Name='CONTEXTID']/preceding-sibling::*) + 1"/>
<xsl:variable name="TXID" select="count(//e:ColumnInfo[e:Name='TXID']/preceding-sibling::*) + 1"/>
<xsl:variable name="USERID" select="count(//e:ColumnInfo[e:Name='USERID']/preceding-sibling::*) + 1"/>
<xsl:variable name="DOMAIN" select="count(//e:ColumnInfo[e:Name='DOMAIN']/preceding-sibling::*) + 1"/>
<xsl:variable name="SERVER" select="count(//e:ColumnInfo[e:Name='SERVER']/preceding-sibling::*) + 1"/>
<xsl:variable name="MONITOR" select="count(//e:ColumnInfo[e:Name='MONITOR']/preceding-sibling::*) + 1"/>
<xsl:variable name="CLASSNAME" select="count(//e:ColumnInfo[e:Name='CLASSNAME']/preceding-sibling::*) + 1"/>
<xsl:variable name="METHODNAME" select="count(//e:ColumnInfo[e:Name='METHODNAME']/preceding-sibling::*) + 1"/>
<xsl:variable name="PAYLOAD" select="count(//e:ColumnInfo[e:Name='PAYLOAD']/preceding-sibling::*) + 1"/>

<xsl:param name="contexts" select=""/>

<xsl:template match="/">
<xsl:variable name="sorted-nodes">
<xsl:for-each select="//e:DataRecord[e:ColumnData[$PAYLOAD] != '' and
($contexts = '' or contains($contexts, e:ColumnData[$CONTEXTID]))]">
<xsl:sort select="e:ColumnData[$TIMESTAMP] * 1000000 - e:ColumnData[$PAYLOAD]"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>

<xsl:variable name="nodes" select="exslt:node-set($sorted-nodes)/e:DataRecord"/>

<data>
<xsl:call-template name="processLevel">
<xsl:with-param name="nodes" select="$nodes"/>
<xsl:with-param name="basetime" select="$nodes[1]/e:ColumnData[$TIMESTAMP] * 1000000 - $nodes[1]/e:ColumnData[$PAYLOAD]"/>
</xsl:call-template>
</data>
</xsl:template>


<xsl:template name="processLevel">
<xsl:param name="nodes"/>
<xsl:param name="basetime"/>

<xsl:for-each select="$nodes">
<xsl:variable name="position" select="position()"/>
<xsl:variable name="endMS" select="e:ColumnData[$TIMESTAMP]"/>
<xsl:variable name="start" select="$endMS * 1000000 - e:ColumnData[$PAYLOAD]"/>

<!-- Output the nodes that are not fully enclosed by others in $nodes.

Nodes that overlap partially will all be output at this
level - their contents may contain duplicates at lower
levels.

Where the times match exactly, break the tie using the
document order. -->
<xsl:if test="not($nodes[(position() != $position) and
((e:ColumnData[$TIMESTAMP] * 1000000 - e:ColumnData[$PAYLOAD]) < $start and e:ColumnData[$TIMESTAMP] > = $endMS or
(e:ColumnData[$TIMESTAMP] * 1000000 - e:ColumnData[$PAYLOAD]) < = $start and e:ColumnData[$TIMESTAMP] > $endMS or
(e:ColumnData[$TIMESTAMP] * 1000000 - e:ColumnData[$PAYLOAD]) = $start and e:ColumnData[$TIMESTAMP] = $endMS and position() < $position
)]
)">

<record start="{$start}" offset="{$start - $basetime}" duration="{e:ColumnData[$PAYLOAD]}"
classname="{e:ColumnData[$CLASSNAME]}" methodname="{e:ColumnData[$METHODNAME]}"
domain="{e:ColumnData[$DOMAIN]}" server="{e:ColumnData[$SERVER]}" recordid="{e:ColumnData[$RECORDID]}"
userid="{e:ColumnData[$USERID]}" txid="{e:ColumnData[$TXID]}">

<!-- Recurse to include nodes in $nodes that we enclose. -->
<xsl:call-template name="processLevel">
<xsl:with-param name="nodes" select="$nodes[position() != $position and (e:ColumnData[$TIMESTAMP] * 1000000 - e:ColumnData[$PAYLOAD]) > = $start and e:ColumnData[$TIMESTAMP] < = $endMS]"/>
<xsl:with-param name="basetime" select="$start"/>
</xsl:call-template>
</record>
</xsl:if>
</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

格式化事件树文件

  我们所生成的事件树也是一个XML文件。可以在HTML中呈现,以便于大家理解,如图7所示。



  图 7. treeToHTML.xsl样式表可以将事件树文件转换为HTML报表。

  该样式表期望使用eventsToTree.xsl生成的事件树文件作为输入,没有参数。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output method="html"/>

<xsl:template match="/">
<html>
<body>
<table>
<tr>
<th></th>
<th>Offset</th>
<th>Method</th>
<th>Duration</th>
<th>Record</th>
<th>User</th>
<th>Transaction ID</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>

<xsl:template match="record">
<xsl:param name="indent" select=""/>
<xsl:param name="level" select="1"/>

<xsl:variable name="colour">
<xsl:choose>
<xsl:when test="$level=1">#F0D0D0</xsl:when>
<xsl:when test="$level=2">#D0D0F0</xsl:when>
<xsl:when test="$level=3">#C0C0E0</xsl:when>
<xsl:when test="$level=4">#B0B0D0</xsl:when>
<xsl:when test="$level=5">#A0A0C0</xsl:when>
<xsl:when test="$level=6">#9090B0</xsl:when>
<xsl:when test="$level=7">#8080A0</xsl:when>
<xsl:when test="$level=8">#707090</xsl:when>
<xsl:when test="$level=9">#606080</xsl:when>
<xsl:otherwise>#505070</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<tr bgcolor="{$colour}">
<td align="right">
<font size="-1">
<xsl:number level="any"/>
</font>
</td>
<td>
<xsl:value-of select="$indent"/>
<xsl:text>+</xsl:text>
<xsl:value-of select="format-number(@offset div 1000000, '0.00')"/>
</td>

<td>
<xsl:value-of select="$indent"/>
<xsl:value-of select="@classname"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="@methodname"/>
<xsl:text>()</xsl:text>
</td>

<td align="right"><xsl:value-of select="format-number(@duration div 1000000, '0.000')"/></td>

<td>
<xsl:value-of select="@domain"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="@server"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="@recordid"/>
</td>

<td>
<xsl:value-of select="@userid"/>
</td>

<td>
<xsl:value-of select="@txid"/>
</td>
</tr>

<xsl:apply-templates>
<xsl:with-param name="indent" select="concat('        ', $indent)"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

  就我目前正在研究的性能问题而言,这种格式相当有用。缩进用于表示事件中的继承关系。第一列的偏移量给出了父事件启动的时间,单位为毫秒。显然,我们也可以根据需要对eventsToTree.xsl和treeToHTML.xsl进行修改,使报表含有其他列或具有不同的格式。

读者练习

  读者可以自己尝试使用样式表将事件树文件转换为SVG图,或者添加适当的JavaScript使事件树具有导航性和动态性。

结束语

  WebLogic诊断框架是WebLogic Server中的一个强大且尚未充分应用的特性。我已经介绍了如何使用XSLT使诊断数据更具生命力。我这些技巧对于您的基于WebLogic Server的系统能够有所帮助。

参考资料
WebLogic Diagnostics Framework(WLDF)简介(中文版,Dev2Dev,2006年8月),作者为Rebecca Sly(Dev2Dev,2006)——关于WLDF的优秀入门教程
WLDF查询语言——产品文档
原文出处:http://dev2dev.bea.com/pub/a/2007/09/mining-wldf-xslt.html


作者简介
Philip Aston是BEA Services ( 专攻 WebLogic Server ) 的高级首席咨询师。他还维护 The Grinder , 一种开源负载测试工具。

推荐人评论

WebLogic诊断框架(WebLogic Diagnostic Framework,WLDF)是BEA WebLogic Server 9.0中引入的一个功能强大的子系统。在WLDF的帮助下,您可以监控和记录运行中的WebLogic Server域的一切行为。

用户评论

正在载入评论列表...

是谁推荐了此篇文章

专家头像李哲
个人blog发送信息
李哲推荐的其他文章

赞助商精华文章

热点新闻

热点评论

    精彩专题

    资源下载

    
      网站简介广告服务网站地图帮助联系方式诚聘英才English问题报告
    北京百联美达美数码科技有限公司 版权所有京 ICP 证 020026 号
    北京创新乐知广告有限公司 提供技术支持
    Copyright © 2000-2006, CSDN.NET, All Rights Reserved