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        TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy();
093        String filePattern = AmetysHomeHelper.getAmetysHome() + "/logs/" + _filePrefix + "-%d.log";
094        rollingPolicy.setFileNamePattern(filePattern);
095        fileAppender.setRollingPolicy(rollingPolicy);
096
097        PatternLayout layout = new PatternLayout(PATTERN_LAYOUT);
098        fileAppender.setLayout(layout);
099
100        AmetysExceptionFilter filter = new AmetysExceptionFilter();
101        fileAppender.addFilter(filter);
102        fileAppender.activateOptions();
103        return fileAppender;
104    }
105
106    private FileAppender _createFileAppender() throws IOException
107    {
108        String filename = AmetysHomeHelper.getAmetysHome() + "/logs/" + _filePrefix + ".log";
109        PatternLayout layout = new PatternLayout(PATTERN_LAYOUT);
110        FileAppender fileAppender = new FileAppender(layout, filename);
111        AmetysExceptionFilter filter = new AmetysExceptionFilter();
112        fileAppender.addFilter(filter);
113        fileAppender.activateOptions();
114        return fileAppender;
115    }
116
117    public Logger getCategory()
118    {
119        org.apache.log4j.Logger logger = LogManager.getLogger(_categoryName);
120        logger.setAdditivity(_additive);
121        logger.setLevel(_level);
122        return logger;
123    }
124
125    public void configure(Configuration configuration) throws ConfigurationException
126    {
127        _categoryName = configuration.getChild("category-name").getValue("").trim();
128        _filePrefix = configuration.getChild("file-prefix").getValue("").trim();
129        _additive = configuration.getChild("additive").getValueAsBoolean(true);
130        _rollingFileAppender = configuration.getChild("rolling-file").getValueAsBoolean(true);
131        String levelAsString = configuration.getChild("log-level").getValue(DEFAULT_LEVEL.toString());
132        _level = Level.toLevel(levelAsString);
133
134        if (StringUtils.isBlank(_filePrefix))
135        {
136            throw new ConfigurationException("<file-prefix> is mandatory and should not be blank", configuration);
137        }
138        if (StringUtils.isBlank(_categoryName))
139        {
140            throw new ConfigurationException("<category-name> is mandatory and should not be blank", configuration);
141        }
142    }
143
144    public void setPluginInfo(String pluginName, String featureName, String id)
145    {
146        _appenderName = id;
147    }
148
149}