| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You 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.apache.geode.management.internal.cli.util; |
| |
| import static java.util.stream.Collectors.toList; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.function.Predicate; |
| import java.util.stream.Stream; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| import org.apache.geode.management.internal.configuration.utils.ZipUtils; |
| |
| /** |
| * this LogExporter only finds the .log and .gfs files under in the same directory of the base files |
| * it doesn't use the base file's filename patterns to find the related logs/stats yet. |
| */ |
| public class LogExporter { |
| private static final Logger LOGGER = LogService.getLogger(); |
| |
| private final LogFilter logFilter; |
| private final File baseLogFile; |
| private final File baseStatsFile; |
| |
| /** |
| * @param logFilter the filter that's used to check if we need to accept the file or the logLine |
| * @param baseLogFile if not null, we will export the logs in that directory |
| * @param baseStatsFile if not null, we will export stats in that directory |
| */ |
| public LogExporter(LogFilter logFilter, File baseLogFile, File baseStatsFile) { |
| assert logFilter != null; |
| this.logFilter = logFilter; |
| this.baseLogFile = baseLogFile; |
| this.baseStatsFile = baseStatsFile; |
| } |
| |
| /** |
| * |
| * @return Path to the zip file that has all the filtered files, null if no files are selected to |
| * export. |
| */ |
| public Path export() throws IOException { |
| Path tempDirectory = Files.createTempDirectory("exportLogs"); |
| |
| if (baseLogFile != null) { |
| for (Path logFile : findLogFiles(baseLogFile.toPath().getParent())) { |
| Path filteredLogFile = tempDirectory.resolve(logFile.getFileName()); |
| writeFilteredLogFile(logFile, filteredLogFile); |
| } |
| } |
| |
| if (baseStatsFile != null) { |
| for (Path statFile : findStatFiles(baseStatsFile.toPath().getParent())) { |
| Files.copy(statFile, tempDirectory.resolve(statFile.getFileName())); |
| } |
| } |
| |
| Path zipFile = null; |
| if (tempDirectory.toFile().listFiles().length > 0) { |
| zipFile = Files.createTempFile("logExport", ".zip"); |
| ZipUtils.zipDirectory(tempDirectory, zipFile); |
| LOGGER.info("Zipped files to: " + zipFile); |
| } |
| |
| FileUtils.deleteDirectory(tempDirectory.toFile()); |
| |
| return zipFile; |
| } |
| |
| protected void writeFilteredLogFile(Path originalLogFile, Path filteredLogFile) |
| throws IOException { |
| this.logFilter.startNewFile(); |
| |
| try (BufferedReader reader = new BufferedReader(new FileReader(originalLogFile.toFile()))) { |
| try (BufferedWriter writer = new BufferedWriter(new FileWriter(filteredLogFile.toFile()))) { |
| |
| String line; |
| while ((line = reader.readLine()) != null) { |
| LogFilter.LineFilterResult result = this.logFilter.acceptsLine(line); |
| |
| if (result == LogFilter.LineFilterResult.REMAINDER_OF_FILE_REJECTED) { |
| break; |
| } |
| |
| if (result == LogFilter.LineFilterResult.LINE_ACCEPTED) { |
| writeLine(line, writer); |
| } |
| } |
| } |
| } |
| } |
| |
| private void writeLine(String line, BufferedWriter writer) { |
| try { |
| writer.write(line); |
| writer.newLine(); |
| } catch (IOException e) { |
| throw new RuntimeException("Unable to write to log file", e); |
| } |
| } |
| |
| /** |
| * @return combined size of stat archives and filtered log files in bytes |
| */ |
| public long estimateFilteredSize() throws IOException { |
| long filteredSize = 0; |
| if (baseLogFile != null) { |
| for (Path logFile : findLogFiles(baseLogFile.toPath().getParent())) { |
| filteredSize += filterAndSize(logFile); |
| } |
| } |
| |
| if (baseStatsFile != null) { |
| for (Path statFile : findStatFiles(baseStatsFile.toPath().getParent())) { |
| filteredSize += statFile.toFile().length(); |
| } |
| } |
| |
| return filteredSize; |
| } |
| |
| /** |
| * @return size of file in bytes |
| */ |
| private long filterAndSize(Path originalLogFile) throws IOException { |
| long size = 0; |
| this.logFilter.startNewFile(); |
| |
| try (BufferedReader reader = new BufferedReader(new FileReader(originalLogFile.toFile()))) { |
| String line; |
| while ((line = reader.readLine()) != null) { |
| LogFilter.LineFilterResult result = this.logFilter.acceptsLine(line); |
| |
| if (result == LogFilter.LineFilterResult.REMAINDER_OF_FILE_REJECTED) { |
| break; |
| } |
| if (result == LogFilter.LineFilterResult.LINE_ACCEPTED) { |
| size += line.length() + System.lineSeparator().length(); |
| } |
| } |
| } |
| return size; |
| } |
| |
| List<Path> findLogFiles(Path workingDir) throws IOException { |
| Predicate<Path> logFileSelector = (Path file) -> file.toString().toLowerCase().contains(".log"); |
| return findFiles(workingDir, logFileSelector); |
| } |
| |
| |
| List<Path> findStatFiles(Path workingDir) throws IOException { |
| Predicate<Path> statFileSelector = |
| (Path file) -> file.toString().toLowerCase().endsWith(".gfs"); |
| return findFiles(workingDir, statFileSelector); |
| } |
| |
| private List<Path> findFiles(Path workingDir, Predicate<Path> fileSelector) throws IOException { |
| Stream<Path> selectedFiles/* = null */; |
| if (!workingDir.toFile().isDirectory()) { |
| return Collections.emptyList(); |
| } |
| selectedFiles = Files.list(workingDir).filter(fileSelector).filter(this.logFilter::acceptsFile); |
| |
| return selectedFiles.collect(toList()); |
| } |
| } |