Web下查看Tomcat日志–Java

in Java with 0 comment

由于系统刚刚上线,各种未知bug层出不穷,应用服务和数据库服务双双被隔离,无法被外界访问,无法抓住问题的源头,基于运维的需要就在系统上添加了查看运行日志的功能。现有多个子系统应用分别部署在不同的服务器里,只能通过外网子应用访问内网子应用,现在想通过外网子应用与内网子应用间的通讯,让外网可以查看内网子应用的日志。现以部署在外网的应用为例,查看外网日志,记录下工作例程。外网子应用是部署在Windows server的Tomcat下,查看Tomcat的输出日志。
功能很简单,点击查看后,可以以一定的时间间隔不停地将日志输出在屏幕上,并提供暂停和中断按钮。先配置好Tomcat运行日志重定向到日志文件。

1.View

在页面上布局操作按钮和输出日志,输出日志以背景为黑色,字体为蓝色,代码如下:

<div id=“body”>
        <div class=“well with-header”>
            <div class=“header bg-themeprimary”>
                <strong>查看日志</strong>
            </div>
            <form id=“defaultForm” class=“form form-horizontal bv-form” role=“form” action=“ckrzsj!show.do” method=“post”>
                <div class=“form-group”>
                    <div class=“col-sm-1”>
                        <button id=“ckrqsj” type=“button” onclick=“javascript:tockrz();” class=“btn btn-primary input-sm”><i class=“fa fa-print”></i>CheckLog</button>
                    </div>
                    <div class=“col-sm-1”>
                        <button id=“ckrqsj2” type=“button” onclick=“javascript:terminate();” class=“btn btn-primary input-sm”
                            style=“display:none;”>
                        <i class=“fa fa-ban”></i>Terminate</button>
                    </div>
                </div>
                <div class=“form-group”>
                    <div style=“margin-bottom: 5px;background-color: black;color: green;font-weight: bold;font-size: 14px;’Times New Roman,Georgia,Serif'”
                        class=“well bordered-left bordered-pink”>
                            <div class=“row”>
                                <div class=“col-sm-12” id=“logs”>
                                </div>
                            </div>
                    </div>
                </div>
            </form>
        </div>
    </div>

JavaScript上以10秒时间间隔异步读取当前读取行数至日志文件末尾的数据,并更新当前读取行数。

<script type=“text/javascript”>
        var line = 1;//访问日志的当前行数
        var timeout = 0;
        var isStoping = false;
        function tockrz(){
            isStoping = !isStoping;
            if(isStoping){
                $(“#ckrqsj”).html(“<i class=’fa fa-ban’></i>Stop”);
                ckrz();
                timeout =setInterval(ckrz, 10000);
                $(“#ckrqsj2”).show();
            }
            else {
                $(“#ckrqsj”).html(“<i class=’fa fa-print’></i>CheckLog”);
                clearInterval(timeout);
                $(“#ckrqsj2”).hide();
            }
        }
        function ckrz(){
            $.ajax({
                url:“<%=path%>/ckrzsj!getRz.do”,
                type:“post”,
                async: false,
                cache: false,
                dataType:“json”, //这里返回的类型有:json,html,xml,text
                data:{
                    line:line
                },
                beforeSend:function(){
                },
                success:function(data,textStatus){
                    var datas = “”;
                    var lines = data.lineList;
                    line = data.line;
                    for(var i=0;i<lines.length;i++){
                        datas += lines[i];
                    }
                    $(‘#logs’).append(‘<p>’+datas+'</p>’);
   // 滚到屏幕下方                 window.scrollTo(0,document.body.scrollHeight); 
                }
            });
        }
        function terminate(){ // 中断后重置数据
            line = 1;
            isStoping = false;
            $(“#ckrqsj”).html(“<i class=’fa fa-print’></i>CheckLog”);
            clearInterval(timeout);
            $(“#logs”).empty();
            $(“#ckrqsj2”).hide();
        }
    </script>

2.Action

先判断当前操作系统类型,并调用相应系统的查看日志方法,并将结果返回给页面。

public class CkrzAction {
    private int line;
    public int getLine() {
        return line;
    }
    public void setLine(int line) {
        this.line = line;
    }
    public String show(){
        return “show”;
    }
    public String getRz() throws Exception{
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType(“text/json;charset=UTF-8”);
        response.setHeader(“Cache-Control”, “no-cache”);
        PrintWriter out = response.getWriter();
        List<String> lines = new ArrayList<String>();
        int l = line;
        if(!OSType.isWindows()) {
            l = LinuxCall.callCmd(lines, line);
        }
        else {
            l = WindowCall.callCmd(lines, line);
        }
        Map<String, Object> datas = new HashMap<String,Object>();
        datas.put(“lineList”, lines);
        datas.put(“line”, l);
        out.println(JSONObject.fromObject(datas));
        out.flush();
        out.close();
        return null;
    }
}

3.查看日志方法

Windows下直接读取文件日志,有点坑。。。

public class WindowCall {
    private static String logFile = “D:\\apache-tomcat-8.0.24\\logs\\catalina.out”;
    static {
        InputStream input = LinuxCall.class.getClassLoader().getResourceAsStream(“logPath.properties”);
        Properties p = new Properties();
        try {
            p.load(input);
            logFile = p.getProperty(“logpath”);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static int callCmd(List<String> lines,int line) throws Exception{
        if(lines==null){
            return 1;
        }
        BufferedReader read = null;
        try{
            read = new BufferedReader(new InputStreamReader(new FileInputStream(new  File(logFile))));
            String l = null;
            int startline = 0;
            while((l = read.readLine())!=null){
                if(++startline>=line){
                    line++;
                    lines.add(l);
                }
            }
        }
        finally{
            if(read!=null) {
                read.close();
            }
        }
        return line;
    }
    public static void main(String[] args) {
        try {
            List<String> lines = new ArrayList<String>();
            WindowCall.callCmd(lines,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Linux下直接调用shell命令,频繁使用,性能损耗较大。

public class LinuxCall {
    private static String logFile = “/home/tomcat/logs/catalina.out”;
    static {
        InputStream input = LinuxCall.class.getClassLoader().getResourceAsStream(“logPath.properties”);
        Properties p = new Properties();
        try {
            p.load(input);
            logFile = p.getProperty(“logpath”);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static int callCmd(List<String> lines,int line) throws Exception{
        if(lines==null){
            return 1;
        }
        String cmd = “nl “ + logFile + “|sed -n ‘” + line + “,$p'”;
        String[] cmds = {“/bin/sh”,“-c”,cmd};
        Process pro = Runtime.getRuntime().exec(cmds);
        pro.waitFor();
        InputStream in = pro.getInputStream();
        BufferedReader read = new BufferedReader(new InputStreamReader(in));
        String l = null;
        while((l = read.readLine())!=null){
            line++;
            lines.add(l);
        }
        return line;
    }
    public static void main(String[] args) {
        try {
            List<String> lines = new ArrayList<String>();
            LinuxCall.callCmd(lines,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.日志路径

logPath.properties

#logpath=/home/tomcat/logs/catalina.out

logpath=D\:\\apache-tomcat-8.0.24\\logs\\catalina.out

5.系统类型

通过JVM调用系统参数,判断操作系统类型

public class OSType {
    private static String os = System.getProperty(“os.name”).toLowerCase();
    private OSType(){}
    public static String getOsName(){
        return os;
    }
    public static boolean isWindows(){
        return os.indexOf(“windows”) >= 0;
    }
    public static boolean isLinux(){
        return os.indexOf(“linux”) >= 0;
    }
    public static void main(String[] args) {
        System.out.println(OSType.isWindows());
        System.out.println(OSType.isLinux());
        System.out.println(os);
    }
}

6.结果

进入页面:

开始日志

点击查看:

日志

在Action层加上子系统间的通讯服务,并将View与其他层的分离,就可以达到目的了。还有就是日志I/O频繁的问题,考虑到日志重定向到文件时按日期分割,减少文件大小,后面又要改程序。最后就是,只做日志下载功能不就可以了,干嘛还这么麻烦。。。