001/* 002 * (C) Copyright 2011-2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Julien Carsique 018 * 019 */ 020 021package org.nuxeo.log4j; 022 023import java.io.File; 024import java.util.ArrayList; 025import java.util.List; 026import java.util.Map; 027import java.util.function.Function; 028import java.util.stream.Collectors; 029import java.util.stream.Stream; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.apache.logging.log4j.Level; 034import org.apache.logging.log4j.core.Appender; 035import org.apache.logging.log4j.core.LoggerContext; 036import org.apache.logging.log4j.core.appender.FileAppender; 037import org.apache.logging.log4j.core.appender.RollingFileAppender; 038import org.apache.logging.log4j.core.config.Configuration; 039import org.apache.logging.log4j.core.config.ConfigurationSource; 040import org.apache.logging.log4j.core.config.Configurator; 041import org.apache.logging.log4j.core.config.LoggerConfig; 042import org.apache.logging.log4j.core.config.xml.XmlConfiguration; 043 044/** 045 * Provides helper methods for working with log4j 046 * 047 * @author jcarsique 048 * @since 5.4.2 049 */ 050public class Log4JHelper { 051 private static final Log log = LogFactory.getLog(Log4JHelper.class); 052 053 /** 054 * Returns list of files produced by {@link FileAppender}s defined in a given {@link Configuration}. There's no 055 * need for the log4j configuration corresponding to this repository of being active. 056 * 057 * @param configuration the {@link Configuration} to browse looking for {@link FileAppender} 058 * @return {@link FileAppender}s present in configuration 059 * @since 10.3 060 */ 061 public static List<String> getFileAppendersFileNames(Configuration configuration) { 062 List<String> names = new ArrayList<>(); 063 for (Appender appender : configuration.getAppenders().values()) { 064 if (appender instanceof FileAppender) { 065 names.add(((FileAppender) appender).getFileName()); 066 } else if (appender instanceof RollingFileAppender) { 067 names.add(((RollingFileAppender) appender).getFileName()); 068 } 069 } 070 return names; 071 } 072 073 /** 074 * Creates a {@link Configuration} initialized with given log4j configuration file without making this 075 * configuration active. 076 * 077 * @param log4jConfigurationFile the XML configuration file to load 078 * @return {@link Configuration} initialized with log4jConfigurationFile 079 * @since 10.3 080 */ 081 public static Configuration newConfiguration(File log4jConfigurationFile) { 082 if (log4jConfigurationFile == null || !log4jConfigurationFile.exists()) { 083 throw new IllegalArgumentException("Missing Log4J configuration: " + log4jConfigurationFile); 084 } else { 085 XmlConfiguration configuration = new XmlConfiguration(null, 086 ConfigurationSource.fromUri(log4jConfigurationFile.toURI())); 087 configuration.initialize(); 088 log.debug("Log4j configuration " + log4jConfigurationFile + " successfully loaded."); 089 return configuration; 090 } 091 } 092 093 /** 094 * @see #getFileAppendersFileNames(Configuration) 095 * @param log4jConfigurationFile the XML configuration file to load 096 * @return {@link FileAppender}s defined in log4jConfigurationFile 097 * @since 10.3 098 */ 099 public static List<String> getFileAppendersFileNames(File log4jConfigurationFile) { 100 return getFileAppendersFileNames(newConfiguration(log4jConfigurationFile)); 101 } 102 103 /** 104 * Set DEBUG level on the given logger. 105 * 106 * @param loggerNames the logger names to change level 107 * @param level the level to set 108 * @param includeChildren whether or not to change children levels 109 * @since 10.3 110 */ 111 public static void setLevel(String[] loggerNames, Level level, boolean includeChildren) { 112 if (includeChildren) { 113 // don't use Configurator.setAllLevels(String, Level) in order to reload configuration only once 114 @SuppressWarnings("resource") // not ours to close 115 LoggerContext loggerContext = LoggerContext.getContext(false); 116 Configuration config = loggerContext.getConfiguration(); 117 boolean set = false; 118 for (String parentLogger : loggerNames) { 119 set |= setLevel(parentLogger, level, config); 120 for (final Map.Entry<String, LoggerConfig> entry : config.getLoggers().entrySet()) { 121 if (entry.getKey().startsWith(parentLogger)) { 122 set |= setLevel(entry.getValue(), level); 123 } 124 } 125 } 126 if (set) { 127 loggerContext.updateLoggers(); 128 } 129 } else { 130 Configurator.setLevel(Stream.of(loggerNames).collect(Collectors.toMap(Function.identity(), l -> level))); 131 } 132 } 133 134 // Copied from org.apache.logging.log4j.core.config.Configurator 135 private static boolean setLevel(final String loggerName, final Level level, final Configuration config) { 136 boolean set; 137 LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); 138 if (!loggerName.equals(loggerConfig.getName())) { 139 // TODO Should additivity be inherited? 140 loggerConfig = new LoggerConfig(loggerName, level, true); 141 config.addLogger(loggerName, loggerConfig); 142 loggerConfig.setLevel(level); 143 set = true; 144 } else { 145 set = setLevel(loggerConfig, level); 146 } 147 return set; 148 } 149 150 // Copied from org.apache.logging.log4j.core.config.Configurator 151 private static boolean setLevel(final LoggerConfig loggerConfig, final Level level) { 152 final boolean set = !loggerConfig.getLevel().equals(level); 153 if (set) { 154 loggerConfig.setLevel(level); 155 } 156 return set; 157 } 158 159}