Announcement Announcement Module
Collapse
No announcement yet.
Change to Log Levels dynamically via JMX Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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.

  • #2
    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) ;
    }

    }

    Comment


    • #3
      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
      <beans>
      <bean id=loggingMBean class=com.toa.Log4jMBean/>
      <bean id=exporter class=org.springframework.jmx.export.MBeanExporter >
      <property name=beans>
      <map>
      <entry key=bean:name=appllogging value-ref=loggingMBean/>
      </map>
      </property>
      </bean>
      </beans>

      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.

      Comment


      • #4
        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"%>
        <html>
        <head><title>Dynamic Log4J Control</title></head>
        <body>
        <h1>Dynamic Log4J Control</h1>
        <%  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));
            } 
        %>
        <c:set var="rootLogger" value="<%= Logger.getRootLogger() %>"/>
        <form>
        <table border="1">
        <tr><th>Level</th><th>Logger</th><th>Set New Level</th></tr>
        <tr><td>${rootLogger.level}</td><td>${rootLogger.name}</td><td>
            <c:forTokens var="level" delims="," items="DEBUG,INFO,WARN,ERROR,OFF">
                <a href="log4j.jsp?log=&level=${level}">${level}</a>
            </c:forTokens>
        </td></tr>
        <c:forEach var="logger" items="${rootLogger.loggerRepository.currentLoggers}">
            <c:if test="${!empty logger.level.syslogEquivalent || param.showAll}">
                <tr><td>${logger.level}</td><td>${logger.name}</td><td>
                <c:forTokens var="level" delims="," items="DEBUG,INFO,WARN,ERROR,OFF">
                    <a href="log4j.jsp?log=${logger.name}&level=${level}">${level}</a>
                </c:forTokens>
                </td></tr>
            </c:if>
        </c:forEach>
        <tr><td></td><td><input type="text" name="log"/></td><td>
        <select name="level">
            <c:forTokens var="level" delims="," items="DEBUG,INFO,WARN,ERROR,OFF">
                <option>${level}</option>
            </c:forTokens>
        </select> <input type="submit" value="Add New Logger"/></td></tr>
        </table>
        </form>
        Show <a href="log4j.jsp?showAll=true">all known loggers</a>
        </body>
        </html>

        Comment


        • #5
          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("<ul type=square>");
          Enumeration loggers = LogManager.getCurrentLoggers();
          Logger logger;
          while(loggers.hasMoreElements()){
          logger = (Logger) loggers.nextElement();
          html.append("<li>"+logger.getName()+"<dd>"+logger. getEffectiveLevel()+"</dd></li>");
          }
          return html.append("</ul>").toString();
          }

          Comment


          • #6
            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("<ul type=square>");
            Enumeration loggers = LogManager.getCurrentLoggers();
            Logger logger;
            while(loggers.hasMoreElements()){
            logger = (Logger) loggers.nextElement();
            html.append("<li>"+logger.getName()+"<dd>"+logger. getEffectiveLevel()+"</dd></li>");
            }
            return html.append("</ul>").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.

            Comment


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

              Thanks,
              Kris

              Comment


              • #8
                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).

                Comment


                • #9
                  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

                  Comment


                  • #10
                    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.

                    Comment

                    Working...
                    X