Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > Java > 用DWR2.0做的一个Server日志查看器
【标  题】:用DWR2.0做的一个Server日志查看器
【关键字】:DWR2.0,Server
【来  源】:http://www.blogjava.net/mstar/archive/2007/01/03/ajax_dwr2_logviewer.html

用DWR2.0做的一个Server日志查看器

Your Ad Here

有时候我需要查看已经部署到服务器上的应用程序的日志,每次都要远程登录服务器感觉很麻烦,所以一般我会把log文件的目录用apache做个网站,这样通过IE就可以访问到了。但是有时要看即时输出情况,就要不断的F5,很麻烦。所以就有个想法,不如用DWR2.0的反转Ajax来做个程序,让日志有变化时自动的发送到客户端,这样就我一个劲的按F5了。

我下面就把这个程序分享给大家,希望大家提提意见。

首先是环境:
DWR 2.0.rc1
Sun JDK 1.5

先看张运行起来的图吧,大家一看就知道这是个什么东西了。
logviewer.png
你可以制定要监视的log文件,当然有哪些文件文件可以被监视,你必须在服务端的xml配置中文件设置,当然你也可以监视一个目录里的log文件,这对于而log文件是每天生成一个的情况很有用。你可以设定在浏览器上显示的行数,操作行数,屏幕会自动滚动。你还可以添加一些过滤器,过滤掉不想看见的行,我目前只做了到了过滤掉一些信息,当然如果你有兴趣,你也再添加一些更复杂的过滤器。过滤器的模式是用正则表达式表示的。

下面是点击“开始监听”,运行后样子
logviewer2.png
如果服务器上的catalina.2006-12-09.log文件发生变化,客户端的浏览器上log显示区也会自动的向上滚动。


下面我就大致的介绍一下如何用DWR2.0来实现这样的功能。在这里介绍的可能不是很详细,不清楚的地方请看我提供的源码。

先来介绍一下目录结构
├─lib? -- 编译和测试用的第三方类库
├─webapp -- 部署目录
├─test -- 测试程序
├─java -- 主程序
└─build.xml -- ant构建文件

webapp下的文件和目录
│? style.css? -- 样式表文件
│? index.html -- 主画面文件

├─WEB-INF
│? │? web.xml -- 部署配置文件
│? │? dwr.xml -- dwr的配置文件
│? │? conf.xml -- 我们这个应用程序配置文件,主要是配置log文件
│? │
│? ├─classes
│? │
│? └─lib

└─script -- javascript文件


index.html中就是我们上面的图片上能看到的页面元素。其中的控件的事件处理都写在\script\logviewer.js文件中。

当页面加载时执行startPoll()方法,复杂开始与服务器的通信,并且把log文件选择框初始化,把已经添加过滤器列表显示出来。

function ?startPoll()?{
????DWREngine.setActiveReverseAjax(
true );

????LogManager.getLogFileNames(
function ?(data)?{
????????DWRUtil.removeAllOptions(
" log_file " );
????????DWRUtil.addOptions(
" log_file " ,?data);
????});

????LogManager.getFilters(
function (data)?{
????????
for ?( var ?i? = ? 0 ;?i? < ?data.length;?i ++ )?{
????????????addFilterDiv(data[i].pattern,?data[i].id);
????????}
????});
}


当点击“开始监听”按钮时调用服务端的LogManager的send方法,服务端开启监听线程,开始监听做为参数传递的文件,如果文件有变动就会把最近增加的行发送到浏览器上来。

var ?startWatch? = ? function ()?{
????clearLog();
????LogManager.send(DWRUtil.getValue(
" log_file " ));
}


当点击“结束监听”按钮,调用LogManager的stop()方法,结束掉监听线程。

function ?stopWatch()?{
????LogManager.stop();
}


当点击“清空日志”按钮,清除mainPanel中的所有子元素

function ?clearLog()?{
????
var ?mainPanel? = ?$( " main_panel " );
????
while ?(mainPanel.hasChildNodes())?{
????????mainPanel.removeChild(mainPanel.firstChild);
????}
}

当点击“添加过滤器”,填充输入框,要求输入做为过滤器的正则表达式,输入完成后,要做两件事:
1、LogManager.addFilter方法,把输入的正则表达式传送给服务端。
2、把这个正则表达式添加到页面上。

function ?addFilter()?{
????
var ?regex? = ?prompt( " 输入正则表达式 " ,? "" );
????
if ?(regex? != ? null ? && ?regex? != ? "" )?{
????????LogManager.addFilter(regex,?
function ?(filterId)?{
????????????addFilterDiv(regex,?filterId);
????????});
????}
}
注意这里,我们用到了DWR的回调模式,在调用服务端方法LogManager.addFilter成功后我们才调用客户端的addFilterDiv方法把这个输入的正则表达式显示到页面上。

如果你足够细心的话,应该会发现在这个js文件中有一个叫做addNewLine的方法在index.html中是没有被调用的。这个方法其实是给服务端的LogManager.send函数调用的。

上面这些内容就是服务端脚本的主要内容了,其实很简单。主要负责通过DWR与服务端通信和处理页面显示。

下面介绍服务端的核心类:LogManager

这个类主要就这样几个方法:
???/**
?????*?停止监控
?????
*/
????
public?void?stop()?{
????????
if?(watcher?!=?null)?{
????????????watcher.halt();
????????}
????}

????
/**
?????*?发送log信息
?????
*/
????
public?void?send(String?filename)?{
????????WebContext?wctx?
=?WebContextFactory.get();
????????
final?ScriptSession?scriptSession?=?wctx.getScriptSession();
????????
if?(watcher?!=?null)?{
????????????watcher.halt();
????????}

????????
try?{
????????????watcher?
=?new?LogFileWatcher(filename);
????????????watcher.addListener(
new?LogUpdateListener()?{
????????????????
public?void?onLogUpdate(List<String>?lines)?{
????????????????????
for?(String?line?:?lines)?{
????????????????????????
if?(checkFilters(line))?{
????????????????????????????ScriptBuffer?scriptBuffer?
=?new?ScriptBuffer();
????????????????????????????scriptBuffer.appendScript(
"addNewLine(")
????????????????????????????????????.appendData(line)
????????????????????????????????????.appendScript(
");");
????????????????????????????scriptSession.addScript(scriptBuffer);
????????????????????????}
????????????????????}
????????????????}
????????????});
????????????watcher.start();
????????}?
catch?(IOException?e)?{
????????????ScriptBuffer?scriptBuffer?
=?new?ScriptBuffer();
????????????scriptBuffer.appendScript(
"addNewLine(")
????????????????????.appendData(e.getMessage())
????????????????????.appendScript(
");");
????????????scriptSession.addScript(scriptBuffer);
????????????log.warn(e);
????????}
????}

????
/**
?????*?取得指定的日志文件路径
?????*
?????*?
@return?指定的日志文件路径
?????
*/
????
public?List<String>?getLogFileNames()?{
????????List
<String>?filenames?=?new?ArrayList<String>();
????????
try?{
????????????XMLConfiguration?config?
=?getConfiguration();
????????????List?logfiles?
=?config.getList("log-files.file");
????????????
for?(Object?o?:?logfiles)?{
????????????????filenames.add((String)?o);
????????????}
????????}?
catch?(ConfigurationException?e)?{
????????????log.warn(e);
????????}

????????
return?filenames;
????}

????
/**
?????*?取得指定的日志目录下的文件
?????*
?????*?
@return?指定的日志目录下的文件
?????
*/
????
public?List<String>?getLogFileNamesFromDir()?{
????????List
<String>?filenames?=?new?ArrayList<String>();
????????
try?{
????????????XMLConfiguration?config?
=?getConfiguration();
????????????String?dir?
=?config.getString("log-dir.dir");
????????????
if?(dir?!=?null)?{
????????????????File?rootDir?
=?new?File(dir);
????????????????
if?(rootDir.exists())?{
????????????????????
if?(rootDir.isFile())?{
????????????????????????filenames.add(rootDir.getPath().replace(
'\\',?'/'));
????????????????????}?
else?if?(rootDir.isDirectory())?{
????????????????????????String?patternString?
=?config.getString("log-dir.filter");
????????????????????????File[]?files;
????????????????????????
if?(patternString?!=?null?&&?!patternString.equals(""))?{
????????????????????????????files?
=?rootDir.listFiles(new?LogFileFilter(patternString));
????????????????????????}?
else?{
????????????????????????????files?
=?rootDir.listFiles();
????????????????????????}

????????????????????????
for?(File?file?:?files)?{
????????????????????????????filenames.add(file.getPath().replace(
'\\',?'/'));
????????????????????????}
????????????????????}
????????????????}
????????????}
????????}?
catch?(ConfigurationException?e)?{
????????????log.warn(e);
????????}

????????
return?filenames;
????}

????
/**
?????*?添加一个过滤器,返回过滤器的id
?????
*/
????
public?int?addFilter(String?regex)?{
????????
synchronized?(filters)?{
????????????Filter?filter?
=?new?Filter(regex,?SequenceGenerator.getInstance().next(),?FilterType.INCLUDE);
????????????filters.add(filter);
????????????
return?filter.getId();
????????}

????}

????
/**
?????*?根据id删除一个过滤器
?????
*/
????
public?void?removeFilter(int?id)?{
????????
synchronized?(filters)?{
????????????filters.remove(
new?Filter(id));
????????}
????}

????
/**
?????*?取得现在所有的过滤器列表
?????
*/
????
public?List<Map<String,?Object>>?getFilters()?{
????????List
<Map<String,?Object>>?result?=?new?ArrayList<Map<String,?Object>>();
????????
synchronized?(filters)?{
????????????
for?(Filter?filter?:?filters)?{
????????????????Map
<String,?Object>?filterItem?=?new?HashMap<String,?Object>();
????????????????filterItem.put(
"id",?filter.getId());
????????????????filterItem.put(
"pattern",?filter.getPattern().pattern());
????????????????result.add(filterItem);
????????????}
????????}
????????
return?result;
????}

对于大家都做过Java的朋友来说,这些代码应该很容易就能看懂,我就不多说了。大家主要注意一下ScriptSession类,这个类就是起到主要功能的类了。

其中的LogFileWatcher是一个Thread类,它是用来监视log文件的。

SequenceGenerator.java是用来生成过滤器的id的。

LogUpdateListener.java是一个接口,用于实现事件回调的。

然后看一个dwr的配置文件
<dwr>
????
<allow>
????????
<create?creator="new"?javascript="LogManager"?scope="session">
????????????
<param?name="class"?value="org.devside.logviewer.LogManager"/>
????????????
<include?method="send"/>
????????????
<include?method="stop"/>
????????????
<include?method="getLogFileNames"/>
????????????
<include?method="getLogFileNamesFromDir"/>
????????????
<include?method="addFilter"/>
????????????
<include?method="removeFilter"/>
????????????
<include?method="getFilters"/>
????????
</create>
????
</allow>
</dwr>

这里的配置文件和1.x几乎没什么两样,就是scope我这里设置成了session范围的。这样就可以多个人同时监视不同的log文件了。

web.xml文件也基本上是老样子
<?xml?version="1.0"?encoding="UTF-8"?>
<web-app?id="LogViewer"?version="2.4"
?????????xmlns
="http://java.sun.com/xml/ns/j2ee"
?????????xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
?????????xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee?http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
????
<display-name>Web?Log?Viewer</display-name>

????
<servlet>
????????
<description>Direct?Web?Remoter?Servlet</description>
????????
<display-name>DWR?Servlet</display-name>
????????
<servlet-name>dwr-invoker</servlet-name>
????????
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
????????
<init-param>
????????????
<param-name>debug</param-name>
????????????
<param-value>true</param-value>
????????
</init-param>
????????
<init-param>
????????????
<param-name>pollAndCometEnabled</param-name>
????????????
<param-value>true</param-value>
????????
</init-param>
????????
<load-on-startup>1</load-on-startup>
????
</servlet>

????
<servlet-mapping>
????????
<servlet-name>dwr-invoker</servlet-name>
????????
<url-pattern>/dwr/*</url-pattern>
????
</servlet-mapping>

????
<welcome-file-list>
????????
<welcome-file>index.html</welcome-file>
????
</welcome-file-list>
</web-app>
dwr的包名发生了变化,并且要开启反转ajax,就要把pollAndCometEnabled参数设置为true。

总结,总体来说DWR2.0中的反转ajax还是很容易使用的,这也是dwr的一贯风格,不用知道过多的细节就能容易的实现ajax。dwr绝对是Java开发者的首选ajax框架。
另外我这个程序其实还是为了演示用的,如果想要用户实际开发可能还需要修改,比如安全性上面,性能上面。而性能上面的主要问题是客户端浏览器,如果服务端的log文件过大,而浏览器有不能即时的回收内存,就会造成客户端浏览器内存占用过大而死掉的问题。而服务端由于java的内容回收机制已经比较成熟应该不会有什么问题。我在ie6和firefox2都试过了,firefox效果能好一些。

源码下载:
http://www.blogjava.net/Files/mstar/LogViewer.part1.rar
http://www.blogjava.net/Files/mstar/LogViewer.part2.rar
swt 简单的托盘程序:【上一篇】
xjl:Rhino的两个问题:【下一篇】
【相关文章】
  • 欢迎喜欢vc++和SQL SERVER数据库编程的朋友和我交流!
  • Win 2003 Server重新安装Oracle9i
  • description The server encountered an internal error () that prevented it from fulfilling this reque...
  • 如何把Access 数据导出到SQL Server?
  • SQL Server各种日期计算方法
  • SQL Server 管理常用SQL和T-SQL语句
  • Oralce names server简介
  • 回归命令行 SQLServer的命令行工具们(2) – sqlcmd.exe(中篇)
  • ZT:如何用Python访问SQLServer的代码示例
  • 回归命令行 SQLServer的命令行工具们(2) – sqlcmd.exe(上篇)
  • 【随机文章】
  • VBScript 赋值运算符 (=)
  • VBScript Execute 语句
  • oracle OCP指南
  • 谈linux磁盘结构及分区
  • ASANTE蓝色小精灵路由器FR3004LC
  • 小心被忽悠 揭露低价电脑背后的秘密
  • 第16届Jolt Product Excellence奖
  • 在C++的虚继承中要注意的一个传值问题
  • 我的收藏:Community Server专题五:IHttpHandlerFactory
  • PHP中实现进程间通讯
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.