001/*
002 *  Copyright 2017 Anyware Services
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 */
016package org.ametys.runtime.log;
017
018import java.io.IOException;
019
020import org.apache.avalon.framework.configuration.Configurable;
021import org.apache.avalon.framework.configuration.Configuration;
022import org.apache.avalon.framework.configuration.ConfigurationException;
023import org.apache.commons.lang3.StringUtils;
024import org.apache.log4j.Appender;
025import org.apache.log4j.FileAppender;
026import org.apache.log4j.Level;
027import org.apache.log4j.LogManager;
028import org.apache.log4j.Logger;
029import org.apache.log4j.PatternLayout;
030import org.apache.log4j.rolling.RollingFileAppender;
031import org.apache.log4j.rolling.TimeBasedRollingPolicy;
032
033import org.ametys.core.util.AmetysExceptionFilter;
034import org.ametys.runtime.plugin.component.PluginAware;
035import org.ametys.runtime.util.AmetysHomeHelper;
036
037/**
038 * Default static implementation of {@link ExternalLog}
039 * For implementing the {@link ExternalLog} interface (while being {@link Configurable}), extends this class and implements the {@link #getAppender()} and/or {@link #getCategory()} methods.
040 * 
041 * Example of XML
042 * <pre>
043 * {@code
044 * &lt;extension id="runtime.core.externalLogger.myTest"
045 *         class="org.ametys.runtime.log.StaticExternalLog"
046 *         point="org.ametys.runtime.log.ExternalLogExtensionPoint">
047 *     &lt;appender-name>my-logger&lt;/appender-name>
048 *     &lt;category-name>com.example.mylog&lt;/category-name>
049 *     &lt;file-prefix>my-file-name&lt;/file-prefix>
050 *     &lt;additive>false&lt;/additive>
051 *     &lt;rolling-file>true&lt;/rolling-file>
052 *     &lt;log-level>INFO&lt;/log-level>
053 * &lt;/extension>
054 * }
055 * </pre>
056 */
057public class StaticExternalLog implements ExternalLog, Configurable, PluginAware
058{
059    /** default layout pattern */
060    protected static final String PATTERN_LAYOUT = "%d %-5p [%c] (%t;%X{requestURI}) %m%n";
061    
062    /** Default log level */
063    protected static final Level DEFAULT_LEVEL = Level.WARN;
064    private String _appenderName;
065    private String _categoryName;
066    private String _filePrefix;
067    private boolean _additive;
068    private Level _level;
069    private boolean _rollingFileAppender;
070    private Appender _appender;
071
072    public Appender getAppender() throws IOException
073    {
074        if (_appender == null)
075        {
076            if (_rollingFileAppender)
077            {
078                _appender = _createRollingFileAppender();
079            }
080            else
081            {
082                _appender = _createFileAppender();
083            }
084        }
085        return _appender;
086    }
087
088    private RollingFileAppender _createRollingFileAppender()
089    {
090        RollingFileAppender fileAppender = new RollingFileAppender();
091        fileAppender.setName(_appenderName);
092        fileAppender.setEncoding("UTF-8");
093        TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
094        String filePattern = AmetysHomeHelper.getAmetysHome() + "/logs/" + _filePrefix + "-%d.log";
095        rollingPolicy.setFileNamePattern(filePattern);
096        fileAppender.setRollingPolicy(rollingPolicy);
097
098        PatternLayout layout = new PatternLayout(PATTERN_LAYOUT);
099        fileAppender.setLayout(layout);
100
101        AmetysExceptionFilter filter = new AmetysExceptionFilter();
102        fileAppender.addFilter(filter);
103        fileAppender.activateOptions();
104        return fileAppender;
105    }
106
107    private FileAppender _createFileAppender() throws IOException
108    {
109        String filename = AmetysHomeHelper.getAmetysHome() + "/logs/" + _filePrefix + ".log";
110        PatternLayout layout = new PatternLayout(PATTERN_LAYOUT);
111        FileAppender fileAppender = new FileAppender(layout, filename);
112        AmetysExceptionFilter filter = new AmetysExceptionFilter();
113        fileAppender.addFilter(filter);
114        fileAppender.activateOptions();
115        return fileAppender;
116    }
117
118    public Logger getCategory()
119    {
120        org.apache.log4j.Logger logger = LogManager.getLogger(_categoryName);
121        logger.setAdditivity(_additive);
122        logger.setLevel(_level);
123        return logger;
124    }
125
126    public void configure(Configuration configuration) throws ConfigurationException
127    {
128        _categoryName = configuration.getChild("category-name").getValue("").trim();
129        _filePrefix = configuration.getChild("file-prefix").getValue("").trim();
130        _additive = configuration.getChild("additive").getValueAsBoolean(true);
131        _rollingFileAppender = configuration.getChild("rolling-file").getValueAsBoolean(true);
132        String levelAsString = configuration.getChild("log-level").getValue(DEFAULT_LEVEL.toString());
133        _level = Level.toLevel(levelAsString);
134
135        if (StringUtils.isBlank(_filePrefix))
136        {
137            throw new ConfigurationException("<file-prefix> is mandatory and should not be blank", configuration);
138        }
139        if (StringUtils.isBlank(_categoryName))
140        {
141            throw new ConfigurationException("<category-name> is mandatory and should not be blank", configuration);
142        }
143    }
144
145    public void setPluginInfo(String pluginName, String featureName, String id)
146    {
147        _appenderName = id;
148    }
149
150}