/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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.elasticsearch.common.logging.log4j; import com.google.common.collect.ImmutableMap; import org.apache.log4j.PropertyConfigurator; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.env.Environment; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Properties; import static org.elasticsearch.common.Strings.cleanPath; import static org.elasticsearch.common.settings.Settings.settingsBuilder; /** * */ public class LogConfigurator { static final List<String> ALLOWED_SUFFIXES = Arrays.asList(".yml", ".yaml", ".json", ".properties"); private static boolean loaded; private static ImmutableMap<String, String> replacements = new MapBuilder<String, String>() .put("console", "org.elasticsearch.common.logging.log4j.ConsoleAppender") .put("async", "org.apache.log4j.AsyncAppender") .put("dailyRollingFile", "org.apache.log4j.DailyRollingFileAppender") .put("externallyRolledFile", "org.apache.log4j.ExternallyRolledFileAppender") .put("file", "org.apache.log4j.FileAppender") .put("jdbc", "org.apache.log4j.jdbc.JDBCAppender") .put("jms", "org.apache.log4j.net.JMSAppender") .put("lf5", "org.apache.log4j.lf5.LF5Appender") .put("ntevent", "org.apache.log4j.nt.NTEventLogAppender") .put("null", "org.apache.log4j.NullAppender") .put("rollingFile", "org.apache.log4j.RollingFileAppender") .put("extrasRollingFile", "org.apache.log4j.rolling.RollingFileAppender") .put("smtp", "org.apache.log4j.net.SMTPAppender") .put("socket", "org.apache.log4j.net.SocketAppender") .put("socketHub", "org.apache.log4j.net.SocketHubAppender") .put("syslog", "org.apache.log4j.net.SyslogAppender") .put("telnet", "org.apache.log4j.net.TelnetAppender") .put("terminal", "org.elasticsearch.common.logging.log4j.TerminalAppender") // policies .put("timeBased", "org.apache.log4j.rolling.TimeBasedRollingPolicy") .put("sizeBased", "org.apache.log4j.rolling.SizeBasedTriggeringPolicy") // layouts .put("simple", "org.apache.log4j.SimpleLayout") .put("html", "org.apache.log4j.HTMLLayout") .put("pattern", "org.apache.log4j.PatternLayout") .put("consolePattern", "org.apache.log4j.PatternLayout") .put("enhancedPattern", "org.apache.log4j.EnhancedPatternLayout") .put("ttcc", "org.apache.log4j.TTCCLayout") .put("xml", "org.apache.log4j.XMLLayout") .immutableMap(); /** * Consolidates settings and converts them into actual log4j settings, then initializes loggers and appenders. * * @param settings custom settings that should be applied * @param resolveConfig controls whether the logging conf file should be read too or not. */ public static void configure(Settings settings, boolean resolveConfig) { if (loaded) { return; } loaded = true; // TODO: this is partly a copy of InternalSettingsPreparer...we should pass in Environment and not do all this... Environment environment = new Environment(settings); Settings.Builder settingsBuilder = settingsBuilder(); if (resolveConfig) { resolveConfig(environment, settingsBuilder); } settingsBuilder .putProperties("elasticsearch.", System.getProperties()) .putProperties("es.", System.getProperties()); // add custom settings after config was added so that they are not overwritten by config settingsBuilder.put(settings); settingsBuilder.replacePropertyPlaceholders(); Properties props = new Properties(); for (Map.Entry<String, String> entry : settingsBuilder.build().getAsMap().entrySet()) { String key = "log4j." + entry.getKey(); String value = entry.getValue(); if (replacements.containsKey(value)) { value = replacements.get(value); } if (key.endsWith(".value")) { props.setProperty(key.substring(0, key.length() - ".value".length()), value); } else if (key.endsWith(".type")) { props.setProperty(key.substring(0, key.length() - ".type".length()), value); } else { props.setProperty(key, value); } } // ensure explicit path to logs dir exists props.setProperty("log4j.path.logs", cleanPath(environment.logsFile().toAbsolutePath().toString())); PropertyConfigurator.configure(props); } /** * sets the loaded flag to false so that logging configuration can be * overridden. Should only be used in tests. */ static void reset() { loaded = false; } static void resolveConfig(Environment env, final Settings.Builder settingsBuilder) { try { Files.walkFileTree(env.configFile(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String fileName = file.getFileName().toString(); if (fileName.startsWith("logging.")) { for (String allowedSuffix : ALLOWED_SUFFIXES) { if (fileName.endsWith(allowedSuffix)) { loadConfig(file, settingsBuilder); break; } } } return FileVisitResult.CONTINUE; } }); } catch (IOException ioe) { throw new ElasticsearchException("Failed to load logging configuration", ioe); } } static void loadConfig(Path file, Settings.Builder settingsBuilder) { try { settingsBuilder.loadFromPath(file); } catch (SettingsException | NoClassDefFoundError e) { // ignore } } }