/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.log.api; import java.io.FileNotFoundException; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TextFileLogger extends AbstractLogger { private final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TextFileLogger.class.getName()); private RotatingLogFileReader reader; private DateParser dateParser; public TextFileLogger(LoggerSpecification spec, LoggerFactory loggerFactory) throws FileNotFoundException, IOException { super("local", spec.getName(), spec.getDescription(), loggerFactory, spec.getLogCount(), spec.getLastLogDate(), spec.getConfig()); Properties config = spec.getConfig(); String filePath = config.getProperty("file.path"); String datePattern = config.getProperty("date.pattern"); if (datePattern == null) datePattern = "MMM dd HH:mm:ss"; String dateExtractor = config.getProperty("date.extractor"); if (dateExtractor == null || dateExtractor.isEmpty()) dateExtractor = dateFormatToRegex(datePattern); String dateLocale = config.getProperty("date.locale"); if (dateLocale == null) dateLocale = "en"; this.reader = new RotatingLogFileReader(filePath); String offset = config.getProperty("last_offset"); String firstLine = config.getProperty("first_line"); logger.trace("kraken log api: text logger [{}] last offset [{}], last line [{}]", new Object[] { spec.getName(), offset, firstLine }); reader.setFirstLine(firstLine); reader.setLastOffset(offset == null ? 0 : Long.valueOf(offset)); this.dateParser = new DefaultDateParser(new SimpleDateFormat(datePattern, new Locale(dateLocale)), dateExtractor); } private String dateFormatToRegex(String pattern) { StringBuilder regex = new StringBuilder(); boolean isInQuote = false; int l = pattern.length(); regex.append("("); for (int i = 0; i < l; i++) { if (i + 1 < l && pattern.charAt(i) == '\'') { if (pattern.charAt(i + 1) == '\'') { regex.append("'"); i++; } else { if (isInQuote) { if (pattern.charAt(i) == '\'') { isInQuote = false; continue; } regex.append(pattern.charAt(i)); continue; } else isInQuote = true; } continue; } int r = 1; while (i + 1 < l && pattern.charAt(i) == pattern.charAt(i + 1)) { r++; i++; continue; } switch (pattern.charAt(i)) { case 'G': regex.append("(AD|BC)"); break; case 'W': case 'F': regex.append("\\d" + repeat(1, r)); break; case 'E': if (r <= 3) regex.append(".{3}"); else regex.append("\\p{Upper}\\p{Lower}+day"); break; case 'a': regex.append("(AM|PM)"); break; case 'M': if (r > 3) { regex.append("(?i)(January|February|March|April|May|June|July|August|September|" + "October|November|December|Undecimber)"); break; } else if (r == 3) { regex.append(".{3}"); break; } case 'w': case 'd': case 'H': case 'k': case 'K': case 'h': case 'm': case 's': regex.append("\\d" + repeat(Math.max(1, r), Math.max(2, r))); break; case 'D': regex.append("\\d" + repeat(Math.max(1, r), Math.max(3, r))); break; case 'y': regex.append("\\d" + repeat(Math.max(1, r), Math.max(2, r))); break; case 'S': regex.append("\\d" + repeat(Math.max(1, r), Math.max(3, r))); break; case 'Z': regex.append("[+-]\\d" + repeat(4)); break; case '(': case ')': case '{': case '}': regex.append("\\"); default: regex.append(pattern.charAt(i)); if (r > 1) regex.append(repeat(r)); } } regex.append(")"); return regex.toString(); } private String repeat(int num) { return "{" + num + "}"; } private String repeat(int min, int max) { if (min == max) return repeat(min); return "{" + min + "," + max + "}"; } @Override protected void runOnce() { try { this.reader.open(); while (true) { if (getStatus() == LoggerStatus.Stopping || getStatus() == LoggerStatus.Stopped) break; String line = reader.readLine(); if (line == null) break; if (line.isEmpty()) continue; if (logger.isDebugEnabled()) logger.debug("kraken log api: text logger [{}], read line [{}]", getFullName(), line); Date date = dateParser.parse(line); if (date == null) { logger.trace("kraken log api: cannot parse date [{}]", line); return; } Map<String, Object> params = new HashMap<String, Object>(); params.put("date", date); params.put("line", line); Log log = new SimpleLog(date, getFullName(), params); write(log); } getConfig().put("first_line", reader.getFirstLine()); getConfig().put("last_offset", reader.getLastOffset()); logger.trace("kraken log api: name [{}], updated offset [{}]", getName(), reader.getLastOffset()); } catch (Exception e) { logger.error("kraken log api: cannot read log file", e); } finally { this.reader.close(); } } private class DefaultDateParser implements DateParser { private SimpleDateFormat dateFormat; private String dateExtractor; public DefaultDateParser(SimpleDateFormat dateFormat, String dateExtractor) { this.dateFormat = dateFormat; this.dateExtractor = dateExtractor; } @Override public Date parse(String line) { Pattern p = Pattern.compile(dateExtractor); Matcher m = p.matcher(line); if (!m.find() || m.groupCount() == 0) { logger.error("kraken log api: cannot find date extractor pattern in log file, " + reader.getFilePath()); return null; } do { for (int group = 1; group <= m.groupCount(); group++) { try { String dateString = m.group(group); Date date = dateFormat.parse(dateString); Calendar c = Calendar.getInstance(); int currentYear = c.get(Calendar.YEAR); c.setTime(date); int year = c.get(Calendar.YEAR); if (year == 1970) c.set(Calendar.YEAR, currentYear); return c.getTime(); } catch (ParseException e) { } } } while (m.find()); logger.error("kraken log api: cannot find date in log file, " + reader.getFilePath()); return null; } } }