/** * Copyright 2013 the original author or authors. * * 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 io.neba.core.logviewer; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.eclipse.gemini.blueprint.context.BundleContextAware; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.TreeSet; import static org.apache.commons.io.FileUtils.listFiles; import static org.apache.commons.lang.StringUtils.isEmpty; /** * Represents both the log files in the default logfile directory (${sling.home}/logs) * as well as any additional log files configured in the felix console. * * @author Olaf Otto */ @Service public class LogFiles implements BundleContextAware { // Obtained from the felix console configuration for the log manager. private static final String LOG_FILE_PROPERTY = "org.apache.sling.commons.log.file"; private static final String LOG_MANAGER_PID = "org.apache.sling.commons.log.LogManager"; private static final String LOG_FACTORY_PID = "org.apache.sling.commons.log.LogManager.factory.config"; private static final IOFileFilter LOGFILE_FILTER = new IOFileFilter() { @Override public boolean accept(File file) { return file.canRead() && acceptFileName(file.getName()); } @Override public boolean accept(File dir, String name) { return acceptFileName(name); } private boolean acceptFileName(String fileName) { return fileName.endsWith(".log") || fileName.contains(".log."); } }; @Autowired private ConfigurationAdmin configurationAdmin; private BundleContext context; private File slingHomeDirectory; @PostConstruct public void determineSlingHomeDirectory() { this.slingHomeDirectory = new File(this.context.getProperty("sling.home")); } private File getLogfileDirectory() throws IOException { Configuration logConfiguration = getCommonsLogConfiguration(); File defaultLogFile = getConfiguredLogfile(logConfiguration); if (defaultLogFile != null && defaultLogFile.exists() && defaultLogFile.canRead()) { return defaultLogFile.getParentFile(); } else { return null; } } private File getConfiguredLogfile(Configuration logConfiguration) throws IOException { Dictionary properties = logConfiguration.getProperties(); if (properties == null) { return null; } String logFilePath = (String) properties.get(LOG_FILE_PROPERTY); if (isEmpty(logFilePath)) { return null; } File logFile = new File(logFilePath); if (!logFile.isAbsolute()) { logFile = new File(this.slingHomeDirectory, logFilePath); } return logFile.getCanonicalFile(); } @SuppressWarnings("unchecked") public Collection<File> resolveLogFiles() throws IOException { File logDir = getLogfileDirectory(); Collection<File> logFiles = new TreeSet<>((o1, o2) -> { return o1.getPath().compareToIgnoreCase(o2.getPath()); }); if (logDir == null) { // No configured log file directory exists, assume the default logDir = new File(this.slingHomeDirectory, "logs"); } // The log directory may be removed during runtime - always check access. if (logDir.exists() && logDir.isDirectory()) { logFiles.addAll(listFiles(logDir, LOGFILE_FILTER, TrueFileFilter.INSTANCE)); } for (File logFile : resolveFactoryConfiguredLogFiles()) { if (!logFile.getParentFile().getAbsolutePath().startsWith(logDir.getAbsolutePath())) { logFiles.addAll(listFiles(logFile.getParentFile(), LOGFILE_FILTER, TrueFileFilter.INSTANCE)); } } return logFiles; } private Collection<File> resolveFactoryConfiguredLogFiles() throws IOException { Collection<File> logFiles = new ArrayList<>(); Configuration[] configurations; try { configurations = this.configurationAdmin.listConfigurations("(service.factoryPid=" + LOG_FACTORY_PID + ")"); } catch (InvalidSyntaxException e) { throw new IllegalStateException("Unable to obtain the log files with factory pid " + LOG_FACTORY_PID + ".", e); } if (configurations != null) { for (Configuration logConfiguration : configurations) { File logFile = getConfiguredLogfile(logConfiguration); if (logFile != null && logFile.exists() && logFile.canRead()) { logFiles.add(logFile); } } } return logFiles; } private Configuration getCommonsLogConfiguration() throws IOException { return this.configurationAdmin.getConfiguration(LOG_MANAGER_PID); } @Override public void setBundleContext(BundleContext bundleContext) { this.context = bundleContext; } }