`
zengbo0710
  • 浏览: 414661 次
社区版块
存档分类
最新评论

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

阅读更多

有时候我需要查看已经部署到服务器上的应用程序的日志,每次都要远程登录服务器感觉很麻烦,所以一般我会把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
 

分享到:
评论

相关推荐

    DWR2.0 整合Spring2.0

    DWR2.0是DWR的一个版本,它在DWR1.x的基础上做了很多改进,增强了性能和易用性。而Spring框架则是一个广泛使用的轻量级Java企业级应用开发框架,它提供了一种模块化和灵活的方式来构建和管理应用程序。 在DWR2.0中...

    DWR2.0 中文手册

    7. **调试工具**:DWR提供了一个内置的调试工具,可以帮助开发者在开发过程中查看和调试DWR的通信过程,便于问题定位。 8. **性能优化**:DWR 2.0对性能进行了优化,如通过压缩和合并JavaScript文件来减少HTTP请求...

    dwr2.0 dwr3.0 jar包

    首先,DWR 2.0是DWR项目的一个早期版本,它引入了核心的远程方法调用(Remote Method Invocation, RMI)功能,使得JavaScript代码能够透明地调用Java对象的方法。在这个版本中,DWR提供了一套全面的API,包括自动...

    DWR2.0中文文档

    DWR是一个Java库,允许Web应用程序在浏览器和服务器之间进行实时通信,无需使用XMLHttpRequest或Flash等插件。它简化了Ajax(异步JavaScript和XML)的应用开发,提高了用户体验。这本书的内容既包含了作者的原创思考...

    DWR3.0.jar、DWR.war和DWR2.0中文说明文档

    DWR的实例war文件通常包含了一个预配置的DWR应用,展示了如何在实际项目中集成和使用DWR。通过分析这个war文件,开发者可以学习如何配置DWR的XML配置文件(dwr.xml),以及如何创建可从JavaScript调用的Java方法。 ...

    dwr 2.0 的 dtd 和官方网站首页

    在压缩包中的“开始dwr”文件可能是一个引导性的文档或教程,帮助开发者快速上手DWR 2.0的使用。而“dtd20”很可能是DWR 2.0的DTD文件,用于验证DWR配置文件的正确性。 总的来说,DWR 2.0是一个强大的工具,通过...

    dwr2.0最简单例子实用亲测试

    在“dwr2.0最简单例子实用亲测试”中,我们可以预期这是一个关于如何使用DWR 2.0版本的入门教程,包含了实际可运行的示例代码。下面将详细介绍DWR的基本概念和在这个实例中可能涉及的关键知识点: 1. **DWR的核心...

    dwr2.0 spring 3.0 整合示例

    Direct Web Remoting (DWR) 是一个开源的Java库,允许Web应用程序在浏览器和服务器之间进行实时的、安全的通信,而无需使用插件。DWR 2.0 版本是在DWR早期版本的基础上发展起来的,它提供了一系列增强功能,包括更好...

    Dwr3.0 与 Dwr2.0 区别

    假设我们有一个基于 DWR 2.0 的在线购物系统,需要实现一个“添加到购物车”的功能。在这个过程中,我们需要调用服务器端的 Java 方法来更新数据库中的商品库存。 **使用 DWR 2.0 实现:** 1. **配置文件 (`dwr....

    dwr2.0学习例子

    这个"**demo**"压缩包中可能包含了一个或多个DWR 2.0的示例项目,这些项目通常会展示如何配置DWR、如何在服务器端定义可调用的Java类、如何在客户端使用JavaScript进行调用,以及如何处理返回的数据。通过研究这些...

    DWR 2.0M3 学习笔记

    DWR 2.0M3 是该库的一个版本,其中的"M3"代表了第三个里程碑版本,通常意味着它已经相对成熟,但可能还有一些未解决的问题或待完善的特性。 在DWR 2.0M3的学习笔记中,我们可以深入探讨以下几个关键知识点: 1. **...

    Dwr最简单例子(2.0)

    在这个"Dwr最简单例子(2.0)"中,我们将探讨如何使用DWR 2.0设置一个基础的应用程序,以便理解其核心概念和工作原理。首先,我们需要了解DWR的基本组件: 1. **配置文件**:DWR的配置文件(通常为`dwr.xml`)定义了...

    DWR2.jar + DWR.xml + DWR2.0.dtd + Web.xml

    DWR2.0是DWR的一个版本,提供了一些增强特性和改进。 **DWR2.jar** 是DWR的主要库文件,包含了DWR框架的所有核心组件和实现。这个JAR文件包含了许多类,如`DWRServlet`,它是DWR与HTTP请求交互的核心组件,以及各种...

    简单购物车(dwr2.0)

    【标题】"简单购物车(dwr2.0)"是一个基于Web的购物车应用程序,它利用了Direct Web Remoting (DWR) 2.0框架。DWR是一种JavaScript库,允许在浏览器和服务器之间进行实时、异步的通信,使得前端与后端的数据交换变得...

Global site tag (gtag.js) - Google Analytics