001package com.credibledoc.substitution.doc.module.substitution; 002 003import com.credibledoc.combiner.date.DateService; 004import com.credibledoc.combiner.log.buffered.LogBufferedReader; 005import com.credibledoc.combiner.log.buffered.LogFileReader; 006import com.credibledoc.combiner.node.file.NodeFile; 007import com.credibledoc.combiner.tactic.Tactic; 008import com.credibledoc.substitution.core.exception.SubstitutionRuntimeException; 009import com.credibledoc.substitution.doc.module.substitution.application.Substitution; 010import lombok.RequiredArgsConstructor; 011import org.springframework.stereotype.Service; 012 013import javax.inject.Inject; 014import java.io.File; 015import java.text.SimpleDateFormat; 016import java.util.Date; 017import java.util.regex.Matcher; 018import java.util.regex.Pattern; 019 020/** 021 * Implementation of the {@link Tactic} 022 * for the {@link Substitution}. 023 */ 024@Service 025@RequiredArgsConstructor(onConstructor = @__(@Inject)) 026public class SubstitutionTactic implements Tactic { 027 028 /** 029 * RegEx of a date in a {@link Substitution} log line, 030 * for example <pre>29.09.2018 22:53:42.494|https-jsse-nio-15443-exec-1...</pre> 031 */ 032 private static final String PATTERN_DATE_STRING = 033 "\\d\\d\\.\\d\\d\\.\\d\\d\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d"; 034 035 /** 036 * Compiled {@value #PATTERN_DATE_STRING} value 037 */ 038 private static final Pattern PATTERN_DATE = Pattern.compile(PATTERN_DATE_STRING); 039 040 /** 041 * {@link Pattern} of date and time of {@link Substitution}, for example 042 * for example <pre>29.09.2018 22:53:42.494|https-jsse-nio-15443-exec-1...</pre> 043 */ 044 private static final String DATE_FORMAT_STRING = "dd.MM.yyyy HH:mm:ss.SSS"; 045 private static final String ONE_SPACE = " "; 046 private static final int THREAD_NAME_INDEX = 35; 047 private static final String PIPE = "|"; 048 049 private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT_STRING); 050 051 @Override 052 public Date findDate(File file) { 053 try (LogBufferedReader logBufferedReader = new LogBufferedReader(new LogFileReader(file))) { 054 String line = logBufferedReader.readLine(); 055 while (line != null) { 056 Date date = parseDateFromLine(line); 057 if (date != null) { 058 return date; 059 } 060 line = logBufferedReader.readLine(); 061 } 062 return null; 063 } catch (Exception e) { 064 throw new SubstitutionRuntimeException("Cannot find date. File: " + file.getAbsolutePath(), e); 065 } 066 } 067 068 @Override 069 public Date findDate(String line, NodeFile nodeFile) { 070 return parseDateFromLine(line); 071 } 072 073 @Override 074 public boolean containsDate(String line) { 075 if (line == null) { 076 return false; 077 } 078 return PATTERN_DATE.matcher(line).find(); 079 } 080 081 @Override 082 public String parseDateStingFromLine(String line) { 083 if (line == null) { 084 return null; 085 } 086 return findDateString(line); 087 } 088 089 /** 090 * Parse a {@link Date} from a log line. 091 * 092 * @param line for example 093 * <pre>29.09.2018 22:53:42.494|https-jsse-nio-15443-exec-1...</pre> 094 * for {@link Substitution} 095 * @return a parsed {@link Date}, for example 13.04.2018 07:27:41.462 096 * or 'null' if the line is null or the date cannot be found. 097 */ 098 private Date parseDateFromLine(String line) { 099 if (line == null) { 100 return null; 101 } 102 try { 103 String clientDateString = findDateString(line); 104 if (clientDateString != null) { 105 return simpleDateFormat.parse(clientDateString); 106 } 107 108 return null; 109 } catch (Exception e) { 110 throw new SubstitutionRuntimeException("Cannot parse a date from the line: " + line, e); 111 } 112 } 113 114 /** 115 * Parse a {@link Date} from a log line. 116 * 117 * @param line for example 118 * <pre>29.09.2018 22:53:42.494|https-jsse-nio-15443-exec-1...</pre> 119 * for {@link Substitution} 120 * @return a parsed {@link Date}, for example 13.04.2018 07:27:41.462 or 'null' if the line is 'null' or the date cannot be found. 121 */ 122 private String findDateString(String line) { 123 int maxLength = line.length() > 90 ? 90 : line.length(); 124 String dateString = null; 125 Matcher matcher = PATTERN_DATE.matcher(line.substring(0, maxLength)); 126 if (matcher.find()) { 127 dateString = matcher.group(); 128 } 129 return dateString; 130 } 131 132 133 /** 134 * Examples: 135 * <pre>05.11.2018 08:37:08.100|https-jsse-nio-15443-exec-10|DEBUG|...</pre> 136 * <pre>19.12.2018 06:17:56.761 http-nio-8080-exec-305 INFO [1212121]...</pre> 137 */ 138 @Override 139 public String findThreadName(String line) { 140 int beginIndex = line.indexOf(PIPE); 141 int endIndex = line.indexOf(PIPE, beginIndex + 1); 142 143 if (isPipeSeparator(line)) { 144 if (beginIndex != -1 && endIndex != -1) { 145 return line.substring(beginIndex + PIPE.length(), endIndex); 146 } 147 } else { 148 int firstSpaceIndex = line.indexOf(ONE_SPACE); 149 int secondSpaceIndex = line.indexOf(ONE_SPACE, firstSpaceIndex + 1); 150 int thirdSpaceIndex = line.indexOf(ONE_SPACE, secondSpaceIndex + 1); 151 return line.substring(secondSpaceIndex + 1, thirdSpaceIndex); 152 } 153 154 return null; 155 } 156 157 private boolean isPipeSeparator(String line) { 158 return line.substring(0, THREAD_NAME_INDEX).contains(PIPE); 159 } 160 161 @Override 162 public Date findDate(String line) { 163 return DateService.getInstance().parseDateTimeFromLine(line, simpleDateFormat, PATTERN_DATE, 35); 164 } 165}