Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
psiprobe.beans.LogResolverBean Maven / Gradle / Ivy
Go to download
PSI Probe Core - Core logic, data models, and controllers
/**
* Licensed under the GPL License. You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
package psiprobe.beans;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.Loader;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ClassUtils;
import psiprobe.model.Application;
import psiprobe.model.DisconnectedLogDestination;
import psiprobe.tools.ApplicationUtils;
import psiprobe.tools.Instruments;
import psiprobe.tools.logging.FileLogAccessor;
import psiprobe.tools.logging.LogDestination;
import psiprobe.tools.logging.catalina.CatalinaLoggerAccessor;
import psiprobe.tools.logging.commons.CommonsLoggerAccessor;
import psiprobe.tools.logging.jdk.Jdk14LoggerAccessor;
import psiprobe.tools.logging.jdk.Jdk14ManagerAccessor;
import psiprobe.tools.logging.log4j.Log4JLoggerAccessor;
import psiprobe.tools.logging.log4j.Log4JManagerAccessor;
import psiprobe.tools.logging.log4j2.Log4J2AppenderAccessor;
import psiprobe.tools.logging.log4j2.Log4J2LoggerConfigAccessor;
import psiprobe.tools.logging.log4j2.Log4J2LoggerContextAccessor;
import psiprobe.tools.logging.log4j2.Log4J2WebLoggerContextUtilsAccessor;
import psiprobe.tools.logging.logback.LogbackFactoryAccessor;
import psiprobe.tools.logging.logback.LogbackLoggerAccessor;
import psiprobe.tools.logging.slf4jlogback.TomcatSlf4jLogbackFactoryAccessor;
import psiprobe.tools.logging.slf4jlogback.TomcatSlf4jLogbackLoggerAccessor;
/**
* The Class LogResolverBean.
*/
public class LogResolverBean {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(LogResolverBean.class);
/** The container wrapper. */
@Inject
private ContainerWrapperBean containerWrapper;
/** The stdout files. */
private List stdoutFiles = new ArrayList<>();
/**
* Gets the container wrapper.
*
* @return the container wrapper
*/
public ContainerWrapperBean getContainerWrapper() {
return containerWrapper;
}
/**
* Sets the container wrapper.
*
* @param containerWrapper the new container wrapper
*/
public void setContainerWrapper(ContainerWrapperBean containerWrapper) {
this.containerWrapper = containerWrapper;
}
/**
* Gets the stdout files.
*
* @return the stdout files
*/
public List getStdoutFiles() {
return stdoutFiles;
}
/**
* Sets the stdout files.
*
* @param stdoutFiles the new stdout files
*/
@Autowired
public void setStdoutFiles(List stdoutFiles) {
logger.info("stdoutFiles {}", stdoutFiles);
this.stdoutFiles = stdoutFiles;
}
/**
* Gets the log destinations.
*
* @param all the all
* @return the log destinations
*/
public List getLogDestinations(boolean all) {
List allAppenders = getAllLogDestinations();
if (allAppenders == null) {
return null;
}
//
// this list has to guarantee the order in which elements are added
//
List uniqueList = new LinkedList<>();
AbstractLogComparator cmp = new LogDestinationComparator(all);
Collections.sort(allAppenders, cmp);
for (LogDestination dest : allAppenders) {
if (Collections.binarySearch(uniqueList, dest, cmp) < 0) {
if (all || dest.getFile() == null || dest.getFile().exists()) {
uniqueList.add(new DisconnectedLogDestination().builder(dest));
}
}
}
return uniqueList;
}
/**
* Gets the log sources.
*
* @param logFile the log file
* @return the log sources
*/
public List getLogSources(File logFile) {
List filtered = new LinkedList<>();
List sources = getLogSources();
for (LogDestination dest : sources) {
if (logFile.equals(dest.getFile())) {
filtered.add(dest);
}
}
return filtered;
}
/**
* Gets the log sources.
*
* @return the log sources
*/
public List getLogSources() {
List sources = new LinkedList<>();
List allAppenders = getAllLogDestinations();
if (allAppenders != null) {
AbstractLogComparator cmp = new LogSourceComparator();
Collections.sort(allAppenders, cmp);
for (LogDestination dest : allAppenders) {
if (Collections.binarySearch(sources, dest, cmp) < 0) {
sources.add(new DisconnectedLogDestination().builder(dest));
}
}
}
return sources;
}
/**
* Gets the all log destinations.
*
* @return the all log destinations
*/
private List getAllLogDestinations() {
if (!Instruments.isInitialized()) {
return null;
}
List allAppenders = new ArrayList<>();
//
// interrogate classloader hierarchy
//
ClassLoader cl2 = Thread.currentThread().getContextClassLoader().getParent();
while (cl2 != null) {
interrogateClassLoader(cl2, null, allAppenders);
cl2 = cl2.getParent();
}
//
// check for known stdout files, such as "catalina.out"
//
interrogateStdOutFiles(allAppenders);
//
// interrogate webapp classloaders and available loggers
//
List contexts = getContainerWrapper().getTomcatContainer().findContexts();
for (Context ctx : contexts) {
interrogateContext(ctx, allAppenders);
}
return allAppenders;
}
/**
* Gets the log destination.
*
* @param logType the log type
* @param webapp the webapp
* @param context the context
* @param root the root
* @param logName the log name
* @param logIndex the log index
* @return the log destination
*/
public LogDestination getLogDestination(String logType, String webapp, boolean context,
boolean root, String logName, String logIndex) {
LogDestination result = null;
Context ctx = null;
Application application = null;
if (webapp != null) {
ctx = getContainerWrapper().getTomcatContainer().findContext(webapp);
if (ctx != null) {
application = ApplicationUtils.getApplication(ctx, getContainerWrapper());
}
}
if (logName != null && "stdout".equals(logType)) {
result = getStdoutLogDestination(logName);
} else if (ctx != null && "catalina".equals(logType)) {
result = getCatalinaLogDestination(ctx, application);
} else if (logIndex != null && ("jdk".equals(logType) || "log4j".equals(logType)
|| "log4j2".equals(logType) || "logback".equals(logType))
|| "tomcatSlf4jLogback".equals(logType)) {
if (context && ctx != null && !"log4j2".equals(logType)) {
result = getCommonsLogDestination(ctx, application, logIndex);
} else if (ctx != null && "log4j2".equals(logType)) {
result = getLog4J2LogDestination(ctx, application, root, logName, logIndex);
} else {
ClassLoader cl;
ClassLoader prevCl = null;
if (ctx != null) {
cl = ctx.getLoader().getClassLoader();
prevCl = ClassUtils.overrideThreadContextClassLoader(cl);
} else {
cl = Thread.currentThread().getContextClassLoader().getParent();
}
try {
if ((root || logName != null) && logIndex != null) {
if ("jdk".equals(logType)) {
result = getJdk14LogDestination(cl, application, root, logName, logIndex);
} else if ("log4j".equals(logType)) {
result = getLog4JLogDestination(cl, application, root, logName, logIndex);
} else if ("logback".equals(logType)) {
result = getLogbackLogDestination(cl, application, root, logName, logIndex);
} else if ("tomcatSlf4jLogback".equals(logType)) {
result = getLogbackTomcatJuliLogDestination(cl, application, root, logName, logIndex);
}
}
} finally {
if (prevCl != null) {
ClassUtils.overrideThreadContextClassLoader(prevCl);
}
}
}
}
return result;
}
/**
* Interrogate context.
*
* @param ctx the ctx
* @param allAppenders the all appenders
*/
private void interrogateContext(Context ctx, List allAppenders) {
Application application = ApplicationUtils.getApplication(ctx, getContainerWrapper());
ClassLoader cl = ctx.getLoader().getClassLoader();
Object contextLogger = ctx.getLogger();
if (contextLogger != null) {
if (contextLogger.getClass().getName().startsWith("org.apache.commons.logging")) {
CommonsLoggerAccessor commonsAccessor = new CommonsLoggerAccessor();
commonsAccessor.setTarget(contextLogger);
commonsAccessor.setApplication(application);
allAppenders.addAll(commonsAccessor.getDestinations());
} else if (contextLogger.getClass().getName().startsWith("org.apache.catalina.logger")) {
CatalinaLoggerAccessor catalinaAccessor = new CatalinaLoggerAccessor();
catalinaAccessor.setApplication(application);
catalinaAccessor.setTarget(contextLogger);
allAppenders.add(catalinaAccessor);
}
ServletContext servletContext = ctx.getServletContext();
try {
Log4J2LoggerContextAccessor loggerContextAccessor = null;
try {
Log4J2WebLoggerContextUtilsAccessor webLoggerContextUtilsAccessor =
new Log4J2WebLoggerContextUtilsAccessor(cl);
loggerContextAccessor = webLoggerContextUtilsAccessor.getWebLoggerContext(servletContext);
} catch (Exception e) {
logger.debug("Log4J2LoggerContextAccessor instantiation failed", e);
}
List loggerContexts = getLoggerContexts(cl);
for (Object loggerContext : loggerContexts) {
Map loggerConfigs = getLoggerConfigs(loggerContext);
for (Object loggerConfig : loggerConfigs.values()) {
Log4J2LoggerConfigAccessor logConfigAccessor = new Log4J2LoggerConfigAccessor();
logConfigAccessor.setTarget(loggerConfig);
logConfigAccessor.setApplication(application);
logConfigAccessor.setContext(true);
logConfigAccessor.setLoggerContext(loggerContextAccessor);
Method getAppenders =
MethodUtils.getAccessibleMethod(loggerConfig.getClass(), "getAppenders");
@SuppressWarnings("unchecked")
Map appenders = (Map) getAppenders.invoke(loggerConfig);
for (Object appender : appenders.values()) {
Log4J2AppenderAccessor appenderAccessor = new Log4J2AppenderAccessor();
appenderAccessor.setTarget(appender);
appenderAccessor.setLoggerAccessor(logConfigAccessor);
appenderAccessor.setApplication(application);
allAppenders.add(appenderAccessor);
}
}
}
} catch (Exception e) {
logger.debug("getting appenders failed", e);
}
}
if (application.isAvailable()) {
ClassLoader prevCl = ClassUtils.overrideThreadContextClassLoader(cl);
try {
interrogateClassLoader(cl, application, allAppenders);
} catch (Exception e) {
logger.error(
"Could not interrogate classloader loggers for {}. Enable debug logging to see the trace stack",
ctx.getName());
logger.debug("", e);
} finally {
if (prevCl != null) {
ClassUtils.overrideThreadContextClassLoader(prevCl);
}
}
}
}
/**
* Interrogate class loader.
*
* @param cl the cl
* @param application the application
* @param appenders the appenders
*/
private void interrogateClassLoader(ClassLoader cl, Application application,
List appenders) {
String applicationName =
application != null ? "application \"" + application.getName() + "\"" : "server";
// check for JDK loggers
try {
Jdk14ManagerAccessor jdk14accessor = new Jdk14ManagerAccessor(cl);
jdk14accessor.setApplication(application);
appenders.addAll(jdk14accessor.getHandlers());
} catch (Exception e) {
logger.debug("Could not resolve JDK loggers for '{}'", applicationName, e);
}
// check for Log4J loggers
try {
Log4JManagerAccessor log4JAccessor = new Log4JManagerAccessor(cl);
log4JAccessor.setApplication(application);
appenders.addAll(log4JAccessor.getAppenders());
} catch (Exception e) {
logger.debug("Could not resolve log4j loggers for '{}'", applicationName, e);
}
// check for Logback loggers
try {
LogbackFactoryAccessor logbackAccessor = new LogbackFactoryAccessor(cl);
logbackAccessor.setApplication(application);
appenders.addAll(logbackAccessor.getAppenders());
} catch (Exception e) {
logger.debug("Could not resolve logback loggers for '{}'", applicationName, e);
}
// check for tomcat-slf4j-logback loggers
try {
TomcatSlf4jLogbackFactoryAccessor tomcatSlf4jLogbackAccessor =
new TomcatSlf4jLogbackFactoryAccessor(cl);
tomcatSlf4jLogbackAccessor.setApplication(application);
appenders.addAll(tomcatSlf4jLogbackAccessor.getAppenders());
} catch (Exception e) {
logger.debug("Could not resolve tomcat-slf4j-logback loggers for '{}'", applicationName, e);
}
}
/**
* Interrogate std out files.
*
* @param appenders the appenders
*/
private void interrogateStdOutFiles(List appenders) {
for (String fileName : stdoutFiles) {
FileLogAccessor fla = resolveStdoutLogDestination(fileName);
if (fla != null) {
appenders.add(fla);
}
}
}
/**
* Gets the stdout log destination.
*
* @param logName the log name
* @return the stdout log destination
*/
private LogDestination getStdoutLogDestination(String logName) {
for (String fileName : stdoutFiles) {
if (fileName.equals(logName)) {
FileLogAccessor fla = resolveStdoutLogDestination(fileName);
if (fla != null) {
return fla;
}
}
}
return null;
}
/**
* Resolve stdout log destination.
*
* @param fileName the file name
* @return the file log accessor
*/
private FileLogAccessor resolveStdoutLogDestination(String fileName) {
File stdout = new File(System.getProperty("catalina.base"), "logs/" + fileName);
if (stdout.exists()) {
FileLogAccessor fla = new FileLogAccessor();
fla.setName(fileName);
fla.setFile(stdout);
return fla;
}
return null;
}
/**
* Gets the catalina log destination.
*
* @param ctx the ctx
* @param application the application
* @return the catalina log destination
*/
private LogDestination getCatalinaLogDestination(Context ctx, Application application) {
Object log = ctx.getLogger();
if (log != null) {
CatalinaLoggerAccessor logAccessor = new CatalinaLoggerAccessor();
logAccessor.setTarget(log);
logAccessor.setApplication(application);
if (logAccessor.getFile().exists()) {
return logAccessor;
}
}
return null;
}
/**
* Gets the commons log destination.
*
* @param ctx the ctx
* @param application the application
* @param logIndex the log index
* @return the commons log destination
*/
private LogDestination getCommonsLogDestination(Context ctx, Application application,
String logIndex) {
Object contextLogger = ctx.getLogger();
CommonsLoggerAccessor commonsAccessor = new CommonsLoggerAccessor();
commonsAccessor.setTarget(contextLogger);
commonsAccessor.setApplication(application);
return commonsAccessor.getDestination(logIndex);
}
/**
* Gets the jdk14 log destination.
*
* @param cl the cl
* @param application the application
* @param root the root
* @param logName the log name
* @param handlerIndex the handler index
* @return the jdk14 log destination
*/
private LogDestination getJdk14LogDestination(ClassLoader cl, Application application,
boolean root, String logName, String handlerIndex) {
try {
Jdk14ManagerAccessor manager = new Jdk14ManagerAccessor(cl);
manager.setApplication(application);
Jdk14LoggerAccessor log = root ? manager.getRootLogger() : manager.getLogger(logName);
if (log != null) {
return log.getHandler(handlerIndex);
}
} catch (Exception e) {
logger.debug("getJdk14LogDestination failed", e);
}
return null;
}
/**
* Gets the log4j log destination.
*
* @param cl the cl
* @param application the application
* @param root the root
* @param logName the log name
* @param appenderName the appender name
* @return the log4j log destination
*/
private LogDestination getLog4JLogDestination(ClassLoader cl, Application application,
boolean root, String logName, String appenderName) {
try {
Log4JManagerAccessor manager = new Log4JManagerAccessor(cl);
manager.setApplication(application);
Log4JLoggerAccessor log = root ? manager.getRootLogger() : manager.getLogger(logName);
if (log != null) {
return log.getAppender(appenderName);
}
} catch (Exception e) {
logger.debug("getLog4JLogDestination failed", e);
}
return null;
}
/**
* Gets the log4j2 log destination.
*
* @param ctx the ctx
* @param application the application
* @param root the root
* @param logName the log name
* @param appenderName the appender name
* @return the log4j2 log destination
*/
private LogDestination getLog4J2LogDestination(Context ctx, Application application, boolean root,
String logName, String appenderName) {
Log4J2AppenderAccessor result = null;
try {
Loader loader = ctx.getLoader();
ClassLoader classLoader = loader.getClassLoader();
Log4J2WebLoggerContextUtilsAccessor webLoggerContextUtilsAccessor =
new Log4J2WebLoggerContextUtilsAccessor(classLoader);
Log4J2LoggerContextAccessor loggerContextAccessor =
webLoggerContextUtilsAccessor.getWebLoggerContext(ctx.getServletContext());
List loggerContexts = getLoggerContexts(classLoader);
Object loggerConfig = null;
for (Object loggerContext : loggerContexts) {
Map loggerConfigs = getLoggerConfigs(loggerContext);
loggerConfig = loggerConfigs.get(root ? "" : logName);
if (loggerConfig != null) {
break;
}
}
if (loggerConfig != null) {
Log4J2LoggerConfigAccessor accessor = new Log4J2LoggerConfigAccessor();
accessor.setTarget(loggerConfig);
accessor.setApplication(application);
accessor.setContext(true);
accessor.setLoggerContext(loggerContextAccessor);
result = accessor.getAppender(appenderName);
}
} catch (Exception e) {
logger.debug("getLog4J2LogDestination failed", e);
}
logger.debug("getLog4J2LogDestination(): OUT: result={}", result);
return result;
}
private Map getLoggerConfigs(Object loggerContext)
throws IllegalAccessException, InvocationTargetException {
Method getConfiguration =
MethodUtils.getAccessibleMethod(loggerContext.getClass(), "getConfiguration");
Object configuration = getConfiguration.invoke(loggerContext);
Method getLoggerConfigs =
MethodUtils.getAccessibleMethod(configuration.getClass(), "getLoggers");
return (Map) getLoggerConfigs.invoke(configuration);
}
private List getLoggerContexts(ClassLoader cl) throws ClassNotFoundException,
InstantiationException, IllegalAccessException, InvocationTargetException,
IllegalArgumentException, NoSuchMethodException, SecurityException {
Class> clazz =
cl.loadClass("org.apache.logging.log4j.core.selector.ClassLoaderContextSelector");
Object classLoaderContextSelector = clazz.getDeclaredConstructor().newInstance();
Method getLoggerContexts = MethodUtils.getAccessibleMethod(clazz, "getLoggerContexts");
return (List) getLoggerContexts.invoke(classLoaderContextSelector);
}
/**
* Gets the logback log destination.
*
* @param cl the cl
* @param application the application
* @param root the root
* @param logName the log name
* @param appenderName the appender name
* @return the logback log destination
*/
private LogDestination getLogbackLogDestination(ClassLoader cl, Application application,
boolean root, String logName, String appenderName) {
try {
LogbackFactoryAccessor manager = new LogbackFactoryAccessor(cl);
manager.setApplication(application);
LogbackLoggerAccessor log = root ? manager.getRootLogger() : manager.getLogger(logName);
if (log != null) {
return log.getAppender(appenderName);
}
} catch (Exception e) {
logger.debug("getLogbackLogDestination failed", e);
}
return null;
}
/**
* Gets the logback tomcat juli log destination.
*
* @param cl the cl
* @param application the application
* @param root the root
* @param logName the log name
* @param appenderName the appender name
* @return the logback tomcat juli log destination
*/
private LogDestination getLogbackTomcatJuliLogDestination(ClassLoader cl, Application application,
boolean root, String logName, String appenderName) {
try {
TomcatSlf4jLogbackFactoryAccessor manager = new TomcatSlf4jLogbackFactoryAccessor(cl);
manager.setApplication(application);
TomcatSlf4jLogbackLoggerAccessor log =
root ? manager.getRootLogger() : manager.getLogger(logName);
if (log != null) {
return log.getAppender(appenderName);
}
} catch (Exception e) {
logger.debug("getTomcatSlf4jLogbackLogDestination failed", e);
}
return null;
}
/**
* The Class AbstractLogComparator.
*/
private abstract static class AbstractLogComparator
implements Comparator, Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The Constant DELIM. */
protected static final char DELIM = '!';
@Override
public final int compare(LogDestination o1, LogDestination o2) {
String name1 = convertToString(o1);
String name2 = convertToString(o2);
return name1.compareTo(name2);
}
/**
* Convert to string.
*
* @param d1 the d1
* @return the string
*/
protected abstract String convertToString(LogDestination d1);
}
/**
* The Class LogDestinationComparator.
*/
private static class LogDestinationComparator extends AbstractLogComparator
implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The all. */
private final boolean all;
/**
* Instantiates a new log destination comparator.
*
* @param all the all
*/
public LogDestinationComparator(boolean all) {
this.all = all;
}
@Override
protected String convertToString(LogDestination dest) {
File file = dest.getFile();
String fileName = file == null ? "" : file.getAbsolutePath();
String name;
if (all) {
Application app = dest.getApplication();
String appName = app == null ? Character.toString(DELIM) : app.getName();
String context = dest.isContext() ? "is" : "not";
String root = dest.isRoot() ? "is" : "not";
String logType = dest.getLogType();
name = appName + DELIM + context + DELIM + root + DELIM + logType + DELIM + fileName;
} else {
name = fileName;
}
return name;
}
}
/**
* The Class LogSourceComparator.
*/
private static class LogSourceComparator extends AbstractLogComparator implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
@Override
protected String convertToString(LogDestination dest) {
File file = dest.getFile();
String fileName = file == null ? "" : file.getAbsolutePath();
Application app = dest.getApplication();
String appName = app == null ? Character.toString(DELIM) : app.getName();
String logType = dest.getLogType();
String context = dest.isContext() ? "is" : "not";
String root = dest.isRoot() ? "is" : "not";
String logName = dest.getName();
return appName + DELIM + logType + DELIM + context + DELIM + root + DELIM + logName + DELIM
+ fileName;
}
}
}