/* * Lilith - a log event viewer. * Copyright (C) 2007-2015 Joern Huxhorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.huxhorn.lilith.tools; import de.huxhorn.lilith.api.FileConstants; import de.huxhorn.lilith.conditions.GroovyCondition; import de.huxhorn.lilith.data.access.AccessEvent; import de.huxhorn.lilith.data.eventsource.EventWrapper; import de.huxhorn.lilith.data.logging.LoggingEvent; import de.huxhorn.lilith.engine.AccessFileBufferFactory; import de.huxhorn.lilith.engine.LogFileFactory; import de.huxhorn.lilith.engine.LoggingFileBufferFactory; import de.huxhorn.lilith.engine.impl.LogFileFactoryImpl; import de.huxhorn.lilith.swing.callables.IndexingCallable; import de.huxhorn.lilith.tools.formatters.AccessFormatter; import de.huxhorn.lilith.tools.formatters.Formatter; import de.huxhorn.lilith.tools.formatters.LoggingFormatter; import de.huxhorn.sulky.buffers.AppendOperation; import de.huxhorn.sulky.buffers.Buffer; import de.huxhorn.sulky.buffers.FileBuffer; import de.huxhorn.sulky.codec.filebuffer.DefaultFileHeaderStrategy; import de.huxhorn.sulky.codec.filebuffer.FileHeader; import de.huxhorn.sulky.codec.filebuffer.FileHeaderStrategy; import de.huxhorn.sulky.codec.filebuffer.MetaData; import de.huxhorn.sulky.codec.filebuffer.ReadOnlyExclusiveCodecFileBuffer; import de.huxhorn.sulky.io.IOUtilities; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FilterCommand { public static boolean filterFile(File inputFile, File outputFile, File conditionFile, String searchString, String pattern, boolean overwrite, boolean keepRunning, boolean exclusive) { final Logger logger = LoggerFactory.getLogger(FilterCommand.class); File inputDataFile = FileHelper.resolveDataFile(inputFile); String inputDataFileStr = inputDataFile.getAbsolutePath(); if (!inputDataFile.isFile()) { if (logger.isErrorEnabled()) logger.error("'{}' is not a file!", inputDataFileStr); return false; } if (!inputDataFile.canRead()) { if (logger.isErrorEnabled()) logger.error("Can't read '{}'!", inputDataFileStr); return false; } if(exclusive) { keepRunning = false; } File inputIndexFile = FileHelper.resolveIndexFile(inputFile); //String inputIndexFileStr = inputIndexFile.getAbsolutePath(); long inputDataModified = inputDataFile.lastModified(); //File indexFile = new File(indexFileStr); if (!inputIndexFile.isFile()) { // Index file does not exist. IndexCommand.indexLogFile(inputDataFile); } else { // Previous index file was found long inputIndexModified = inputIndexFile.lastModified(); if (inputIndexModified < inputDataModified) { // Index file is outdated. IndexCommand.indexLogFile(inputDataFile); } } String scriptFileName = conditionFile.getAbsolutePath(); GroovyCondition groovyCondition = new GroovyCondition(scriptFileName); if(searchString != null) { groovyCondition.setSearchString(searchString); } File outputDataFile = FileHelper.resolveDataFile(outputFile); String outputDataFileStr = outputDataFile.getAbsolutePath(); File outputIndexFile = FileHelper.resolveIndexFile(outputFile); String outputIndexFileStr = outputIndexFile.getAbsolutePath(); if(overwrite) { if(outputDataFile.delete()) { if(logger.isDebugEnabled()) logger.debug("Deleted {}.", outputDataFileStr); } if(outputIndexFile.delete()) { if(logger.isDebugEnabled()) logger.debug("Deleted {}.", outputIndexFileStr); } } if(outputDataFile.isFile()) { long outputDataModified = outputDataFile.lastModified(); if(!outputIndexFile.isFile()) { // Index file does not exist. IndexCommand.indexLogFile(outputDataFile); } else { // Previous index file was found long outputIndexModified = outputIndexFile.lastModified(); if (outputIndexModified < outputDataModified) { // Index file is outdated. IndexCommand.indexLogFile(outputDataFile); } } } FileHeaderStrategy fileHeaderStrategy = new DefaultFileHeaderStrategy(); try { FileHeader header = fileHeaderStrategy.readFileHeader(inputDataFile); if (header == null) { if (logger.isWarnEnabled()) { logger.warn("Couldn't read file header from '{}'!", inputDataFileStr); } return false; } if (header.getMagicValue() != FileConstants.MAGIC_VALUE) { if (logger.isWarnEnabled()) { logger.warn("Invalid magic value! ", Integer.toHexString(header.getMagicValue())); } return false; } MetaData metaData = header.getMetaData(); if (metaData == null || metaData.getData() == null) { if (logger.isWarnEnabled()) { logger.warn("Couldn't read meta data from '{}'!", inputDataFileStr); } return false; } Map<String, String> data = metaData.getData(); String contentType = data.get(FileConstants.CONTENT_TYPE_KEY); LogFileFactory logFileFactory = new LogFileFactoryImpl(new File(".")); if (FileConstants.CONTENT_TYPE_VALUE_LOGGING.equals(contentType)) { Map<String, String> loggingMetaData = new HashMap<>(); loggingMetaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_LOGGING); loggingMetaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); loggingMetaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); LoggingFileBufferFactory fileBufferFactory = new LoggingFileBufferFactory(logFileFactory, loggingMetaData); Buffer<EventWrapper<LoggingEvent>> inputBuffer; if(exclusive) { ReadOnlyExclusiveCodecFileBuffer<EventWrapper<LoggingEvent>> input = new ReadOnlyExclusiveCodecFileBuffer<>(inputDataFile, inputIndexFile); input.setCodec(fileBufferFactory.resolveCodec(metaData)); inputBuffer = input; } else { inputBuffer = fileBufferFactory.createBuffer(inputDataFile, inputIndexFile, data); } FileBuffer<EventWrapper<LoggingEvent>> outputBuffer = fileBufferFactory.createBuffer(outputDataFile, outputIndexFile, data); LoggingFormatter formatter = null; if(pattern != null) { formatter = new LoggingFormatter(); formatter.setPattern(pattern); } long firstUnfiltered=filterContent(inputBuffer, outputBuffer, groovyCondition, formatter); if(keepRunning) { pollFile(inputBuffer, outputBuffer, groovyCondition, formatter, inputDataFile, inputIndexFile, firstUnfiltered); } return true; } else if (FileConstants.CONTENT_TYPE_VALUE_ACCESS.equals(contentType)) { Map<String, String> accessMetaData = new HashMap<>(); accessMetaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_ACCESS); accessMetaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); accessMetaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); AccessFileBufferFactory fileBufferFactory = new AccessFileBufferFactory(logFileFactory, accessMetaData); Buffer<EventWrapper<AccessEvent>> inputBuffer; if(exclusive) { ReadOnlyExclusiveCodecFileBuffer<EventWrapper<AccessEvent>> input = new ReadOnlyExclusiveCodecFileBuffer<>(inputDataFile, inputIndexFile); input.setCodec(fileBufferFactory.resolveCodec(metaData)); inputBuffer = input; } else { inputBuffer = fileBufferFactory.createBuffer(inputDataFile, inputIndexFile, data); } FileBuffer<EventWrapper<AccessEvent>> outputBuffer = fileBufferFactory.createBuffer(outputDataFile, outputIndexFile, data); AccessFormatter formatter = null; if(pattern != null) { formatter = new AccessFormatter(); formatter.setPattern(pattern); } long firstUnfiltered=filterContent(inputBuffer, outputBuffer, groovyCondition, formatter); if(keepRunning) { pollFile(inputBuffer, outputBuffer, groovyCondition, formatter, inputDataFile, inputIndexFile, firstUnfiltered); } return true; } else { if (logger.isWarnEnabled()) logger.warn("Unexpected content type {}.", contentType); return false; } } catch (IOException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception while reading from file '" + inputDataFileStr + "'!", ex); } } return false; } private static <T extends Serializable> long filterContent(Buffer<EventWrapper<T>> inputBuffer, AppendOperation<EventWrapper<T>> outputBuffer, GroovyCondition groovyCondition, Formatter<EventWrapper<T>> formatter) { long bufferSize=inputBuffer.getSize(); long i; for (i = 0; i < bufferSize; i++) { EventWrapper<T> current = inputBuffer.get(i); if (current != null) { if(groovyCondition.isTrue(current)) { if(formatter != null) { String msg = formatter.format(current); if (msg != null) { System.out.print(msg); System.out.flush(); } } outputBuffer.add(current); } } } return i; } private static <T extends Serializable> void pollFile(Buffer<EventWrapper<T>> inputBuffer, AppendOperation<EventWrapper<T>> outputBuffer, GroovyCondition groovyCondition, Formatter<EventWrapper<T>> formatter, File inputDataFile, File inputIndexFile, long index) { final Logger logger = LoggerFactory.getLogger(FilterCommand.class); for(;;) { long dataModified = inputDataFile.lastModified(); long indexModified = inputIndexFile.lastModified(); if (indexModified < dataModified) { // Index file is outdated. IndexingCallable callable=new IndexingCallable(inputDataFile, inputIndexFile, true); try { callable.call(); } catch(Exception e) { if(logger.isWarnEnabled()) logger.warn("Exception while reindexing!", e); break; } for(;index < inputBuffer.getSize();index++) { EventWrapper<T> current = inputBuffer.get(index); if (current != null) { if(groovyCondition.isTrue(current)) { if(formatter != null) { String msg = formatter.format(current); if (msg != null) { System.out.print(msg); System.out.flush(); } } outputBuffer.add(current); } } } } try { Thread.sleep(5000); } catch(InterruptedException e) { if(logger.isInfoEnabled()) logger.info("Interrupted..."); IOUtilities.interruptIfNecessary(e); break; } } } }