自定义日志阅读器——包括了一个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日志并进行多维度分析。
相关文章
|
3月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
9天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
26 1
|
2月前
|
Shell Python
salt自定义模块内使用日志例子
salt自定义模块内使用日志例子
|
3月前
|
应用服务中间件 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`。
184 1
|
3月前
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
|
3月前
|
开发框架 .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中的问题
|
3月前
|
Java 应用服务中间件 Windows
【Azure 应用服务】App Service for Windows 环境中为Tomcat自定义4xx/5xx页面
【Azure 应用服务】App Service for Windows 环境中为Tomcat自定义4xx/5xx页面
|
3月前
|
应用服务中间件 nginx
[nginx]日志中记录自定义请求头
[nginx]日志中记录自定义请求头
|
3月前
|
JSON 安全 Go
[golang]使用logrus自定义日志模块
[golang]使用logrus自定义日志模块
|
3月前
|
存储 运维 Java
SpringBoot使用log4j2将日志记录到文件及自定义数据库
通过上述步骤,你可以在Spring Boot应用中利用Log4j2将日志输出到文件和数据库中。这不仅促进了良好的日志管理实践,也为应用的监控和故障排查提供了强大的工具。强调一点,配置文件和代码的具体实现可能需要根据应用的实际需求和运行环境进行调优和修改,始终记住测试配置以确保一切运行正常。
582 0