001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.log4j;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
018    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019    import com.liferay.portal.kernel.log.LogFactory;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.PropsKeys;
022    import com.liferay.portal.kernel.util.PropsUtil;
023    import com.liferay.portal.kernel.util.ServerDetector;
024    import com.liferay.portal.kernel.util.StreamUtil;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    
028    import java.io.IOException;
029    import java.io.InputStream;
030    
031    import java.net.URL;
032    
033    import java.util.Enumeration;
034    import java.util.HashMap;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.concurrent.ConcurrentHashMap;
038    
039    import org.apache.log4j.Level;
040    import org.apache.log4j.LogManager;
041    import org.apache.log4j.Logger;
042    import org.apache.log4j.xml.DOMConfigurator;
043    
044    import org.dom4j.Document;
045    import org.dom4j.Element;
046    import org.dom4j.io.SAXReader;
047    
048    import org.xml.sax.EntityResolver;
049    import org.xml.sax.InputSource;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     * @author Tomas Polesovsky
054     */
055    public class Log4JUtil {
056    
057            public static void configureLog4J(ClassLoader classLoader) {
058                    configureLog4J(classLoader.getResource("META-INF/portal-log4j.xml"));
059    
060                    try {
061                            Enumeration<URL> enu = classLoader.getResources(
062                                    "META-INF/portal-log4j-ext.xml");
063    
064                            while (enu.hasMoreElements()) {
065                                    configureLog4J(enu.nextElement());
066                            }
067                    }
068                    catch (IOException ioe) {
069                            java.util.logging.Logger logger =
070                                    java.util.logging.Logger.getLogger(Log4JUtil.class.getName());
071    
072                            logger.log(
073                                    java.util.logging.Level.WARNING,
074                                    "Unable to load portal-log4j-ext.xml", ioe);
075                    }
076            }
077    
078            public static void configureLog4J(URL url) {
079                    if (url == null) {
080                            return;
081                    }
082    
083                    String urlContent = _getURLContent(url);
084    
085                    if (urlContent == null) {
086                            return;
087                    }
088    
089                    // See LPS-6029, LPS-8865, and LPS-24280
090    
091                    DOMConfigurator domConfigurator = new DOMConfigurator();
092    
093                    domConfigurator.doConfigure(
094                            new UnsyncStringReader(urlContent),
095                            LogManager.getLoggerRepository());
096    
097                    try {
098                            SAXReader saxReader = new SAXReader();
099    
100                            saxReader.setEntityResolver(
101                                    new EntityResolver() {
102    
103                                            @Override
104                                            public InputSource resolveEntity(
105                                                    String publicId, String systemId) {
106    
107                                                    if (systemId.endsWith("log4j.dtd")) {
108                                                            return new InputSource(
109                                                                    DOMConfigurator.class.getResourceAsStream(
110                                                                            "log4j.dtd"));
111                                                    }
112    
113                                                    return null;
114                                            }
115    
116                                    });
117    
118                            Document document = saxReader.read(
119                                    new UnsyncStringReader(urlContent), url.toExternalForm());
120    
121                            Element rootElement = document.getRootElement();
122    
123                            List<Element> categoryElements = rootElement.elements("category");
124    
125                            for (Element categoryElement : categoryElements) {
126                                    String name = categoryElement.attributeValue("name");
127    
128                                    Element priorityElement = categoryElement.element("priority");
129    
130                                    String priority = priorityElement.attributeValue("value");
131    
132                                    java.util.logging.Logger jdkLogger =
133                                            java.util.logging.Logger.getLogger(name);
134    
135                                    jdkLogger.setLevel(_getJdkLevel(priority));
136                            }
137                    }
138                    catch (Exception e) {
139                            _logger.error(e, e);
140                    }
141            }
142    
143            public static Map<String, String> getCustomLogSettings() {
144                    return new HashMap<>(_customLogSettings);
145            }
146    
147            public static String getOriginalLevel(String className) {
148                    Level level = Level.ALL;
149    
150                    Enumeration<Logger> enu = LogManager.getCurrentLoggers();
151    
152                    while (enu.hasMoreElements()) {
153                            Logger logger = enu.nextElement();
154    
155                            if (className.equals(logger.getName())) {
156                                    level = logger.getLevel();
157    
158                                    break;
159                            }
160                    }
161    
162                    return level.toString();
163            }
164    
165            public static void initLog4J(
166                    String serverId, String liferayHome, ClassLoader classLoader,
167                    LogFactory logFactory, Map<String, String> customLogSettings) {
168    
169                    ServerDetector.init(serverId);
170    
171                    _liferayHome = liferayHome;
172    
173                    configureLog4J(classLoader);
174    
175                    try {
176                            LogFactoryUtil.setLogFactory(logFactory);
177                    }
178                    catch (Exception e) {
179                            _logger.error(e, e);
180                    }
181    
182                    for (String name : customLogSettings.keySet()) {
183                            String priority = customLogSettings.get(name);
184    
185                            setLevel(name, priority, false);
186                    }
187            }
188    
189            public static void setLevel(String name, String priority, boolean custom) {
190                    Logger logger = Logger.getLogger(name);
191    
192                    logger.setLevel(Level.toLevel(priority));
193    
194                    java.util.logging.Logger jdkLogger = java.util.logging.Logger.getLogger(
195                            name);
196    
197                    jdkLogger.setLevel(_getJdkLevel(priority));
198    
199                    if (custom) {
200                            _customLogSettings.put(name, priority);
201                    }
202            }
203    
204            /**
205             * @see com.liferay.portal.util.FileImpl#getBytes(InputStream, int, boolean)
206             */
207            private static byte[] _getBytes(InputStream inputStream)
208                    throws IOException {
209    
210                    UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
211                            new UnsyncByteArrayOutputStream();
212    
213                    StreamUtil.transfer(inputStream, unsyncByteArrayOutputStream, -1, true);
214    
215                    return unsyncByteArrayOutputStream.toByteArray();
216            }
217    
218            private static java.util.logging.Level _getJdkLevel(String priority) {
219                    if (StringUtil.equalsIgnoreCase(priority, Level.DEBUG.toString())) {
220                            return java.util.logging.Level.FINE;
221                    }
222                    else if (StringUtil.equalsIgnoreCase(
223                                            priority, Level.ERROR.toString())) {
224    
225                            return java.util.logging.Level.SEVERE;
226                    }
227                    else if (StringUtil.equalsIgnoreCase(priority, Level.WARN.toString())) {
228                            return java.util.logging.Level.WARNING;
229                    }
230                    else {
231                            return java.util.logging.Level.INFO;
232                    }
233            }
234    
235            private static String _getLiferayHome() {
236                    if (_liferayHome == null) {
237                            _liferayHome = PropsUtil.get(PropsKeys.LIFERAY_HOME);
238                    }
239    
240                    return _liferayHome;
241            }
242    
243            private static String _getURLContent(URL url) {
244                    Map<String, String> variables = new HashMap<>();
245    
246                    variables.put("@liferay.home@", _getLiferayHome());
247    
248                    String spiId = System.getProperty("spi.id");
249    
250                    if (spiId == null) {
251                            spiId = StringPool.BLANK;
252                    }
253    
254                    variables.put("@spi.id@", spiId);
255    
256                    String urlContent = null;
257    
258                    InputStream inputStream = null;
259    
260                    try {
261                            inputStream = url.openStream();
262    
263                            byte[] bytes = _getBytes(inputStream);
264    
265                            urlContent = new String(bytes, StringPool.UTF8);
266                    }
267                    catch (Exception e) {
268                            _logger.error(e, e);
269    
270                            return null;
271                    }
272                    finally {
273                            StreamUtil.cleanUp(inputStream);
274                    }
275    
276                    for (Map.Entry<String, String> variable : variables.entrySet()) {
277                            urlContent = StringUtil.replace(
278                                    urlContent, variable.getKey(), variable.getValue());
279                    }
280    
281                    if (ServerDetector.getServerId() != null) {
282                            return urlContent;
283                    }
284    
285                    urlContent = _removeAppender(urlContent, "TEXT_FILE");
286    
287                    return _removeAppender(urlContent, "XML_FILE");
288            }
289    
290            private static String _removeAppender(String content, String appenderName) {
291                    int x = content.indexOf("<appender name=\"" + appenderName + "\"");
292    
293                    int y = content.indexOf("</appender>", x);
294    
295                    if (y != -1) {
296                            y = content.indexOf("<", y + 1);
297                    }
298    
299                    if ((x != -1) && (y != -1)) {
300                            content = content.substring(0, x) + content.substring(y);
301                    }
302    
303                    return StringUtil.replace(
304                            content, "<appender-ref ref=\"" + appenderName + "\" />",
305                            StringPool.BLANK);
306            }
307    
308            private static final Logger _logger = Logger.getRootLogger();
309    
310            private static final Map<String, String> _customLogSettings =
311                    new ConcurrentHashMap<>();
312            private static String _liferayHome;
313    
314    }