PDA

View Full Version : Change to Log Levels dynamically via JMX



krishoma
Aug 11th, 2006, 12:40 PM
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.

wims.tijd
Aug 11th, 2006, 01:03 PM
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) ;
}

}

krishoma
Aug 11th, 2006, 01:18 PM
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.

dgynn
Aug 11th, 2006, 03:03 PM
I don't have a JMX solution, but here is a single-page JSP approach. Save this file as log4j.jsp.


<%@ 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>

wims.tijd
Aug 12th, 2006, 01:40 PM
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();
}

krishoma
Aug 14th, 2006, 03:28 PM
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.

krishoma
Aug 15th, 2006, 03:28 PM
Are there any limitations with this approach? does this work in appiications deployed across different nodes in a cluster.

Thanks,
Kris

Costin Leau
Aug 16th, 2006, 05:03 AM
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).

krishoma
Aug 21st, 2006, 02:59 PM
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

Costin Leau
Aug 28th, 2006, 12:09 AM
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.