本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7593343
建立时间:2006年5月29日




[DWR(Ajax)]用DWR2.0做的一个Server日志查看器
软件技术

lhwork 发表于 2007/1/4 22:43:17

有时候我需要查看已经部署到服务器上的应用程序的日志,每次都要远程登录服务器感觉很麻烦,所以一般我会把log文件的目录用apache做个网 站,这样通过IE就可以访问到了。但是有时要看即时输出情况,就要不断的F5,很麻烦。所以就有个想法,不如用DWR2.0的反转Ajax来做个程序,让 日志有变化时自动的发送到客户端,这样就我一个劲的按F5了。我下面就把这个程序分享给大家,希望大家提提意见。首先是环境:DWR 2.0.rc1Sun JDK 1.5先看张运行起来的图吧,大家一看就知道这是个什么东西了。500)this.width=500'>你 可以制定要监视的log文件,当然有哪些文件文件可以被监视,你必须在服务端的xml配置中文件设置,当然你也可以监视一个目录里的log文件,这对于而 log文件是每天生成一个的情况很有用。你可以设定在浏览器上显示的行数,操作行数,屏幕会自动滚动。你还可以添加一些过滤器,过滤掉不想看见的行,我目 前只做了到了过滤掉一些信息,当然如果你有兴趣,你也再添加一些更复杂的过滤器。过滤器的模式是用正则表达式表示的。下面是点击“开始监听”,运行后样子500)this.width=500'>如果服务器上的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.rarhttp://www.blogjava.net/Files/mstar/LogViewer.part2.rar


阅读全文(4396) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.047 second(s), page refreshed 144779121 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号