/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.systemservices.impl.logsvc.stream; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.compress.compressors.CompressorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.systemservices.impl.logsvc.LogMessage; import com.emc.storageos.systemservices.impl.logsvc.LogStatusInfo; import com.emc.storageos.systemservices.impl.logsvc.parse.LogNginxAccessParser; import com.emc.storageos.systemservices.impl.logsvc.parse.LogNginxErrorParser; import com.emc.storageos.systemservices.impl.logsvc.parse.LogParser; import com.emc.storageos.systemservices.impl.logsvc.parse.LogServiceParser; import com.emc.storageos.systemservices.impl.logsvc.parse.LogSyslogParser; import com.emc.storageos.systemservices.impl.logsvc.util.LogUtil; import com.emc.vipr.model.sys.logging.LogRequest; /** * Reader that reads logs from the specific file, regular or compressed file. * Parse each log to LogMessage * * @author siy */ public class LogReader implements LogStream { private BufferedReader reader; private LogRequest request; private long logCount; private LogMessage currentLog = null; private LogParser parser = null; private static List<LogParser> parserTable = new LinkedList<>(); private LogStatusInfo status = null; private final String filePath; private int fileLineNumber = 0; private String service; private Pattern pattern; // Logger reference. private static final Logger logger = LoggerFactory.getLogger(LogReader.class); static { LogParser logSvcParser = new LogServiceParser(); LogParser logSyslogParser = new LogSyslogParser(); LogParser logNginxAccessParser = new LogNginxAccessParser(); LogParser logNginxErrorParser = new LogNginxErrorParser(); parserTable.add(logSvcParser); parserTable.add(logSyslogParser); parserTable.add(logNginxAccessParser); parserTable.add(logNginxErrorParser); } public LogReader(String path, LogRequest req, LogStatusInfo status, String service) throws IOException, CompressorException { if (LogUtil.logFileZipped(path)) { reader = LogUtil.getBufferedReaderForBZ2File(path); } else { reader = new BufferedReader(new FileReader(path)); } request = req; if (req.getRegex() != null) { pattern = Pattern.compile(req.getRegex(), Pattern.DOTALL | Pattern.MULTILINE); } this.status = status; this.filePath = path; this.service = service; } /** * Read one log message from log file * * @return * @throws IOException */ @Override public LogMessage readNextLogMessage() { // logger.info("readMessage()"); try { if (reader == null) { return null; } while (true) { String line = reader.readLine(); if (line == null) { close(); if (currentLog != null && matchRegex(currentLog)) { incrementLogCount(currentLog); return currentLog; } return null; } fileLineNumber++; LogMessage nextLog = null; if (parser != null) { // already find the match parser nextLog = parser.parseLine(line, request); } else { // match parser for (LogParser parser : parserTable) { nextLog = parser.parseLine(line, request); if (!nextLog.isContinuation()) { this.parser = parser; break; } } // this line does not match all parsers, skip it and write it into status if (nextLog == null || nextLog.isContinuation()) { status.appendInfo(this.filePath, fileLineNumber); continue; } } if (nextLog.isContinuation()) { if (currentLog != null) { currentLog.appendMessage(LogUtil.stringToBytes(line)); } } else if (nextLog.isRejected()) { // matches the log pattern, but does not match filters // logs are only rejected in the first line if (currentLog != null) { LogMessage returnedLog = currentLog; currentLog = null; if (matchRegex(returnedLog)) { incrementLogCount(returnedLog); return returnedLog; } // else read the next line } } else if (nextLog.isRejectedLast()) { // log is too late if (currentLog != null) { LogMessage returnedLog = currentLog; currentLog = null; if (matchRegex(returnedLog)) { incrementLogCount(returnedLog); return returnedLog; } // else break from the loop } break; } else { // accepted as the first line of a new log message if (currentLog != null) { LogMessage returnedLog = currentLog; currentLog = nextLog; // in case of multiple adjacent header logs // skip all but the last one if (returnedLog.isHeader() && currentLog.isHeader()) { continue; } if (matchRegex(returnedLog)) { incrementLogCount(returnedLog); return returnedLog; } // else read the next line } else { currentLog = nextLog; } } } } catch (IOException e) { status.appendErrFileName(filePath); } return null; } private void incrementLogCount(LogMessage returnedLog) { if (!returnedLog.isHeader()) { logCount++; } } private void close() { try { if (reader != null) { reader.close(); } } catch (Exception e) { logger.error("Failed to close LogReader:", e); } finally { reader = null; } } private boolean matchRegex(LogMessage message) { if (pattern == null) { return true; } if (message == null) { return false; } return pattern.matcher(new String(message.getLogContent())).matches(); } public LogRequest getRequest() { return request; } public void setRequest(LogRequest request) { this.request = request; } public long getLogCount() { return this.logCount; } }