/*
* Carrot2 project.
*
* Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński.
* All rights reserved.
*
* Refer to the full license file "carrot2.LICENSE"
* in the root folder of the repository checkout or at:
* http://www.carrot2.org/carrot2.LICENSE
*/
package org.carrot2.webapp;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map.Entry;
import javax.servlet.*;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.*;
import org.carrot2.shaded.guava.common.collect.*;
/**
* Initializes file appenders to save logs to files named after the context path. Works
* only if the container supports Servlet API 2.5.
*/
public class LogInitContextListener implements ServletContextListener
{
/**
* An instance of this class will save itself in the application context under this
* identifier.
*/
public static final String CONTEXT_ID = LogInitContextListener.class.getName();
/**
* Any created {@link Appender}s.
*/
private Multimap<Logger, Appender> appenders = ArrayListMultimap.create();
/**
* Callback hook from the application container. Initialize logging appenders
* immediately or defer initialization until possible.
*/
public void contextInitialized(ServletContextEvent event)
{
final ServletContext servletContext = event.getServletContext();
if (servletContext.getAttribute(CONTEXT_ID) != null)
{
// Only one instance needed.
return;
}
/*
* If the container has Servlet 2.5 API, init loggers immediately. Otherwise, save
* itself to the context and wait for {@link QueryProcessorServlet} to perform
* deferred initialization.
*/
try
{
final Method method = ServletContext.class.getMethod("getContextPath");
final String contextPath = (String) method.invoke(servletContext);
addAppenders(contextPath);
}
catch (RuntimeException e)
{
// Rethrow runtime exceptions, if any.
throw e;
}
catch (Exception e)
{
/*
* No servlet 2.5 API (getContextPath), save in the context for deferred
* initialization.
*/
servletContext.setAttribute(CONTEXT_ID, this);
}
}
/**
* Callback hook from the application container. Cleanup any created appenders and
* unregister them from their loggers.
*/
public void contextDestroyed(ServletContextEvent event)
{
for (Entry<Logger, Collection<Appender>> e : appenders.asMap().entrySet())
{
final Logger logger = e.getKey();
for (Appender a : e.getValue())
{
logger.removeAppender(a);
a.close();
}
}
appenders.clear();
}
/**
* Add appenders based on the provided context path.
*/
void addAppenders(String contextPath)
{
final File logDir = getLogDir();
if (logDir == null)
{
// No log dir.
return;
}
try
{
final String contextPathName = getContextPathSegment(contextPath);
addAppender(new File(logDir, "c2-" + contextPathName + "-queries.log"),
Logger.getLogger(QueryProcessorServlet.QUERY_LOG_NAME), "%d{ISO8601},%m%n");
addAppender(new File(logDir, "c2-" + contextPathName + "-full.log"), Logger
.getRootLogger(), "%d{ISO8601},[%p],[%t],%c,%m%n");
}
catch (IOException e)
{
Logger.getRootLogger().warn("Could not initialize custom appenders.", e);
}
}
/*
*
*/
private void addAppender(File file, Logger logger, String pattern) throws IOException
{
final FileAppender appender = new DailyRollingFileAppender(new PatternLayout(pattern), file
.getAbsolutePath(), "'.'yyyy-MM-dd");
appender.setEncoding("UTF-8");
appender.setAppend(true);
logger.addAppender(appender);
appenders.put(logger, appender);
}
/**
* @return Returns the log directory to dump custom logs to. If null is returned, no
* log dir is defined and custom appenders should not be attached.
*/
private static File getLogDir()
{
/*
* Check for custom override of logs location.
*/
final String customLogFolder = System.getProperty("carrot2.logs");
if (!StringUtils.isEmpty(customLogFolder))
{
File logDir = new File(customLogFolder);
if (logDir.isDirectory())
{
return logDir;
}
}
/*
* Check for catalina's (Tomcat) default log folder.
*/
final String catalinaBase = System.getProperty("catalina.base");
if (!StringUtils.isEmpty(catalinaBase) && new File(catalinaBase).isDirectory())
{
final File logDir = new File(new File(catalinaBase), "logs");
if (logDir.isDirectory())
{
return logDir;
}
}
/*
* If null is returned, no log dir is defined and custom appenders should not be
* attached.
*/
return null;
}
/*
*
*/
private static String getContextPathSegment(String contextPath)
{
if (StringUtils.isBlank(contextPath))
{
contextPath = "root";
}
contextPath = contextPath.replaceAll("[^a-zA-Z0-9\\-]", "");
return contextPath;
}
}