最近在写往公司产品里添加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参数就可以了。