Wednesday, October 23, 2013

  • Change to Log Levels dynamically via JMX

    Hi,

    I have a requirement where in I have to change the log levels dynamically at runtime. It is not possible for me to modify the log4j.properties or log4j.xml as my application is deployed as an .ear file.
    I am sure there could be some solution for this, I was thinking of JMX but not sure how. I appreciate if anyone help me in this regard and if possible explain with sample code.

    TechStack: Weblogic9.1, Apache log4j, Spring Framework, J2EE, hibernate etc

    Thanks
    Kris.
  • export the bean below to jmx
    i did try this (jboss), but didn't have the time
    since the change did not affect the log immedially

    public class Log4jConfig {

    public void enableInfo(String target){
    LogManager.getLogger(target).setLevel(Level.INFO);
    }

    public void enableWarn(String target){
    LogManager.getLogger(target).setLevel(Level.WARN);
    }

    public void enableError(String target){
    LogManager.getLogger(target).setLevel(Level.ERROR) ;
    }

    public void enableDebug(String target){
    LogManager.getLogger(target).setLevel(Level.DEBUG) ;
    }

    }
  • I did tried this option by following the below steps

    a. Create the management bean similar to what you posted
    b. Export the bean in the application context








    c. then I tried to run the applicaton in weblogic 9.1 by using following java system property
    Dcom.sun.management.jmxremote

    d. Ran JConsole to view mbeans and was able to see my applogging bean with all the methods but when I try to invoke them it has no impact on log levels of application. Still I see application reacts the way it is defined in log4j.xml file.

    Is this approach correct, if yes what is that I am missing here, Can we totally eliminate the need of log4j.xml.
    Do we need to pass anything for target parameter in the method of your example from jmx console.

    Thanks,
    Kris.
  • I don't have a JMX solution, but here is a single-page JSP approach. Save this file as log4j.jsp.
    Code:
    <%@ page import="org.apache.log4j.*" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
    Dynamic Log4J Control
    
    

    Dynamic Log4J Control

    <% String logName=request.getParameter("log"); if (null!=logName) { Logger log=("".equals(logName) ? Logger.getRootLogger() : Logger.getLogger(logName)); log.setLevel(Level.toLevel(request.getParameter("level"),Level.DEBUG)); } %>
    LevelLoggerSet New Level
    ${rootLogger.level}${rootLogger.name} ${level}
    ${logger.level}${logger.name} ${level}
    Show all known loggers
  • you need the pass the package name as target

    (com.toa,org.springframework)

    you see the result when you define a quartz job which logs
    every invocation as info and change the log level to error

    you do not need to pass full package name

    add this method to you logbean to see the changes

    public String list(){
    StringBuffer html = new StringBuffer("
      ");
      Enumeration loggers = LogManager.getCurrentLoggers();
      Logger logger;
      while(loggers.hasMoreElements()){
      logger = (Logger) loggers.nextElement();
      html.append("
    • "+logger.getName()+"
      "+logger. getEffectiveLevel()+"
    • ");
      }
      return html.append("
    ").toString();
    }
  • Originally posted by wims.tijd
    you need the pass the package name as target

    (com.toa,org.springframework)

    you see the result when you define a quartz job which logs
    every invocation as info and change the log level to error

    you do not need to pass full package name

    add this method to you logbean to see the changes

    public String list(){
    StringBuffer html = new StringBuffer("
      ");
      Enumeration loggers = LogManager.getCurrentLoggers();
      Logger logger;
      while(loggers.hasMoreElements()){
      logger = (Logger) loggers.nextElement();
      html.append("
    • "+logger.getName()+"
      "+logger. getEffectiveLevel()+"
    • ");
      }
      return html.append("
    ").toString();
    }
    Hi,

    Thanks a lot, it worked I appreciate your timely help.
    Please let me know if there any limitations with this approach.

    Thanks,
    Kris.
  • Are there any limitations with this approach? does this work in appiications deployed across different nodes in a cluster.

    Thanks,
    Kris
  • Depends on your application server JMX implementation - if the calls are spread across the rest of the JMX servers, then yes.
    Check your cluster configuration - note that with JMX one can create hierarchical servers (for example using jManage).
  • we have our application deployed on weblogic 9.1 on three nodes in a cluster and we are trying to achieve dynamic changes to log levels during runtime with no code or property file changes. In this scenario I was trying to understand whether this approach (JMX implementation for log4j) works with impact.

    Thanks,
    Kris
  • The JMX specs do not cover clustering or federation (grouping a set of JMX servers into one group so calls on the group are propagated to each individual server which in turn, can have other sub groups). This feature along with others are covered, AFAIK, by the next JMX iteration.
    That's why, at the moment, you'll have to rely on other tools or libraries to provide this functionality for you.

No comments: