/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package com.liferay.petra.log4j; import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream; import com.liferay.portal.kernel.io.unsync.UnsyncStringReader; import com.liferay.portal.kernel.log.LogFactory; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.PortalClassLoaderUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.ReflectionUtil; import com.liferay.portal.kernel.util.ServerDetector; import com.liferay.portal.kernel.util.StreamUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; /** * @author Brian Wing Shun Chan * @author Tomas Polesovsky * @see com.liferay.util.log4j.Log4JUtil */ public class Log4JUtil { public static void configureLog4J(ClassLoader classLoader) { configureLog4J(classLoader.getResource("META-INF/portal-log4j.xml")); try { Enumeration<URL> enu = classLoader.getResources( "META-INF/portal-log4j-ext.xml"); while (enu.hasMoreElements()) { configureLog4J(enu.nextElement()); } } catch (IOException ioe) { java.util.logging.Logger logger = java.util.logging.Logger.getLogger(Log4JUtil.class.getName()); logger.log( java.util.logging.Level.WARNING, "Unable to load portal-log4j-ext.xml", ioe); } } public static void configureLog4J(URL url) { if (url == null) { return; } String urlContent = _getURLContent(url); if (urlContent == null) { return; } // See LPS-6029, LPS-8865, and LPS-24280 DOMConfigurator domConfigurator = new DOMConfigurator(); domConfigurator.doConfigure( new UnsyncStringReader(urlContent), LogManager.getLoggerRepository()); try { SAXReader saxReader = new SAXReader(); saxReader.setEntityResolver( new EntityResolver() { @Override public InputSource resolveEntity( String publicId, String systemId) { if (systemId.endsWith("log4j.dtd")) { return new InputSource( DOMConfigurator.class.getResourceAsStream( "log4j.dtd")); } return null; } }); Document document = saxReader.read( new UnsyncStringReader(urlContent), url.toExternalForm()); Element rootElement = document.getRootElement(); List<Element> categoryElements = rootElement.elements("category"); for (Element categoryElement : categoryElements) { String name = categoryElement.attributeValue("name"); Element priorityElement = categoryElement.element("priority"); String priority = priorityElement.attributeValue("value"); java.util.logging.Logger jdkLogger = java.util.logging.Logger.getLogger(name); jdkLogger.setLevel(_getJdkLevel(priority)); } } catch (Exception e) { _logger.error(e, e); } } public static Map<String, String> getCustomLogSettings() { return new HashMap<>(_getCustomLogSettings()); } public static String getOriginalLevel(String className) { Level level = Level.ALL; Enumeration<Logger> enu = LogManager.getCurrentLoggers(); while (enu.hasMoreElements()) { Logger logger = enu.nextElement(); if (className.equals(logger.getName())) { level = logger.getLevel(); break; } } return level.toString(); } public static void initLog4J( String serverId, String liferayHome, ClassLoader classLoader, LogFactory logFactory, Map<String, String> customLogSettings) { System.setProperty( ServerDetector.SYSTEM_PROPERTY_KEY_SERVER_DETECTOR_SERVER_ID, serverId); _liferayHome = liferayHome; configureLog4J(classLoader); try { LogFactoryUtil.setLogFactory(logFactory); } catch (Exception e) { _logger.error(e, e); } for (Map.Entry<String, String> entry : customLogSettings.entrySet()) { setLevel(entry.getKey(), entry.getValue(), false); } } public static void setLevel(String name, String priority, boolean custom) { Logger logger = Logger.getLogger(name); logger.setLevel(Level.toLevel(priority)); java.util.logging.Logger jdkLogger = java.util.logging.Logger.getLogger( name); jdkLogger.setLevel(_getJdkLevel(priority)); if (custom) { Map<String, String> customLogSettings = _getCustomLogSettings(); customLogSettings.put(name, priority); } } /** * @see com.liferay.portal.util.FileImpl#getBytes(InputStream, int, boolean) */ private static byte[] _getBytes(InputStream inputStream) throws IOException { UnsyncByteArrayOutputStream unsyncByteArrayOutputStream = new UnsyncByteArrayOutputStream(); StreamUtil.transfer(inputStream, unsyncByteArrayOutputStream, -1, true); return unsyncByteArrayOutputStream.toByteArray(); } private static Map<String, String> _getCustomLogSettings() { ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader(); try { Class<?> clazz = classLoader.loadClass( "com.liferay.util.log4j.Log4JUtil"); Field field = ReflectionUtil.getDeclaredField( clazz, "_customLogSettings"); return (Map<String, String>)field.get(null); } catch (Exception e) { return ReflectionUtil.throwException(e); } } private static java.util.logging.Level _getJdkLevel(String priority) { if (StringUtil.equalsIgnoreCase(priority, Level.DEBUG.toString())) { return java.util.logging.Level.FINE; } else if (StringUtil.equalsIgnoreCase( priority, Level.ERROR.toString())) { return java.util.logging.Level.SEVERE; } else if (StringUtil.equalsIgnoreCase(priority, Level.WARN.toString())) { return java.util.logging.Level.WARNING; } else { return java.util.logging.Level.INFO; } } private static String _getLiferayHome() { if (_liferayHome == null) { _liferayHome = PropsUtil.get(PropsKeys.LIFERAY_HOME); } return _liferayHome; } private static String _getURLContent(URL url) { Map<String, String> variables = new HashMap<>(); variables.put("@liferay.home@", _getLiferayHome()); String spiId = System.getProperty("spi.id"); if (spiId == null) { spiId = StringPool.BLANK; } variables.put("@spi.id@", spiId); String urlContent = null; InputStream inputStream = null; try { inputStream = url.openStream(); byte[] bytes = _getBytes(inputStream); urlContent = new String(bytes, StringPool.UTF8); } catch (Exception e) { _logger.error(e, e); return null; } finally { StreamUtil.cleanUp(inputStream); } for (Map.Entry<String, String> variable : variables.entrySet()) { urlContent = StringUtil.replace( urlContent, variable.getKey(), variable.getValue()); } if (ServerDetector.getServerId() != null) { return urlContent; } urlContent = _removeAppender(urlContent, "TEXT_FILE"); return _removeAppender(urlContent, "XML_FILE"); } private static String _removeAppender(String content, String appenderName) { int x = content.indexOf("<appender name=\"" + appenderName + "\""); int y = content.indexOf("</appender>", x); if (y != -1) { y = content.indexOf("<", y + 1); } if ((x != -1) && (y != -1)) { content = content.substring(0, x) + content.substring(y); } return StringUtil.replace( content, "<appender-ref ref=\"" + appenderName + "\" />", StringPool.BLANK); } private static final Logger _logger = Logger.getRootLogger(); private static final Map<String, String> _customLogSettings = new ConcurrentHashMap<>(); private static String _liferayHome; }