From ba0f89947226c9e34de178342a78936a0938c060 Mon Sep 17 00:00:00 2001 From: Andre Date: Sat, 7 Apr 2018 15:56:29 +0200 Subject: [PATCH] #37 - option to create custom loggers --- .../log4j2/AdminLog4j2Controller.java | 380 ++++--- .../admintool/log4j2/AdminToolLog4j2Util.java | 1007 ++++++++++------- .../log4j2/Log4j2ManageLoggerTO.java | 101 ++ .../resources/static/admintool/css/log4j2.css | 123 +- .../resources/static/admintool/js/log4j2.js | 768 +++++++------ .../templates/admintool/content/log4j2.html | 340 ++++-- 6 files changed, 1605 insertions(+), 1114 deletions(-) create mode 100644 admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/Log4j2ManageLoggerTO.java diff --git a/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminLog4j2Controller.java b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminLog4j2Controller.java index 4c50ad7..2005ce0 100644 --- a/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminLog4j2Controller.java +++ b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminLog4j2Controller.java @@ -1,169 +1,211 @@ -package de.chandre.admintool.log4j2; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.logging.log4j.Level; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; - -import de.chandre.admintool.core.AdminTool; - -@Controller -@RequestMapping(AdminTool.ROOTCONTEXT + "/log4j2") -public class AdminLog4j2Controller -{ - private static final Log LOGGER = LogFactory.getLog(AdminLog4j2Controller.class); - - @Autowired - private AdminToolLog4j2Config config; - - @Autowired - private AdminToolLog4j2Util log4jUtil; - - @RequestMapping(value = "/changeLevel/{loggerName}/{level}", method = {RequestMethod.POST, RequestMethod.GET}) - @ResponseBody - public String changeLevel(@PathVariable("loggerName") String loggerName, @PathVariable("level") String level, - HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - return changeLevelParent(loggerName, level, false, request); - } - - @RequestMapping(value = "/changeLevel/{loggerName}/{level}/parent/{parent}", method = {RequestMethod.POST, RequestMethod.GET}) - @ResponseBody - public String changeLevelParent(@PathVariable("loggerName") String loggerName, @PathVariable("level") String level, - @PathVariable("parent") boolean parent, HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - LOGGER.info(String.format("change %s to %s (parent: %s)", loggerName, level, parent)); - try { - log4jUtil.changeLogger(loggerName, level, parent); - } catch (Exception e) { - return "false"; - } - if (loggerName.equals("ROOT") || parent) { - return "reload"; - } - return "true"; - } - - @RequestMapping(value = "/removeCustomLoggers", method = {RequestMethod.POST, RequestMethod.GET}) - @ResponseBody - public String removeCustomLoggers() { - if (!config.isEnabled()) { - return null; - } - LOGGER.info(String.format("removing custom loggers")); - log4jUtil.removeCustomLoggers(); - return "reload"; - } - - @RequestMapping(value = "/getLevels", method = RequestMethod.GET) - @ResponseBody - public Collection getLevels(HttpServletRequest request) - { - List res = new ArrayList<>(); - for (Level level : log4jUtil.getLevels()) { - res.add(level.name()); - } - return res; - } - - @RequestMapping(value = "/getLevelCss/{prefix}", method = RequestMethod.GET) - @ResponseBody - public Map getLevelCssClass(@PathVariable("prefix") String prefix, HttpServletRequest request) - { - Map css = new HashMap<>(); - for (Level level : log4jUtil.getLevels()) { - css.put(level.name(), log4jUtil.getLoggerLevelCss(prefix, level)); - } - return css; - } - - @RequestMapping(value = "/initConsole", method = RequestMethod.POST) - @ResponseBody - public String initConsole(@RequestBody Log4j2ConsoleTO consoleTO, HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - try { - HttpSession session = request.getSession(true); - - if (session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME) != null) { - // there is already a output stream which should be closed first - log4jUtil.closeOutputStreamAppender(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME))); - } - - String name = log4jUtil.createOutputStreamAppender(consoleTO.getName(), consoleTO.getPattern(), consoleTO.getEncoding(), - consoleTO.getLoggerNames(), consoleTO.getLevel(), consoleTO.isRecursive(), consoleTO.isOverrideLogLevel()); - session.setAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME, name); - LOGGER.debug(String.format("log4j console initialized: %s, %s", consoleTO.getLevel(), consoleTO.getEncoding())); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - return "false"; - } - return "true"; - } - - @RequestMapping(value = "/stopConsole", method = {RequestMethod.GET, RequestMethod.POST}) - @ResponseBody - public String stopConsole(HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - try { - HttpSession session = request.getSession(false); - log4jUtil.closeOutputStreamAppender(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME))); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - return "false"; - } - return "true"; - } - - @RequestMapping(value = {"/getConsoleContent", "/getConsoleContent/"}, method = {RequestMethod.GET, RequestMethod.POST}) - @ResponseBody - public String getConsoleContent(HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - return getConsoleContent(null, request); - } - - @RequestMapping(value = "/getConsoleContent/{encoding}", method = {RequestMethod.GET, RequestMethod.POST}) - @ResponseBody - public String getConsoleContent(@PathVariable("encoding") String encoding, HttpServletRequest request) - { - if (!config.isEnabled()) { - return null; - } - try { - HttpSession session = request.getSession(false); - return log4jUtil.getStringOutput(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME)), encoding); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - return e.getMessage(); - } - } -} +package de.chandre.admintool.log4j2; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.logging.log4j.Level; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import de.chandre.admintool.core.AdminTool; + +@Controller +@RequestMapping(AdminTool.ROOTCONTEXT + "/log4j2") +public class AdminLog4j2Controller +{ + private static final Log LOGGER = LogFactory.getLog(AdminLog4j2Controller.class); + + private static final String RESULT_ACTION_RELOAD = "reload"; + private static final String RESULT_TRUE = Boolean.TRUE.toString(); + private static final String RESULT_FALSE = Boolean.FALSE.toString(); + + @Autowired + private AdminToolLog4j2Config config; + + @Autowired + private AdminToolLog4j2Util log4jUtil; + + @RequestMapping(value = "/changeLevel/{loggerName}/{level}", method = {RequestMethod.POST, RequestMethod.GET}) + @ResponseBody + public String changeLevel(@PathVariable("loggerName") String loggerName, @PathVariable("level") String level, + HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + return changeLevelParent(loggerName, level, false, request); + } + + @RequestMapping(value = "/changeLevel/{loggerName}/{level}/parent/{parent}", method = {RequestMethod.POST, RequestMethod.GET}) + @ResponseBody + public String changeLevelParent(@PathVariable("loggerName") String loggerName, @PathVariable("level") String level, + @PathVariable("parent") boolean parent, HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + LOGGER.info(String.format("change %s to %s (parent: %s)", loggerName, level, parent)); + try { + log4jUtil.changeLogger(loggerName, level, parent); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return RESULT_FALSE; + } + if (loggerName.equals("ROOT") || parent) { + return RESULT_ACTION_RELOAD; + } + return RESULT_TRUE; + } + + /** + * + * @param manageTO + * @param request + * @return + * @since 1.1.6.4 + */ + @RequestMapping(value = "/manageLogger", method = RequestMethod.POST) + @ResponseBody + public String manageLogger(@RequestBody Log4j2ManageLoggerTO manageTO, HttpServletRequest request) + { + if (!config.isEnabled()) { + return RESULT_FALSE; + } + LOGGER.info(String.format("manage logger %s", manageTO)); + try { + log4jUtil.addCustomParentLogger(manageTO.isAdditivity(), manageTO.getLevel(), manageTO.getLoggerName(), manageTO.getAppenderNames()); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return RESULT_FALSE; + } + return RESULT_ACTION_RELOAD; + } + + @RequestMapping(value = "/removeCustomLoggers", method = {RequestMethod.POST, RequestMethod.GET}) + @ResponseBody + public String removeCustomLoggers() { + if (!config.isEnabled()) { + return null; + } + LOGGER.info(String.format("removing custom loggers")); + log4jUtil.removeCustomLoggers(); + return RESULT_ACTION_RELOAD; + } + + @RequestMapping(value = "/removeCustomParentLogger", method = {RequestMethod.POST, RequestMethod.GET}) + @ResponseBody + public String removeCustomParentLogger() { + if (!config.isEnabled()) { + return null; + } + LOGGER.info(String.format("removing custom loggers")); + log4jUtil.removeCustomParentLoggers(); + return RESULT_ACTION_RELOAD; + } + + + + @RequestMapping(value = "/getLevels", method = RequestMethod.GET) + @ResponseBody + public Collection getLevels(HttpServletRequest request) + { + List res = new ArrayList<>(); + for (Level level : log4jUtil.getLevels()) { + res.add(level.name()); + } + return res; + } + + @RequestMapping(value = "/getLevelCss/{prefix}", method = RequestMethod.GET) + @ResponseBody + public Map getLevelCssClass(@PathVariable("prefix") String prefix, HttpServletRequest request) + { + Map css = new HashMap<>(); + for (Level level : log4jUtil.getLevels()) { + css.put(level.name(), log4jUtil.getLoggerLevelCss(prefix, level)); + } + return css; + } + + @RequestMapping(value = "/initConsole", method = RequestMethod.POST) + @ResponseBody + public String initConsole(@RequestBody Log4j2ConsoleTO consoleTO, HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + try { + HttpSession session = request.getSession(true); + + if (session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME) != null) { + // there is already a output stream which should be closed first + log4jUtil.closeOutputStreamAppender(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME))); + } + + String name = log4jUtil.createOutputStreamAppender(consoleTO.getName(), consoleTO.getPattern(), consoleTO.getEncoding(), + consoleTO.getLoggerNames(), consoleTO.getLevel(), consoleTO.isRecursive(), consoleTO.isOverrideLogLevel()); + session.setAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME, name); + LOGGER.debug(String.format("log4j console initialized: %s, %s", consoleTO.getLevel(), consoleTO.getEncoding())); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return RESULT_FALSE; + } + return RESULT_TRUE; + } + + @RequestMapping(value = "/stopConsole", method = {RequestMethod.GET, RequestMethod.POST}) + @ResponseBody + public String stopConsole(HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + try { + HttpSession session = request.getSession(false); + log4jUtil.closeOutputStreamAppender(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME))); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return RESULT_FALSE; + } + return RESULT_TRUE; + } + + @RequestMapping(value = {"/getConsoleContent", "/getConsoleContent/"}, method = {RequestMethod.GET, RequestMethod.POST}) + @ResponseBody + public String getConsoleContent(HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + return getConsoleContent(null, request); + } + + @RequestMapping(value = "/getConsoleContent/{encoding}", method = {RequestMethod.GET, RequestMethod.POST}) + @ResponseBody + public String getConsoleContent(@PathVariable("encoding") String encoding, HttpServletRequest request) + { + if (!config.isEnabled()) { + return null; + } + try { + HttpSession session = request.getSession(false); + return log4jUtil.getStringOutput(String.class.cast(session.getAttribute(AdminToolLog4j2Util.SESSION_APPENDER_NAME)), encoding); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return e.getMessage(); + } + } +} diff --git a/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminToolLog4j2Util.java b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminToolLog4j2Util.java index 0bc7a94..b1459c9 100644 --- a/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminToolLog4j2Util.java +++ b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/AdminToolLog4j2Util.java @@ -1,435 +1,572 @@ -package de.chandre.admintool.log4j2; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeSet; -import java.util.UUID; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.OutputStreamAppender; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.spi.StandardLevel; -import org.springframework.stereotype.Service; -import org.springframework.util.ConcurrentReferenceHashMap; -import org.springframework.util.StringUtils; - -/** - * service for log4j2 manipulation - * @author Andre - * @since 1.0.0 - */ -@Service("adminToolLog4j2Util") -public class AdminToolLog4j2Util -{ - private static List LEVELS = new ArrayList<>(7); - static { - LEVELS.add(Level.OFF); - LEVELS.add(Level.TRACE); - LEVELS.add(Level.DEBUG); - LEVELS.add(Level.INFO); - LEVELS.add(Level.WARN); - LEVELS.add(Level.ERROR); - LEVELS.add(Level.FATAL); - } - - private static final Comparator LOGGER_COMP = new Comparator() { - @Override - public int compare(Logger o1, Logger o2) { - return o1.getName().compareTo(o2.getName()); - } - }; - - private static final String DEFAULT_PATTERN = "%d{dd.MM.yyyy HH:mm:ss.SSS} %X{sessionId} [%t] %-5level %logger{36} : %msg%n"; - - public static final String SESSION_APPENDER_NAME = "log4j2AppenderName"; - - private Map customLoggers = new ConcurrentReferenceHashMap<>(); - private Map customParentLoggers = new ConcurrentReferenceHashMap<>(); - - private Map outputStreams = new ConcurrentReferenceHashMap<>(); - - public int getCustomLoggerSize() { - return customLoggers.size(); - } - - public int getCustomParentLoggerSize() { - return customParentLoggers.size(); - } - - /** - * returns all parent loggers - * @return - */ - public Collection getParentLoggers() { - LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - List loggers = new ArrayList<>(ctx.getLoggers()); - Map parentMap = new HashMap<>(); - try { - for (Logger logger : loggers) { - if (null != logger.getParent() && parentMap.get(logger.getParent().getName()) == null) { - parentMap.put(logger.getParent().getName(), logger.getParent()); - } - } - List parents = new ArrayList<>(parentMap.values()); - Collections.sort(parents, LOGGER_COMP); - return parents; - } finally { - loggers.clear(); - parentMap.clear(); - } - } - - public Collection getParentLoggerNames() { - List loggerNames = new ArrayList<>(); - for (Logger logger : getParentLoggers()) { - loggerNames.add(logger.getName()); - } - return loggerNames; - } - - /** - * returns all loggers - * @return - */ - public Collection getLoggers() { - LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - List loggers = new ArrayList<>(ctx.getLoggers()); - Collections.sort(loggers, LOGGER_COMP); - return loggers; - } - - /** - * returns all logger names including custom loggers - * - * @since 1.1.1 - * @return - */ - public Collection getAllLoggerNames() { - Set loggerNames = new TreeSet<>(); - for (Logger logger : getParentLoggers()) { - loggerNames.add(logger.getName()); - } - for (Logger logger : getLoggers()) { - loggerNames.add(logger.getName()); - } - if (!customLoggers.isEmpty()) { - for (Entry entry : customLoggers.entrySet()) { - loggerNames.add(entry.getKey().getName()); - } - } - if (!customParentLoggers.isEmpty()) { - for (Entry entry : customParentLoggers.entrySet()) { - loggerNames.add(entry.getKey().getName()); - } - } - return loggerNames; - } - - /** - * returns the a css class with optional prefix for the particular log level.
- * if prefix is set result will be <prefix>-<css-class> - * - * @param prefix (optional) a prefic - * @param level the log level - * @return - */ - public String getLoggerLevelCss(String prefix, Level level) { - if (null == prefix) { - prefix = ""; - } else { - prefix += "-"; - } - if (level.intLevel() == StandardLevel.TRACE.intLevel()) { - return prefix + "info"; - } - if (level.intLevel() == StandardLevel.DEBUG.intLevel()) { - return prefix + "primary"; - } - if (level.intLevel() == StandardLevel.INFO.intLevel()) { - return prefix + "success"; - } - if (level.intLevel() == StandardLevel.WARN.intLevel()) { - return prefix + "warning"; - } - if (level.intLevel() == StandardLevel.ERROR.intLevel()) { - return prefix + "danger"; - } - if (level.intLevel() == StandardLevel.FATAL.intLevel()) { - return prefix + "muted"; - } - if (level.intLevel() == StandardLevel.OFF.intLevel()) { - return prefix + "muted"; - } - return ""; - } - - /** - * returns fix amount of logger levels - * @return - */ - public Collection getLevels() { - return LEVELS; - } - - private Level getLevel(final String levelStr) { - Level level = Level.getLevel(levelStr); - if (null == level || !LEVELS.contains(level)) { - throw new IllegalArgumentException("wrong logger level: " + String.valueOf(levelStr)); - } - return level; - } - - /** - * changes the level of an logger - * - * @param name logger name - * @param levelStr level as string - * @param parent if the logger is a parent logger - * @throws IllegalArgumentException - */ - public void changeLogger(final String name, final String levelStr, boolean parent) throws IllegalArgumentException - { - Level level = getLevel(levelStr); - changeLogger(name, level, parent); - } - - /** - * - * @param name - * @param level - * @param parent - * @throws IllegalArgumentException - * @see {@link #changeLogger(String, String, boolean)} - */ - public void changeLogger(final String name, final Level level, boolean parent) throws IllegalArgumentException - { - if (null == name) { - throw new IllegalArgumentException("logger name must not null"); - } - String loggerName = name; - if (name.equals("ROOT")) { - loggerName = LogManager.ROOT_LOGGER_NAME; - } - LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - Configuration config = ctx.getConfiguration(); - LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); - if (null == loggerConfig) { - throw new IllegalArgumentException("no logger config found for: " + String.valueOf(loggerName)); - } - if (customLoggers.containsValue(loggerName)) { - setLevelOnExistingCustomLogger(this.customLoggers, loggerName, level); - } - else if (customParentLoggers.containsValue(loggerName)) { - setLevelOnExistingCustomLogger(this.customParentLoggers, loggerName, level); - } - else if (!loggerConfig.getName().equals(loggerName)) { - LoggerConfig loggerConfigNew = new LoggerConfig(); - loggerConfigNew.setLevel(level); - config.addLogger(loggerName, loggerConfigNew); - if (parent) { - customParentLoggers.put(loggerConfigNew, loggerName); - } else { - customLoggers.put(loggerConfigNew, loggerName); - } - } - else { - loggerConfig.setLevel(level); - } - ctx.updateLoggers(); - } - - private void setLevelOnExistingCustomLogger(Map customLoggers, String loggerName, Level level) { - for (Entry entry : customLoggers.entrySet()) { - if (entry.getValue().equals(loggerName)) { - entry.getKey().setLevel(level); - } - } - } - - /** - * removes all custom loggers - * - * @throws IllegalArgumentException - */ - public void removeCustomLoggers() throws IllegalArgumentException - { - if (customLoggers.isEmpty()) { - return; - } - LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - Configuration config = ctx.getConfiguration(); - for (Entry entry : customLoggers.entrySet()) { - config.removeLogger(entry.getValue()); - } - ctx.updateLoggers(); - customLoggers.clear(); - } - - /** - * returns the default log message pattern (used in template) - * @return - * @since 1.1.1 - */ - public String getDefaultPattern() { - return DEFAULT_PATTERN; - } - - /** - * creates the custom output steam appender and returns the name - * - * @param name - * @param pattern - * @param encoding - * @param loggerNames - * @param levelStr - * @return - * @since 1.1.1 - */ - public String createOutputStreamAppender(String name, String pattern, String encoding, Collection loggerNames, - String levelStr, boolean recursive, boolean overrideLogLevel) { - Level level = getLevel(levelStr); - String encodingToUse = StringUtils.isEmpty(encoding) ? "UTF-8" : encoding; - PatternLayout layout = PatternLayout.newBuilder() - .withPattern(StringUtils.isEmpty(pattern) ? DEFAULT_PATTERN : pattern) - .withCharset(Charset.forName(encodingToUse)) - .build(); - - String appenderName = StringUtils.isEmpty(name) ? UUID.randomUUID().toString() : name; - - AdminToolLog4j2OutputStream baos = new AdminToolLog4j2OutputStream(4096, encodingToUse); - outputStreams.put(appenderName, baos); - - OutputStreamAppender appender = OutputStreamAppender.newBuilder() - .setName(appenderName) - .setTarget(baos) - .setLayout(layout) - .setFollow(false) - .build(); - - appender.start(); - - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - config.addAppender(appender); - - Collection parentLoggerNames = getParentLoggerNames(); - - for (String configuredLoggerName : getAllLoggerNames()) { - for (String loggerNameToApply : loggerNames) { - - boolean apply = (recursive && configuredLoggerName.startsWith(loggerNameToApply)) - || (!recursive && configuredLoggerName.equalsIgnoreCase(loggerNameToApply)); - - if (apply) { - LoggerConfig loggerConfig = config.getLoggerConfig(configuredLoggerName); - loggerConfig.addAppender(appender, level, null); - if (overrideLogLevel) { - baos.addOriginalLevel(configuredLoggerName, loggerConfig.getLevel()); - changeLogger(configuredLoggerName, level, parentLoggerNames.contains(configuredLoggerName)); - } - } - } - - } - ctx.updateLoggers(); - return appenderName; - } - - /** - * returns the log messages from custom appenders output stream - * - * @param appenderName - * @param encoding - * @return - * @throws UnsupportedEncodingException - * @since 1.1.1 - */ - public String getStringOutput(String appenderName, String encoding) throws UnsupportedEncodingException { - AdminToolLog4j2OutputStream baos = outputStreams.get(appenderName); - String output = ""; - if (null != baos) { - output = baos.getAndReset(encoding); - } - return output.trim().isEmpty() ? null : output; - - } - - /** - * closes output stream and removes appender from loggers - * @param appenderName - * @throws IOException - * @since 1.1.1 - */ - public void closeOutputStreamAppender(String appenderName) throws IOException { - if (null == appenderName) { - return; - } - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - AdminToolLog4j2OutputStream baos = outputStreams.get(appenderName); - - if (null != config && null != config.getAppenders()) { - OutputStreamAppender appender = config.getAppender(appenderName); - if (null != appender) { - appender.stop(); - - Collection parentLoggerNames = getParentLoggerNames(); - - for (String configuredLoggerName : getAllLoggerNames()) { - LoggerConfig loggerConfig = config.getLoggerConfig(configuredLoggerName); - loggerConfig.removeAppender(appender.getName()); - if (null != baos.getOriginalLevel(configuredLoggerName)) { - changeLogger(configuredLoggerName, baos.getOriginalLevel(configuredLoggerName), - parentLoggerNames.contains(configuredLoggerName)); - } - } - //unsure about, if removing the appender from logger config if it gets also removed from logger instance too... - removeAppender(appender, getParentLoggers()); - removeAppender(appender, getLoggers()); - appender.getManager().getByteBuffer().clear(); - - ctx.updateLoggers(); - } - } - - if (null != baos) { - try { - baos.close(); - baos.clearOriginalLevels(); - } catch (Exception ignore) { - } finally { - outputStreams.remove(appenderName); - } - } - } - - private void removeAppender(Appender appender, Collection appenders) { - for (Logger logger : appenders) { - logger.removeAppender(appender); - } - } - - public Map getAppenders() { - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - - return config.getAppenders(); - } - -} +package de.chandre.admintool.log4j2; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.OutputStreamAppender; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.spi.StandardLevel; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ConcurrentReferenceHashMap; +import org.springframework.util.StringUtils; + +/** + * service for log4j2 manipulation + * @author Andre + * @since 1.0.0 + */ +@Service("adminToolLog4j2Util") +public class AdminToolLog4j2Util +{ + private static List LEVELS = new ArrayList<>(7); + static { + LEVELS.add(Level.OFF); + LEVELS.add(Level.TRACE); + LEVELS.add(Level.DEBUG); + LEVELS.add(Level.INFO); + LEVELS.add(Level.WARN); + LEVELS.add(Level.ERROR); + LEVELS.add(Level.FATAL); + } + + private static final Comparator LOGGER_COMP = new Comparator() { + @Override + public int compare(Logger o1, Logger o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + + private static final String DEFAULT_PATTERN = "%d{dd.MM.yyyy HH:mm:ss.SSS} %X{sessionId} [%t] %-5level %logger{36} : %msg%n"; + + public static final String SESSION_APPENDER_NAME = "log4j2AppenderName"; + + private Map customLoggers = new ConcurrentReferenceHashMap<>(); + private Map customParentLoggers = new ConcurrentReferenceHashMap<>(); + + private Map outputStreams = new ConcurrentReferenceHashMap<>(); + + public int getCustomLoggerSize() { + return customLoggers.size(); + } + + public int getCustomParentLoggerSize() { + return customParentLoggers.size(); + } + + public boolean isCustom(String name) { + return customLoggers.containsValue(name) || customParentLoggers.containsValue(name); + } + + /** + * returns all parent loggers + * @return + */ + public Collection getParentLoggers() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + List loggers = new ArrayList<>(ctx.getLoggers()); + Map parentMap = new HashMap<>(); + try { + for (Logger logger : loggers) { + if (null != logger.getParent() && parentMap.get(logger.getParent().getName()) == null) { + parentMap.put(logger.getParent().getName(), logger.getParent()); + } + } + List parents = new ArrayList<>(parentMap.values()); + Collections.sort(parents, LOGGER_COMP); + return parents; + } finally { + loggers.clear(); + parentMap.clear(); + } + } + + public Collection getParentLoggerNames() { + List loggerNames = new ArrayList<>(); + for (Logger logger : getParentLoggers()) { + loggerNames.add(logger.getName()); + } + return loggerNames; + } + + /** + * returns all loggers + * @return + */ + public Collection getLoggers() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + List loggers = new ArrayList<>(ctx.getLoggers()); + Collections.sort(loggers, LOGGER_COMP); + return loggers; + } + + /** + * returns all logger names including custom loggers + * + * @since 1.1.1 + * @return + */ + public Collection getAllLoggerNames() { + Set loggerNames = new TreeSet<>(); + for (Logger logger : getParentLoggers()) { + loggerNames.add(logger.getName()); + } + for (Logger logger : getLoggers()) { + loggerNames.add(logger.getName()); + } + if (!customLoggers.isEmpty()) { + for (Entry entry : customLoggers.entrySet()) { + loggerNames.add(entry.getKey().getName()); + } + } + if (!customParentLoggers.isEmpty()) { + for (Entry entry : customParentLoggers.entrySet()) { + loggerNames.add(entry.getKey().getName()); + } + } + return loggerNames; + } + + /** + * returns the a css class with optional prefix for the particular log level.
+ * if prefix is set result will be <prefix>-<css-class> + * + * @param prefix (optional) a prefic + * @param level the log level + * @return + */ + public String getLoggerLevelCss(String prefix, Level level) { + if (null == prefix) { + prefix = ""; + } else { + prefix += "-"; + } + if (level.intLevel() == StandardLevel.TRACE.intLevel()) { + return prefix + "info"; + } + if (level.intLevel() == StandardLevel.DEBUG.intLevel()) { + return prefix + "primary"; + } + if (level.intLevel() == StandardLevel.INFO.intLevel()) { + return prefix + "success"; + } + if (level.intLevel() == StandardLevel.WARN.intLevel()) { + return prefix + "warning"; + } + if (level.intLevel() == StandardLevel.ERROR.intLevel()) { + return prefix + "danger"; + } + if (level.intLevel() == StandardLevel.FATAL.intLevel()) { + return prefix + "muted"; + } + if (level.intLevel() == StandardLevel.OFF.intLevel()) { + return prefix + "muted"; + } + return ""; + } + + /** + * returns fix amount of logger levels + * @return + */ + public Collection getLevels() { + return LEVELS; + } + + private Level getLevel(final String levelStr) { + Level level = Level.getLevel(levelStr); + if (null == level || !LEVELS.contains(level)) { + throw new IllegalArgumentException("wrong logger level: " + String.valueOf(levelStr)); + } + return level; + } + + /** + * changes the level of an logger + * + * @param name logger name + * @param levelStr level as string + * @param parent if the logger is a parent logger + * @throws IllegalArgumentException + */ + public void changeLogger(final String name, final String levelStr, boolean parent) throws IllegalArgumentException + { + Level level = getLevel(levelStr); + changeLogger(name, level, parent); + } + + /** + * + * @param name + * @param level + * @param parent + * @throws IllegalArgumentException + * @see {@link #changeLogger(String, String, boolean)} + */ + public void changeLogger(final String name, final Level level, boolean parent) throws IllegalArgumentException + { + if (null == name) { + throw new IllegalArgumentException("logger name must not null"); + } + String loggerName = name; + if (name.equals("ROOT")) { + loggerName = LogManager.ROOT_LOGGER_NAME; + } + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); + if (null == loggerConfig) { + throw new IllegalArgumentException("no logger config found for: " + String.valueOf(loggerName)); + } + if (customLoggers.containsValue(loggerName)) { + setLevelOnExistingCustomLogger(this.customLoggers, loggerName, level); + } + else if (customParentLoggers.containsValue(loggerName)) { + setLevelOnExistingCustomLogger(this.customParentLoggers, loggerName, level); + } + else if (!loggerConfig.getName().equals(loggerName)) { +// LoggerConfig loggerConfigNew = new LoggerConfig(); +// loggerConfigNew.setLevel(level); +// config.addLogger(loggerName, loggerConfigNew); +// if (parent) { +// customParentLoggers.put(loggerConfigNew, loggerName); +// } else { +// customLoggers.put(loggerConfigNew, loggerName); +// } + addCustomParentLogger(false, level, loggerName, Arrays.asList("Console")); + } + else { + loggerConfig.setLevel(level); + } + ctx.updateLoggers(); + } + + private void setLevelOnExistingCustomLogger(Map customLoggers, String loggerName, Level level) { + for (Entry entry : customLoggers.entrySet()) { + if (entry.getValue().equals(loggerName)) { + entry.getKey().setLevel(level); + } + } + } + + public Collection getAppenderNames() { + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + return config.getAppenders().keySet(); + } + + public String getAppendersForLogger(String loggerName) { + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); + List appenderRefs = loggerConfig.getAppenderRefs(); + return StringUtils.collectionToCommaDelimitedString(appenderRefs.parallelStream().map(ar -> ar.getRef()).collect(Collectors.toSet())); + } + + /** + * + * @param additivity + * @param level + * @param loggerName + * @param appenderNames + * @param recursive + * + * @since 1.1.6.4 + */ + public void addCustomParentLogger(boolean additivity, String levelStr, String loggerName, Collection appenderNames) { + Level level = getLevel(levelStr); + addCustomParentLogger(additivity, level, loggerName, appenderNames); + } + + /** + * + * @param additivity + * @param level + * @param loggerName + * @param appenderNames + * @param recursive + * + * @since 1.1.6.4 + */ + public void addCustomParentLogger(boolean additivity, Level level, String loggerName, Collection appenderNames) { + if (StringUtils.isEmpty(loggerName)) { + throw new IllegalArgumentException("loggerName should not be null"); + } + if (null == level) { + throw new IllegalArgumentException("level should not be null"); + } + + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + + if (null == appenderNames) { + appenderNames = Collections.emptyList(); + } + List appenderRefs = appenderNames.stream() + .map(name -> AppenderRef.createAppenderRef(name, null, null)) + .collect(Collectors.toList()); + + LoggerConfig loggerConfigForTest = config.getLoggerConfig(loggerName); + List appenderRefsToAdd = new ArrayList<>(appenderNames); + final LoggerConfig loggerConfig; + if (null == loggerConfigForTest || StringUtils.isEmpty(loggerConfigForTest.getName()) || !loggerConfigForTest.getName().equals(loggerName)) { + //create a new Logger + loggerConfig = LoggerConfig.createLogger(additivity, level, loggerName, "true", appenderRefs.toArray(new AppenderRef[]{}), null, config, null); + customParentLoggers.put(loggerConfig, loggerName); + } + else { + //manage a existing logger + loggerConfig = config.getLoggerConfig(loggerName); + //remove appenderRef which are not selected anymore + List currentRefs = loggerConfig.getAppenderRefs(); + Iterator refIter = currentRefs.iterator(); + while (refIter.hasNext()) { + AppenderRef ref = (AppenderRef) refIter.next(); + if (!appenderNames.contains(ref.getRef())) { + refIter.remove(); + loggerConfig.removeAppender(ref.getRef()); + } else { + appenderRefsToAdd.remove(ref.getRef()); + } + + } + //add appendersRefs + if (!CollectionUtils.isEmpty(appenderRefsToAdd)) { + appenderRefsToAdd.forEach(appenderRefName -> { + loggerConfig.getAppenderRefs().add(AppenderRef.createAppenderRef(appenderRefName, null, null)); + }); + } + } + + config.getAppenders().entrySet().stream() + .filter(entry -> appenderRefsToAdd.contains(entry.getKey())) + .forEach(appenderEntry -> loggerConfig.addAppender(appenderEntry.getValue(), null, null)); + + config.addLogger(loggerName, loggerConfig); + ctx.updateLoggers(); + } + + /** + * removes all custom loggers (without parents) + * + * @throws IllegalArgumentException + */ + public void removeCustomLoggers() throws IllegalArgumentException + { + removeCustomLoggers(customLoggers); + } + + /** + * removes all custom parent loggers + * @throws IllegalArgumentException + */ + public void removeCustomParentLoggers() throws IllegalArgumentException + { + removeCustomLoggers(customParentLoggers); + } + + public void removeCustomLoggers(Map customMap) throws IllegalArgumentException + { + if (customMap.isEmpty()) { + return; + } + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + for (Entry entry : customMap.entrySet()) { + config.removeLogger(entry.getValue()); + } + ctx.updateLoggers(); + customMap.clear(); + } + + + /** + * returns the default log message pattern (used in template) + * @return + * @since 1.1.1 + */ + public String getDefaultPattern() { + return DEFAULT_PATTERN; + } + + /** + * creates the custom output steam appender and returns the name + * + * @param name + * @param pattern + * @param encoding + * @param loggerNames + * @param levelStr + * @return + * @since 1.1.1 + */ + public String createOutputStreamAppender(String name, String pattern, String encoding, Collection loggerNames, + String levelStr, boolean recursive, boolean overrideLogLevel) { + Level level = getLevel(levelStr); + String encodingToUse = StringUtils.isEmpty(encoding) ? "UTF-8" : encoding; + PatternLayout layout = PatternLayout.newBuilder() + .withPattern(StringUtils.isEmpty(pattern) ? DEFAULT_PATTERN : pattern) + .withCharset(Charset.forName(encodingToUse)) + .build(); + + String appenderName = StringUtils.isEmpty(name) ? UUID.randomUUID().toString() : name; + + AdminToolLog4j2OutputStream baos = new AdminToolLog4j2OutputStream(4096, encodingToUse); + outputStreams.put(appenderName, baos); + + OutputStreamAppender appender = OutputStreamAppender.newBuilder() + .setName(appenderName) + .setTarget(baos) + .setLayout(layout) + .setFollow(false) + .build(); + + appender.start(); + + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + config.addAppender(appender); + + Collection parentLoggerNames = getParentLoggerNames(); + + Map configs = getRecursiveLoggerConfigs(loggerNames, recursive, config); + configs.entrySet().forEach(configEntry ->{ + configEntry.getValue().addAppender(appender, level, null); + if (overrideLogLevel) { + baos.addOriginalLevel(configEntry.getKey(), configEntry.getValue().getLevel()); + changeLogger(configEntry.getKey(), level, parentLoggerNames.contains(configEntry.getKey())); + } + }); + + ctx.updateLoggers(); + return appenderName; + } + + /** + * + * @param loggerNames + * @param recursive + * @param config + * @return + */ + private Map getRecursiveLoggerConfigs(Collection loggerNames, boolean recursive, + final Configuration config) { + Map configs = new HashMap<>(); + for (String configuredLoggerName : getAllLoggerNames()) { + for (String loggerNameToApply : loggerNames) { + + boolean apply = (recursive && configuredLoggerName.startsWith(loggerNameToApply)) + || (!recursive && configuredLoggerName.equalsIgnoreCase(loggerNameToApply)); + if (apply) { + configs.put(configuredLoggerName, config.getLoggerConfig(configuredLoggerName)); + } + } + } + return configs; + } + + /** + * returns the log messages from custom appenders output stream + * + * @param appenderName + * @param encoding + * @return + * @throws UnsupportedEncodingException + * @since 1.1.1 + */ + public String getStringOutput(String appenderName, String encoding) throws UnsupportedEncodingException { + AdminToolLog4j2OutputStream baos = outputStreams.get(appenderName); + String output = ""; + if (null != baos) { + output = baos.getAndReset(encoding); + } + return output.trim().isEmpty() ? null : output; + + } + + /** + * closes output stream and removes appender from loggers + * @param appenderName + * @throws IOException + * @since 1.1.1 + */ + public void closeOutputStreamAppender(String appenderName) throws IOException { + if (null == appenderName) { + return; + } + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + AdminToolLog4j2OutputStream baos = outputStreams.get(appenderName); + + if (null != config && null != config.getAppenders()) { + OutputStreamAppender appender = config.getAppender(appenderName); + if (null != appender) { + appender.stop(); + + Collection parentLoggerNames = getParentLoggerNames(); + + for (String configuredLoggerName : getAllLoggerNames()) { + LoggerConfig loggerConfig = config.getLoggerConfig(configuredLoggerName); + loggerConfig.removeAppender(appender.getName()); + if (null != baos.getOriginalLevel(configuredLoggerName)) { + changeLogger(configuredLoggerName, baos.getOriginalLevel(configuredLoggerName), + parentLoggerNames.contains(configuredLoggerName)); + } + } + //unsure about, if removing the appender from logger config if it gets also removed from logger instance too... + removeAppender(appender, getParentLoggers()); + removeAppender(appender, getLoggers()); + appender.getManager().getByteBuffer().clear(); + + ctx.updateLoggers(); + } + } + + if (null != baos) { + try { + baos.close(); + baos.clearOriginalLevels(); + } catch (Exception ignore) { + } finally { + outputStreams.remove(appenderName); + } + } + } + + private void removeAppender(Appender appender, Collection appenders) { + for (Logger logger : appenders) { + logger.removeAppender(appender); + } + } + + public Map getAppenders() { + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + + return config.getAppenders(); + } + +} diff --git a/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/Log4j2ManageLoggerTO.java b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/Log4j2ManageLoggerTO.java new file mode 100644 index 0000000..fee158b --- /dev/null +++ b/admin-tools-log4j2/src/main/java/de/chandre/admintool/log4j2/Log4j2ManageLoggerTO.java @@ -0,0 +1,101 @@ +package de.chandre.admintool.log4j2; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @author Chandre + * @since 1.1.6.4 + */ +public class Log4j2ManageLoggerTO implements Serializable { + private static final long serialVersionUID = 991894759701275970L; + + private String loggerName; + + private List appenderNames; + + private String level; + + private boolean additivity; + + public String getLoggerName() { + return loggerName; + } + + public void setLoggerName(String loggerName) { + this.loggerName = loggerName; + } + + public List getAppenderNames() { + return appenderNames; + } + + public void setAppenderNames(List appenderNames) { + this.appenderNames = appenderNames; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public boolean isAdditivity() { + return additivity; + } + + public void setAdditivity(boolean additivity) { + this.additivity = additivity; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Log4j2ManageLoggerTO [loggerName=").append(loggerName).append(", appenderNames=").append(appenderNames) + .append(", level=").append(level).append(", additivity=").append(additivity).append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (additivity ? 1231 : 1237); + result = prime * result + ((appenderNames == null) ? 0 : appenderNames.hashCode()); + result = prime * result + ((level == null) ? 0 : level.hashCode()); + result = prime * result + ((loggerName == null) ? 0 : loggerName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Log4j2ManageLoggerTO other = (Log4j2ManageLoggerTO) obj; + if (additivity != other.additivity) + return false; + if (appenderNames == null) { + if (other.appenderNames != null) + return false; + } else if (!appenderNames.equals(other.appenderNames)) + return false; + if (level == null) { + if (other.level != null) + return false; + } else if (!level.equals(other.level)) + return false; + if (loggerName == null) { + if (other.loggerName != null) + return false; + } else if (!loggerName.equals(other.loggerName)) + return false; + return true; + } +} diff --git a/admin-tools-log4j2/src/main/resources/static/admintool/css/log4j2.css b/admin-tools-log4j2/src/main/resources/static/admintool/css/log4j2.css index 2ebfc64..0731232 100644 --- a/admin-tools-log4j2/src/main/resources/static/admintool/css/log4j2.css +++ b/admin-tools-log4j2/src/main/resources/static/admintool/css/log4j2.css @@ -1,60 +1,63 @@ - -.label { - margin: 0 2px 0 0; -} - -.label-muted { - background-color:#777 !important; -} - -.changeLogger { - color: #fff; - cursor: pointer; - cursor: hand; -} - -.logname { - white-space: normal; - overflow-wrap: break-word; - word-wrap: break-word; - /*word-break: break-word;*/ - word-break: break-all; - -ms-hyphens: auto; - -moz-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} -td.loglevel { - width: 58px; - min-width: 58px; -} -td.logaction { - width: 330px; - min-width: 330px; -} -span.logline { - display: block; - white-space: nowrap; - width: 100%; -} - -div#lineNumbers { - width: 3%; - float: left; - text-align: right; -} -div#consoleContent { - overflow-x: scroll; - height: 100%; - width: 96%; - float: right; -} - -@media (max-width: 991px) { - div#lineNumbers { - width: 6%; - } - div#consoleContent { - width: 93%; - } -} +.topButton { + margin: 0 0 0 2px; +} + +.label { + margin: 0 2px 0 0; +} + +.label-muted { + background-color:#777 !important; +} + +.changeLogger { + color: #fff; + cursor: pointer; + cursor: hand; +} + +.logname { + white-space: normal; + overflow-wrap: break-word; + word-wrap: break-word; + /*word-break: break-word;*/ + word-break: break-all; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +td.loglevel { + width: 58px; + min-width: 58px; +} +td.logaction { + width: 340px; + min-width: 340px; +} +span.logline { + display: block; + white-space: nowrap; + width: 100%; +} + +div#lineNumbers { + width: 3%; + float: left; + text-align: right; +} +div#consoleContent { + overflow-x: scroll; + height: 100%; + width: 96%; + float: right; +} + +@media (max-width: 991px) { + div#lineNumbers { + width: 6%; + } + div#consoleContent { + width: 93%; + } +} diff --git a/admin-tools-log4j2/src/main/resources/static/admintool/js/log4j2.js b/admin-tools-log4j2/src/main/resources/static/admintool/js/log4j2.js index 2828297..69c3cc3 100644 --- a/admin-tools-log4j2/src/main/resources/static/admintool/js/log4j2.js +++ b/admin-tools-log4j2/src/main/resources/static/admintool/js/log4j2.js @@ -1,333 +1,437 @@ -var leveCss = null; -var prefix = 'bg'; - -AdminTool.Log4j = {} - -AdminTool.Log4j.Loggers = function(el, options) { - if (el) { - this.init(el, options) - } -} -AdminTool.Log4j.Loggers.prototype = new AdminTool.Core(); - -$.extend(AdminTool.Log4j.Loggers.prototype, { - - name : 'adminToolLog4jLoggers', - - postInit: function() { - this.sendRequest( - {url: "/admintool/log4j2/getLevelCss/" + prefix, dataType: "json", my: this}, - function(data, query) { - query.my.setLevelCss(data); - } - ); - this.bind(); - }, - - bind : function() { - if($('#parentLoggers').length > 0) { - $('#parentLoggers').on('init.dt', $.proxy(this.initEvents, this)).dataTable(); - $('#parentLoggers').on('page.dt', $.proxy(this.initEvents, this)); - } - var eventsInitialized = false; - if($('#loggers').length > 0) { - $('#loggers').on('init.dt', $.proxy(this.initEvents, this)).dataTable(); - $('#loggers').on('page.dt', $.proxy(this.initEvents, this)); - eventsInitialized = true; - } - - if($('.removeCustomLogger').length > 0) { - $('.removeCustomLogger').click(function(){ - sendRequest("/admintool/log4j2/removeCustomLoggers", "POST", "text", function(data) { - location.reload(); - }); - }); - } - }, - - initEvents : function() { - $('.changeLogger').each(function() { - var $el = $(this); - $el.unbind('click'); - $el.on({'click': function(){ - getByID('log4jContent').adminToolLog4jLoggers('changeLogLevel', $el)} - }); - }); - }, - - unbind : function() { - $('.removeCustomLogger').unbind(); - $('.changeLogger').unbind(); - }, - - - setLevelCss : function (levels) { - this.levelCss = levels; - }, - - getCurrentLevel: function($link) { - return $link.html(); - }, - - getCurrentRow: function($link) { - return $($link.parent().parent()); - }, - - changeLogLevel : function(link) { - var $link = $(link); - var level = this.getCurrentLevel($link); - var $tr = this.getCurrentRow($link); - var name = $tr.find('.logname').text(); - var serviceUrl = "/admintool/log4j2/changeLevel/" + name + "/" + level; - if ($tr.hasClass('parent')) { - serviceUrl += "/parent/true"; - } - - this.sendRequest( - {url: serviceUrl, requestType: "POST", dataType: "text", my: this, link: $link}, - function(data, query) { - query.my.changeLogLevelDone(data, query.link); - } - ); - }, - - changeLogLevelDone: function(data, $link) { - if (data == 'true') { - var $levelTd = this.getCurrentRow($link).children('.loglevel'); - var oldlevel = $levelTd.text(); - var level = this.getCurrentLevel($link); - - $levelTd.removeAddClass(this.levelCss[oldlevel], this.levelCss[level]); - $levelTd.text(level); - } else if (data == 'reload') { - location.reload(); - } else { - $('#admintoolError').modal(); - } - } - -}); -$.pluginMaker(AdminTool.Log4j.Loggers); - - -AdminTool.Log4j.Console = function(el, options) { - if (el) { - this.init(el, options) - } -} -AdminTool.Log4j.Console.prototype = new AdminTool.Core(); - -$.extend(AdminTool.Log4j.Console.prototype, { - - name : 'adminToolLog4jConsole', - - postInit: function() { - this.bind(); - this.requestCount = 0; - this.lineCount = 0; - this.maxListLength = 100; - this.initCheckboxes(); - }, - - bind : function() { - this.loggerNames = getByID('loggerNames').select2({ - placeholder: 'Root Logger' - }); - - getByID('startConsole').on({'click': $.proxy(this.startConsole, this)}); - getByClazz('stopConsole').hide(); - getByID('clearConsole').on({'click': $.proxy(this.clearConsole, this)}); - - }, - - unbind : function() { - getByID('loggerNames').unbind(); - getByID('startConsole').unbind(); - getByID('clearConsole').unbind(); - }, - - initCheckboxes: function() { - getByID('recursive').iCheck('destroy'); - getByID('recursive').iCheck({ - checkboxClass: 'icheckbox_minimal', - radioClass: 'iradio_minimal' -// increaseArea: '20%' // optional - }); - getByID('overrideLogLevel').iCheck('destroy'); - getByID('overrideLogLevel').iCheck({ - checkboxClass: 'icheckbox_minimal', - radioClass: 'iradio_minimal' -// increaseArea: '20%' // optional - }); - }, - - startConsole : function() { - - var data = { -// name:getByID('name').val(), - pattern: getByID('pattern').val(), - encoding: getByID('encoding').val(), - recursive: getByID('recursive').prop("checked"), - overrideLogLevel: getByID('overrideLogLevel').prop("checked"), - level: getByID('level').val(), - loggerNames: this.loggerNames.val() - }; - - this.sendRequest( - { - url: "/admintool/log4j2/initConsole", - requestType: "POST", - dataType: "text", - data: JSON.stringify(data), - showModalOnError: true, - my: this - }, - function(data, query) { - query.my.consoleStarted(data); - } - ); - }, - - consoleStarted : function(data) { - var stopButtons = getByClazz('stopConsole'); - stopButtons.on({'click': $.proxy(this.stopConsole, this)}); - stopButtons.show(); - this.startUpdateConsole(); - $.AdminLTE.boxWidget.collapse(getByID('log4jTailConfigCollapse')); - getByID('startConsole').prop('disabled', true); - }, - - startUpdateConsole : function() { - this.intervalId = setInterval(function() { - getByID('log4jTail').adminToolLog4jConsole('updateConsole'); - }, 5000); - }, - - stopUpdateConsole : function() { - clearInterval(this.intervalId); - this.intervalId = null; - getByID('startConsole').prop('disabled', false); - }, - - updateConsole: function() { - this.sendRequest( - {url: "/admintool/log4j2/getConsoleContent", dataType: "text", my: this}, - function(data, query) { - if (null != data && data.trim() != "" && data.trim() != "null") { - var lines = data.trim().split("\n"); - if (lines.length > 0) { - var existingLines = $('#consoleContent span'); - var existingNumbers = $('#lineNumbers span'); - var hasContent = existingLines.length > 0; - var clazz; - for (var i=-1, l=lines.length; ++i < l;) { - var line = lines[i]; - if (line == null || line == undefined || line.trim() == "") { - continue; - } - clazz = query.my.getSpanClass(line) || clazz; - - if (!hasContent) { - getByID('consoleContent').html(query.my.getText(line, clazz)); - getByID('lineNumbers').html(query.my.getText("1", "text-muted")); - query.my.lineCount = 1; - } else { - $('#consoleContent span:last-child').after(query.my.getText(line, clazz)); - query.my.lineCount++ - $('#lineNumbers span:last-child').after(query.my.getText(query.my.lineCount.toString(), "text-muted")); - } - } - - var oversize = lines.length + existingLines.length - query.my.getMaxListLength(); - if (oversize > 0) { - for (var i=-1; ++i < oversize;) { - $(existingLines[i]).remove(); - $(existingNumbers[i]).remove(); - } - } - - if (getByID('scrollToBottom').prop( "checked" )) { - $('html, body').scrollTop(getByID('consoleContent')[0].scrollHeight); - } - } - } - query.my.requestCount++; - getByID('requestCount').text(query.my.requestCount); - } - ); - }, - - getMaxListLength() { - var userMaxLength = parseInt(getByID('maxListLength').val()); - if (isNaN(userMaxLength) || userMaxLength == Infinity) { - return this.maxListLength; - } - return userMaxLength; - }, - - getText: function(line, clazz) { - line = line.replace(//g, '>'); - if (undefined !== clazz) { - return '' + line + ''; - } - return '' + line + ''; - }, - - getSpanClass: function(line) { - var lowerLine = line.toLowerCase(); - if (lowerLine.indexOf(' error ') != -1 || lowerLine.indexOf(' fatal ') != -1) { - return "text-danger"; - } - else if (lowerLine.indexOf(' warn ') != -1) { - return "text-warning"; - } - else if (lowerLine.indexOf(' info ') != -1 || lowerLine.indexOf(' debug ') != -1 || lowerLine.indexOf(' trace ') != -1) { - return "text-info"; - } - else if (lowerLine.indexOf(' off ') != -1) { - return "text-muted"; - } - return undefined; - }, - - stopConsole : function() { - this.stopUpdateConsole(); - this.sendRequest( - { - url: "/admintool/log4j2/stopConsole", - dataType: "text", - showModalOnError: true, - my: this - }, - function(data, query) { - query.my.consoleStopped(data); - } - ); - }, - - consoleStopped : function(data) { - var stopButtons = getByClazz('stopConsole'); - stopButtons.unbind(); - stopButtons.hide(); - }, - - clearConsole : function() { - this.requestCount = 0; - this.lineCount = 0; - getByID('requestCount').text(this.requestCount); - getByID('consoleContent').text(""); - getByID('lineNumbers').text(""); - } - -}); -$.pluginMaker(AdminTool.Log4j.Console); - - -$( document ).ready(function() { - if (getByID('log4jContent').length > 0) { - getByID('log4jContent').adminToolLog4jLoggers(); - } - if (getByID('log4jTail').length > 0) { - getByID('log4jTail').adminToolLog4jConsole(); - } +var leveCss = null; +var prefix = 'bg'; + +AdminTool.Log4j = {} + +AdminTool.Log4j.Loggers = function(el, options) { + if (el) { + this.init(el, options) + } +} +AdminTool.Log4j.Loggers.prototype = new AdminTool.Core(); + +$.extend(AdminTool.Log4j.Loggers.prototype, { + + name : 'adminToolLog4jLoggers', + + postInit: function() { + this.sendRequest( + {url: "/admintool/log4j2/getLevelCss/" + prefix, dataType: "json", my: this}, + function(data, query) { + query.my.setLevelCss(data); + } + ); + this.bind(); + }, + + bind : function() { + if($('#parentLoggers').length > 0) { + $('#parentLoggers').on('init.dt', $.proxy(this.initEvents, this)).dataTable(); + $('#parentLoggers').on('page.dt', $.proxy(this.initEvents, this)); + } + var eventsInitialized = false; + if($('#loggers').length > 0) { + $('#loggers').on('init.dt', $.proxy(this.initEvents, this)).dataTable(); + $('#loggers').on('page.dt', $.proxy(this.initEvents, this)); + eventsInitialized = true; + } + + if($('.removeCustomLogger').length > 0) { + $('.removeCustomLogger').click(function(){ + sendRequest("/admintool/log4j2/removeCustomLoggers", "POST", "text", function(data) { + location.reload(); + }); + }); + } + + if($('.removeCustomParentLogger').length > 0) { + $('.removeCustomParentLogger').click(function(){ + sendRequest("/admintool/log4j2/removeCustomParentLogger", "POST", "text", function(data) { + location.reload(); + }); + }); + } + }, + + initEvents : function() { + $('.changeLogger').each(function() { + var $el = $(this); + $el.unbind('click'); + $el.on({'click': function(){ + getByID('log4jContent').adminToolLog4jLoggers('changeLogLevel', $el)} + }); + }); + $('.manageLogger').each(function() { + var $el = $(this); + $el.unbind('click'); + $el.on({'click': function(){ + getByID('log4jContent').adminToolLog4jLoggers('manageLogger', $el)} + }); + }); + getByID('addCustomLogger').on({'click': function(){ + getByID('log4jContent').adminToolLog4jLoggers('manageLogger', null)} + }); + + this.initModalInputs(); + }, + + initModalInputs: function() { + getByID('appenderNames').select2({ + placeholder: 'Appenders', + width: '100%' + }); + + getByID('additivity').iCheck('destroy'); + getByID('additivity').iCheck({ + checkboxClass: 'icheckbox_minimal', + radioClass: 'iradio_minimal' + }); + }, + + unbind : function() { + $('.removeCustomLogger').unbind(); + $('.removeCustomParentLogger').unbind(); + $('.changeLogger').unbind(); + getByID('addCustomLogger').unbind(); + getByID('manageLogger_submit').unbind(); + getByID('appenderNames').select2('destroy'); + getByID('additivity').iCheck('destroy'); + }, + + setLevelCss : function (levels) { + this.levelCss = levels; + }, + + getCurrentLevel: function($link) { + return $link.html(); + }, + + getCurrentRow: function($link) { + return $($link.parent().parent()); + }, + + changeLogLevel : function(link) { + var $link = $(link); + var level = this.getCurrentLevel($link); + var $tr = this.getCurrentRow($link); + var name = $tr.find('.logname').text(); + var serviceUrl = "/admintool/log4j2/changeLevel/" + name + "/" + level; + if ($tr.hasClass('parent')) { + serviceUrl += "/parent/true"; + } + + this.sendRequest( + {url: serviceUrl, requestType: "POST", dataType: "text", my: this, link: $link}, + function(data, query) { + query.my.changeLogLevelDone(data, query.link); + } + ); + }, + + changeLogLevelDone: function(data, $link) { + if (data == 'true') { + var $levelTd = this.getCurrentRow($link).children('.loglevel'); + var oldlevel = $levelTd.text(); + var level = this.getCurrentLevel($link); + + $levelTd.removeAddClass(this.levelCss[oldlevel], this.levelCss[level]); + $levelTd.text(level); + } else if (data == 'reload') { + location.reload(); + } else { + $('#admintoolError').modal(); + } + }, + + manageLogger: function(link) { + var $lni = getByID('loggerName'); + $lni.val("") + $lni.on({'keyup': $.proxy(this.checkActivation, this)}); + $lni.on({'blur': $.proxy(this.checkActivation, this)}); + + getByID('appenderNames').val(null).trigger("change"); + var $btn = getByID('manageLogger_submit'); + $btn.unbind(); + if(null != link) { + var $link = $(link); + var $tr = this.getCurrentRow($link); + var $td = $tr.find('.logname'); + + $lni.attr('disabled','disabled'); + $lni.val($td.text()); + + getByID('appenderNames').val($td.data('appenders').split(',')).trigger("change"); + + $btn.removeAttr('disabled'); + } else { + $lni.removeAttr('disabled'); + $btn.attr('disabled','disabled'); + } + + $btn.on({'click': $.proxy(this.saveLogger, this)}); + + getByID("manageLoggerModal").modal(); + }, + + checkActivation: function() { + var $lni = getByID('loggerName'); + var $btn = getByID('manageLogger_submit'); + + if ($lni.val().length > 0) { + $btn.removeAttr('disabled'); + } else { + $btn.attr('disabled','disabled'); + } + }, + + saveLogger: function() { + + var data = { + loggerName: getByID('loggerName').val(), + encoding: getByID('encoding').val(), + //recursive: getByID('recursive').prop("checked"), + additivity: getByID('additivity').prop("checked"), + level: getByID('level').val(), + appenderNames: getByID('appenderNames').val() + }; + + this.sendRequest({ + url: "/admintool/log4j2/manageLogger", + requestType: "POST", + dataType: "text", + data: JSON.stringify(data), + showModalOnError: true, + my: this + }, + function(data, query) { + if (data == 'reload') { + location.reload(); + } else { + $('#admintoolError').modal(); + } + }); + } + +}); +$.pluginMaker(AdminTool.Log4j.Loggers); + +/* + * Log4j.Console live html appender + */ +AdminTool.Log4j.Console = function(el, options) { + if (el) { + this.init(el, options) + } +} +AdminTool.Log4j.Console.prototype = new AdminTool.Core(); + +$.extend(AdminTool.Log4j.Console.prototype, { + + name : 'adminToolLog4jConsole', + + postInit: function() { + this.bind(); + this.requestCount = 0; + this.lineCount = 0; + this.maxListLength = 100; + this.initCheckboxes(); + }, + + bind : function() { + this.loggerNames = getByID('loggerNames').select2({ + placeholder: 'Root Logger' + }); + + getByID('startConsole').on({'click': $.proxy(this.startConsole, this)}); + getByClazz('stopConsole').hide(); + getByID('clearConsole').on({'click': $.proxy(this.clearConsole, this)}); + + }, + + unbind : function() { + getByID('loggerNames').unbind(); + getByID('startConsole').unbind(); + getByID('clearConsole').unbind(); + }, + + initCheckboxes: function() { + getByID('recursive').iCheck('destroy'); + getByID('recursive').iCheck({ + checkboxClass: 'icheckbox_minimal', + radioClass: 'iradio_minimal' +// increaseArea: '20%' // optional + }); + getByID('overrideLogLevel').iCheck('destroy'); + getByID('overrideLogLevel').iCheck({ + checkboxClass: 'icheckbox_minimal', + radioClass: 'iradio_minimal' +// increaseArea: '20%' // optional + }); + }, + + startConsole : function() { + + var data = { +// name:getByID('name').val(), + pattern: getByID('pattern').val(), + encoding: getByID('encoding').val(), + recursive: getByID('recursive').prop("checked"), + overrideLogLevel: getByID('overrideLogLevel').prop("checked"), + level: getByID('level').val(), + loggerNames: this.loggerNames.val() + }; + + this.sendRequest({ + url: "/admintool/log4j2/initConsole", + requestType: "POST", + dataType: "text", + data: JSON.stringify(data), + showModalOnError: true, + my: this + }, + function(data, query) { + query.my.consoleStarted(data); + }); + }, + + consoleStarted : function(data) { + var stopButtons = getByClazz('stopConsole'); + stopButtons.on({'click': $.proxy(this.stopConsole, this)}); + stopButtons.show(); + this.startUpdateConsole(); + $.AdminLTE.boxWidget.collapse(getByID('log4jTailConfigCollapse')); + getByID('startConsole').prop('disabled', true); + }, + + startUpdateConsole : function() { + this.intervalId = setInterval(function() { + getByID('log4jTail').adminToolLog4jConsole('updateConsole'); + }, 5000); + }, + + stopUpdateConsole : function() { + clearInterval(this.intervalId); + this.intervalId = null; + getByID('startConsole').prop('disabled', false); + }, + + updateConsole: function() { + this.sendRequest( + {url: "/admintool/log4j2/getConsoleContent", dataType: "text", my: this}, + function(data, query) { + if (null != data && data.trim() != "" && data.trim() != "null") { + var lines = data.trim().split("\n"); + if (lines.length > 0) { + var existingLines = $('#consoleContent span'); + var existingNumbers = $('#lineNumbers span'); + var hasContent = existingLines.length > 0; + var clazz; + for (var i=-1, l=lines.length; ++i < l;) { + var line = lines[i]; + if (line == null || line == undefined || line.trim() == "") { + continue; + } + clazz = query.my.getSpanClass(line) || clazz; + + if (!hasContent) { + getByID('consoleContent').html(query.my.getText(line, clazz)); + getByID('lineNumbers').html(query.my.getText("1", "text-muted")); + query.my.lineCount = 1; + } else { + $('#consoleContent span:last-child').after(query.my.getText(line, clazz)); + query.my.lineCount++ + $('#lineNumbers span:last-child').after(query.my.getText(query.my.lineCount.toString(), "text-muted")); + } + } + + var oversize = lines.length + existingLines.length - query.my.getMaxListLength(); + if (oversize > 0) { + for (var i=-1; ++i < oversize;) { + $(existingLines[i]).remove(); + $(existingNumbers[i]).remove(); + } + } + + if (getByID('scrollToBottom').prop( "checked" )) { + $('html, body').scrollTop(getByID('consoleContent')[0].scrollHeight); + } + } + } + query.my.requestCount++; + getByID('requestCount').text(query.my.requestCount); + } + ); + }, + + getMaxListLength() { + var userMaxLength = parseInt(getByID('maxListLength').val()); + if (isNaN(userMaxLength) || userMaxLength == Infinity) { + return this.maxListLength; + } + return userMaxLength; + }, + + getText: function(line, clazz) { + line = line.replace(//g, '>'); + if (undefined !== clazz) { + return '' + line + ''; + } + return '' + line + ''; + }, + + getSpanClass: function(line) { + var lowerLine = line.toLowerCase(); + if (lowerLine.indexOf(' error ') != -1 || lowerLine.indexOf(' fatal ') != -1) { + return "text-danger"; + } + else if (lowerLine.indexOf(' warn ') != -1) { + return "text-warning"; + } + else if (lowerLine.indexOf(' info ') != -1 || lowerLine.indexOf(' debug ') != -1 || lowerLine.indexOf(' trace ') != -1) { + return "text-info"; + } + else if (lowerLine.indexOf(' off ') != -1) { + return "text-muted"; + } + return undefined; + }, + + stopConsole : function() { + this.stopUpdateConsole(); + this.sendRequest({ + url: "/admintool/log4j2/stopConsole", + dataType: "text", + showModalOnError: true, + my: this + }, + function(data, query) { + query.my.consoleStopped(data); + }); + }, + + consoleStopped : function(data) { + var stopButtons = getByClazz('stopConsole'); + stopButtons.unbind(); + stopButtons.hide(); + }, + + clearConsole : function() { + this.requestCount = 0; + this.lineCount = 0; + getByID('requestCount').text(this.requestCount); + getByID('consoleContent').text(""); + getByID('lineNumbers').text(""); + } + +}); +$.pluginMaker(AdminTool.Log4j.Console); + + +$( document ).ready(function() { + if (getByID('log4jContent').length > 0) { + getByID('log4jContent').adminToolLog4jLoggers(); + } + if (getByID('log4jTail').length > 0) { + getByID('log4jTail').adminToolLog4jConsole(); + } }); \ No newline at end of file diff --git a/admin-tools-log4j2/src/main/resources/templates/admintool/content/log4j2.html b/admin-tools-log4j2/src/main/resources/templates/admintool/content/log4j2.html index 8d36502..7dbe0b2 100644 --- a/admin-tools-log4j2/src/main/resources/templates/admintool/content/log4j2.html +++ b/admin-tools-log4j2/src/main/resources/templates/admintool/content/log4j2.html @@ -1,118 +1,222 @@ - - - -
-
-

- Log4j Console Configuration -

- -
- - -
- -
- -
-

- - - -

- -
-
- -
- - - - - - - - - - - - - - - -
- -
-
-
- - -
- -
- -
-

- - - -

- -
-
- -
- - - - - - - - - - - - - - - -
-
-
- -
-
-
- - -
- -
-
- - - - + + + +
+
+

+ Log4j Console Configuration +

+ +
+ + +
+ +
+ +
+

+ + + +

+ + +
+
+ +
+ + + + + + + + + + + + + + + +
+ + +
+
+
+ + +
+ +
+ +
+

+ + + +

+ +
+
+ +
+ + + + + + + + + + + + + + + +
+
+
+ +
+
+
+ + +
+ + + +
+
+ + + +