自定义日志阅读器——包括了一个load取Tomcat日志的分析器

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

 最近在写往公司产品里添加Tomcat适配器,以支持Tomcat。有一些功能需要摘取到Tomcat的部分日志。没有合适的工具,也不想去网上找了,就自己写了一个。

 简单的画了一下设计方案:

 

下面直接上代码了:

日志阅读器:

复制代码
  1 package com.fjn.tools.log.reader;
  2 
  3 import java.io.File;
  4 import java.util.LinkedList;
  5 import java.util.List;
  6 import java.util.Scanner;
  7 
  8 import com.fjn.tools.log.reader.parser.CatalinaSimpleFormatterParser;
  9 
 10 public class LogReader {
 11     private String logFile;
 12     private List<LogFilter> logFilterChain = new LinkedList<LogFilter>();
 13     private final ContinueRead continueRead = new ContinueRead();
 14     private LogParser parser;
 15     private final boolean doFilter(LogRecord record) {
 16         for (LogFilter filter : logFilterChain) {
 17             if (!filter.accept(record)) {
 18                 return false;
 19             }
 20         }
 21         return true;
 22     }
 23 
 24     public void addFilter(LogFilter filter) {
 25         if(filter!=null){
 26             logFilterChain.add(filter);
 27         }
 28     }
 29 
 30     public final String readLogRecords(String startTime, String endTime) {
 31         if (parser == null) {
 32             return null;
 33         }
 34         StringBuilder buff = new StringBuilder();
 35         Scanner scanner = null;
 36         
 37         try {
 38             scanner = new Scanner(new File(logFile));
 39             
 40 
 41             NewLine newLine = null;
 42             if (startTime != null) {
 43                 StartTimeFilter filter = new StartTimeFilter();
 44                 filter.startTime = startTime;
 45                 addFilter(filter);
 46             }
 47             if (endTime != null) {
 48                 EndTimeFilter filter = new EndTimeFilter();
 49                 filter.endTime = endTime;
 50                 filter.continueRead = this.continueRead;
 51                 addFilter(filter);
 52             }
 53             while (scanner.hasNextLine() && continueRead.value) {
 54                 LogRecord record = null;
 55                 if (newLine == null) {
 56                     newLine = new NewLine();
 57                 }
 58                 if (!newLine.hasGetNewLine) {
 59                     newLine.line = scanner.nextLine();
 60                     newLine.hasGetNewLine = true;
 61                 }
 62                 record = parser.getLogRecord(scanner, newLine, continueRead);
 63                 if (record != null) {
 64                     if (doFilter(record)) {
 65                         buff.append(record.toString());
 66                     }
 67                 }
 68             }
 69         } catch (Exception ex) {
 70             // Ignore it
 71         } finally {
 72             if (scanner != null) {
 73                 scanner.close();
 74             }
 75         }
 76         return buff.toString();
 77     }
 78 
 79     public static interface LogParser {
 80         public LogRecord getLogRecord(Scanner scanner, NewLine newLine,
 81                 ContinueRead continueRead);
 82     }
 83 
 84     public static interface LogFilter {
 85         public boolean accept(LogRecord record);
 86     }
 87 
 88     public static abstract class LogRecord {
 89         public String prefix;
 90         public String message;
 91         public String threadStack;
 92         public String datetime;
 93     }
 94 
 95     public static class NewLine {
 96         public boolean hasGetNewLine = false;
 97         public String line = "";
 98     }
 99 
100     public static class ContinueRead {
101         public boolean value = true;
102     }
103 
104     private class StartTimeFilter implements LogFilter {
105         private String startTime;
106 
107         @Override
108         public boolean accept(LogRecord record) {
109             if (startTime == null) {
110                 return true;
111             }
112 
113             if (startTime.compareTo(record.datetime) <= 0) {
114                 return true;
115             }
116             return false;
117         }
118     }
119 
120     private class EndTimeFilter implements LogFilter {
121         private String endTime = "";
122         private ContinueRead continueRead;
123 
124         @Override
125         public boolean accept(LogRecord record) {
126             if (endTime == null || endTime.isEmpty()) {
127                 return true;
128             }
129             if (endTime.compareTo(record.datetime) < 0) {
130                 if (continueRead.value) {
131                     continueRead.value = false;
132                 }
133                 return false;
134             }
135             return true;
136         }
137     }
138     
139     
140     public String getLogFile() {
141         return logFile;
142     }
143 
144     public void setLogFile(String logFile) {
145         this.logFile = logFile;
146     }
147     
148 
149     public LogParser getParser() {
150         return parser;
151     }
152 
153     public void setParser(LogParser parser) {
154         this.parser = parser;
155     }
156 
157     public static void main(String[] args) {
158         LogReader logReader=new LogReader();
159         logReader.setLogFile("E:\\Program Files\\apache/tomcat/apache-tomcat-6.0.41/logs/catalina.2015-05-12.log");
160         logReader.setParser(new CatalinaSimpleFormatterParser());
161         System.out.println(logReader.readLogRecords("2015-10-12 01:53:10", null));
162     }
163 }
复制代码

接下来是一个Tomcat日志分析器:

复制代码
package com.fjn.tools.log.reader.parser;

import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.StringTokenizer;

import com.fjn.tools.log.reader.LogReader.ContinueRead;
import com.fjn.tools.log.reader.LogReader.LogParser;
import com.fjn.tools.log.reader.LogReader.LogRecord;
import com.fjn.tools.log.reader.LogReader.NewLine;

public class CatalinaSimpleFormatterParser implements LogParser {

    @Override
    public LogRecord getLogRecord(Scanner scanner, NewLine newLine,
            ContinueRead continueRead) {
        String line1 = newLine.line;
        if (!line1.matches(SimpleFormatterLogRecord.prefixPattern)) {
            newLine.hasGetNewLine = false;
            return null;
        }
        boolean toNextRecord = false;
        String nextLine = null;
        List<String> messageLines = new LinkedList<String>();
        while (!toNextRecord) {
            if (scanner.hasNextLine()) {
                nextLine = scanner.nextLine();
                if (!nextLine.matches(SimpleFormatterLogRecord.prefixPattern)) {
                    messageLines.add(nextLine);
                } else {
                    toNextRecord = true;
                    newLine.hasGetNewLine = true;
                    newLine.line = nextLine;
                    break;
                }
            } else {
                break;
            }
        }
        SimpleFormatterLogRecord record = new SimpleFormatterLogRecord();
        record.prefix = line1 + "\n";
        StringBuilder messageBuilder = new StringBuilder();
        StringBuilder threadStackBuilder = new StringBuilder();
        boolean toThreadStack = false;
        for (String lineN : messageLines) {
            if (!toThreadStack
                    && lineN.matches(SimpleFormatterLogRecord.threadStackStartPattern)) {
                toThreadStack = true;
            }
            if (toThreadStack) {
                threadStackBuilder.append(lineN).append("\n");
            } else {
                messageBuilder.append(lineN).append("\n");
            }
        }

        record.message = messageBuilder.toString();
        record.threadStack = threadStackBuilder.toString();

        StringTokenizer stk = new StringTokenizer(record.prefix);
        String date = stk.nextToken();
        String time = stk.nextToken();
        record.datetime = dateTimeFormat(date + " " + time);
        
        return record;
    }

    private class SimpleFormatterLogRecord extends LogRecord {
        private static final String prefixPattern = "^(\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2} ).*";
        private static final String threadStackStartPattern = "^((\\w+\\.)*\\w*Exception: ).*";

        public String toString() {
            return this.prefix + this.message + this.threadStack;
        }
    }
    
    private static String dateTimeFormat(String datetime){
        StringTokenizer stk = new StringTokenizer(datetime, "- :");
        int i = 0;
        StringBuilder dateTimeBuilder = new StringBuilder();
        while (stk.hasMoreTokens()) {
            i++;
            String token = stk.nextToken();
            if (i < 7 && token.length() < 2) {
                token = "0" + token;
            }
            if (i < 3) {
                token += "-";
            } else if (i < 4) {
                token += " ";
            } else if (i < 6) {
                token += ":";
            }
            dateTimeBuilder.append(token);
        }
        return dateTimeBuilder.toString();
    }

    public static void main(String[] args) {
        System.out.println(dateTimeFormat("2015-5-12 1:53:10 "));
    }
}
复制代码

 

1) 如果想要分析其它格式的日志,只需要做相应的扩展LogParser就行了。

2) 如果想要只找包含某些关键字的日志,只需要扩展LogFilter就可以了。

3) 如果想要取得某个时间段的日志,只需要指定相应的startTime,endTime参数就可以了。

 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
4月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
43 1
|
3月前
|
Shell Python
salt自定义模块内使用日志例子
salt自定义模块内使用日志例子
|
4月前
|
应用服务中间件 Linux iOS开发
使用 setenv 配置文件管理 Tomcat 的自定义环境变量
【8月更文挑战第29天】通过在Tomcat安装目录的`bin`文件夹下创建`setenv.sh`或`setenv.bat`文件,可以轻松管理Tomcat的自定义环境变量。针对Linux/macOS系统,需编辑`setenv.sh`文件,如`export MY_CUSTOM_VAR=&quot;my custom value&quot;`;而在Windows系统中,则编辑`setenv.bat`,如`set MY_CUSTOM_VAR=my custom value`。
243 1
|
4月前
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
|
4月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
4月前
|
Java 应用服务中间件 Windows
【Azure 应用服务】App Service for Windows 环境中为Tomcat自定义4xx/5xx页面
【Azure 应用服务】App Service for Windows 环境中为Tomcat自定义4xx/5xx页面
|
5月前
|
存储 Web App开发 Java
《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)
【7月更文挑战第13天】这篇文章介绍了如何在Java中创建一个简单的自定义日志系统,以替代Log4j或logback。
302 5
|
4月前
|
应用服务中间件 nginx
[nginx]日志中记录自定义请求头
[nginx]日志中记录自定义请求头
|
4月前
|
JSON 安全 Go
[golang]使用logrus自定义日志模块
[golang]使用logrus自定义日志模块