Attachment didn't seem to work - here's the source... sorry, I can't generate a patch because I can't access the log4j cvs & don't have the original source here.
/* * Copyright 1999,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.log4j.servlet; import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.SingleThreadModel; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * A servlet used to dynamically adjust package logging levels * while an application is running. NOTE: This servlet is * only aware of pre-configured packages and packages that contain objects * that have logged at least one message since application startup. * <br> * In order to use this servlet, you should define and map it * in your web application's deployment descriptor (web.xml file). * For example, add the following (if you're looking at the source * code for this file, rather than the JavaDoc, omit the HTML tags): * <br> * <pre> * <servlet><br> * <servlet-name>Log4jAdminServlet</servlet-name><br> * <servlet-class>org.apache.log4j.servlet.ConfigurationServlet</servlet-class<br> * </servlet><br> * <br> * <servlet-mapping><br> * <servlet-name>Log4jAdminServlet</servlet-name><br> * <url-pattern>/Log4jAdmin</url-pattern><br> * </servlet-mapping><br> * <br> * This servlet will then be accessible via * http://yourhost:yourport/yourwebapp/Log4jAdmin * * @author <a href="mailto:[EMAIL PROTECTED]">Luther E. Birdzell</a> * @author Yoav Shapira <[EMAIL PROTECTED]> * @since 1.3 */ public class ConfigurationServlet extends HttpServlet implements SingleThreadModel { /** * The response content type: text/html */ private static final String CONTENT_TYPE = "text/html"; /** * The root appender. */ private static final String ROOT = "root"; /** * The name of the class / package. */ private static final String CLASS = "CLASS"; /** * The logging level. */ private static final String LEVEL = "LEVEL"; /** * Print the status of all current <code>Logger</code>s and * an option to change their respective logging levels. * * @param request a <code>HttpServletRequest</code> value * @param response a <code>HttpServletResponse</code> value * @exception ServletException if an error occurs * @exception IOException if an error occurs */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); List loggers = getSortedLoggers(); Logger logger = null; String loggerName = null; int loggerNum = 0; // print title and header printHeader(out, request); out.println("<table width=\"90%\" border=\"1\">"); out.println("<FORM action=\"" + request.getRequestURI() + "\" method=\"post\">"); out.println("<tr BGCOLOR=\"#5991A6\">"); out.println( "<td><FONT COLOR=\"BLACK\" FACE=\"Helvetica\"><B>Class</B></FONT></td>"); out.print( "<td><FONT COLOR=\"BLACK\" FACE=\"Helvetica\"><B>Level</B></FONT>"); out.println("</td>"); out.print( "<td><FONT COLOR=\"BLACK\" FACE=\"Helvetica\"><B>Change Level</B></FONT>"); out.println("</td>"); out.println("</tr>"); // print the root Logger displayLogger(out, Logger.getRootLogger(), loggerNum++, request); // print the rest of the loggers Iterator ii = loggers.iterator(); while (ii.hasNext()) { displayLogger(out, (Logger) ii.next(), loggerNum++, request); } out.println("</table>"); out.println( "<FONT SIZE=\"-3\" COLOR=\"BLACK\" FACE=\"Helvetica\">* " + "Inherits LEVEL From Parent.</FONT><BR>"); out.println("<A href=\"" + request.getRequestURI() + "\">Refresh</A><HR>"); // print set options out.println( "<input type=\"submit\" name=\"Submit\" value=\"Save changes\"></FONT>"); out.println("</FORM>"); out.println("</body></html>"); out.flush(); out.close(); } /** * Change a <code>Logger</code>'s level, then call <code>doGet</code> * to refresh the page. * * @param request a <code>HttpServletRequest</code> value * @param response a <code>HttpServletResponse</code> value * @exception ServletException if an error occurs * @exception IOException if an error occurs */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List loggers = getSortedLoggers(); Logger logger = null; String loggerName = null; String newLevel = null; // deal with root logger first newLevel = request.getParameter(ROOT); setClass(ROOT,Level.toLevel(newLevel)); Iterator ii = loggers.iterator(); while (ii.hasNext()) { logger = (Logger) ii.next(); loggerName = logger.getName(); newLevel = (request.getParameter(loggerName)); //System.out.println(loggerName + ": newLevel = " + newLevel); if ( logger.getLevel() == null && (newLevel == null || newLevel.equals("INHERITED")) || logger.getLevel() != null && logger.getLevel() == Level.toLevel(newLevel)) { // level unchanged - do nothing } else { System.out.println("updating " + loggerName + " to " + newLevel); if (newLevel.equals("INHERITED")) { setClass(loggerName,null); } else { setClass(loggerName,Level.toLevel(newLevel)); } } } doGet(request, response); } /** Print a Logger and its current level. @param out the output writer. @param logger the logger to output. @param row the row number in the table this logger will appear in. @param request the servlet request. */ private void displayLogger( PrintWriter out, Logger logger, int row, HttpServletRequest request) { String color = null; String loggerName = (logger.getName().equals("root") ? ROOT : logger.getName()); color = ((row % 2) == 1) ? "#E1E1E1" : "#FBFBFB"; out.println("<tr BGCOLOR=\"" + color + "\">"); out.println( "<td><FONT SIZE=\"-2\" COLOR=\"BLACK\" FACE=\"Helvetica\">" + loggerName + "</FONT></td>"); out.println( "<td><FONT SIZE=\"-2\" COLOR=\"BLACK\" FACE=\"Helvetica\">" + ((logger.getLevel() == null) ? (logger.getEffectiveLevel().toString() + "*") : logger.getLevel().toString()) + "</FONT></td>"); out.println( "<td><FONT SIZE=\"-2\" COLOR=\"BLACK\" FACE=\"Helvetica\">"); if (logger.getLevel() == null) { out.println("<input type=radio name="+loggerName+" value=INHERITED checked>*INHERITED "); out.println("<input type=radio name="+loggerName+" value=DEBUG>DEBUG "); out.println("<input type=radio name="+loggerName+" value=INFO>INFO "); out.println("<input type=radio name="+loggerName+" value=WARN>WARN "); out.println("<input type=radio name="+loggerName+" value=ERROR>ERROR "); out.println("<input type=radio name="+loggerName+" value=FATAL>FATAL "); out.println("<input type=radio name="+loggerName+" value=OFF>OFF "); } else { if (!loggerName.equals(ROOT)) out.println("<input type=radio name="+loggerName+" value=INHERITED>*INHERITED "); out.println("<input type=radio name="+loggerName+" value=DEBUG " + ((logger.getLevel().equals(Level.toLevel("DEBUG"))) ? " checked " : "") + ">DEBUG "); out.println("<input type=radio name="+loggerName+" value=INFO " + ((logger.getLevel().equals(Level.toLevel("INFO"))) ? " checked " : "") + ">INFO "); out.println("<input type=radio name="+loggerName+" value=WARN " + ((logger.getLevel().equals(Level.toLevel("WARN"))) ? " checked " : "") + ">WARN "); out.println("<input type=radio name="+loggerName+" value=ERROR " + ((logger.getLevel().equals(Level.toLevel("ERROR"))) ? " checked " : "") + ">ERROR "); out.println("<input type=radio name="+loggerName+" value=FATAL " + ((logger.getLevel().equals(Level.toLevel("FATAL"))) ? " checked " : "") + ">FATAL "); out.println("<input type=radio name="+loggerName+" value=OFF " + ((logger.getLevel().equals(Level.toLevel("OFF"))) ? " checked " : "") + ">OFF "); } out.println("</td></tr>"); } /** Set a logger's level. @param className class name of the logger to set. @param level the level to set the logger to. @return String return message for display. */ private synchronized String setClass(String className, Level level) { Logger logger = null; String message = null; try { logger = (className.equals(ROOT)) ? Logger.getRootLogger() : Logger.getLogger(className); logger.setLevel(level); } catch (Exception e) { System.out.println("ERROR Setting LOG4J Logger:" + e); } return "Message Set For " + (logger.getName().equals("root") ? ROOT : logger.getName()); } /** Get a sorted list of all current loggers. @return List the list of sorted loggers. */ private List getSortedLoggers() { Logger logger = null; Enumeration enum = LogManager.getCurrentLoggers(); Comparator comp = new LoggerComparator(); List list = new ArrayList(); // Add all current loggers to the list while (enum.hasMoreElements()) { list.add(enum.nextElement()); } // sort the loggers Collections.sort(list, comp); return list; } /** * Prints the page header. * * @param out The output writer * @param request The request */ private void printHeader(PrintWriter out, HttpServletRequest request) { out.println( "<html><head><title>Log4J Control Console</title></head>" + "<body><H3>Log4J Control Console</H3>"); out.println("<A href=\"" + request.getRequestURI() + "\">Refresh</A><HR>"); } /** * Prints the Level select HTML. * * @param out The output writer */ private void printLevelSelector(PrintWriter out) { out.println( "<tr BGCOLOR=\"#5991A6\"><td><FONT COLOR=\"BLACK\" " + "FACE=\"Helvetica\"><B>Level:</B></FONT></td>"); out.println("<td><SELECT name=\"" + LEVEL + "\">"); out.println( "<OPTION VALUE=\"" + Level.OFF + "\">" + Level.OFF + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.FATAL + "\">" + Level.FATAL + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.ERROR + "\">" + Level.ERROR + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.WARN + "\">" + Level.WARN + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.INFO + "\">" + Level.INFO + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.DEBUG + "\">" + Level.DEBUG + "</OPTION>"); out.println( "<OPTION VALUE=\"" + Level.ALL + "\">" + Level.ALL + "</OPTION>"); out.println("</SELECT><BR></td></tr>"); } /** * Compare the names of two <code>Logger</code>s. Used * for sorting. */ private class LoggerComparator implements Comparator { /** * Compare the names of two <code>Logger</code>s. * * @param o1 an <code>Object</code> value * @param o2 an <code>Object</code> value * @return an <code>int</code> value */ public int compare(Object o1, Object o2) { Logger logger1 = (Logger) o1; Logger logger2 = (Logger) o2; ; String logger1Name = null; String logger2Name = null; if (logger1 != null) { logger1Name = (logger1.getName().equals("root") ? ROOT : logger1.getName()); } if (logger2 != null) { logger2Name = (logger2.getName().equals("root") ? ROOT : logger2.getName()); } return logger1Name.compareTo(logger2Name); } /** * Return <code>true</code> if the <code>Object</code> is a * <code>LoggerComparator</code> instance. * * * @param o an <code>Object</code> value * @return a <code>boolean</code> value */ public boolean equals(Object o) { return (o instanceof LoggerComparator); } /** * Returns the parent's hashcode. * * @return int The hashcode value */ public int hashCode() { return super.hashCode(); } } } //EOF "Stephen Pain" <stephen.pain+exter To: "Log4J Users List" <[EMAIL PROTECTED]> [EMAIL PROTECTED]> cc: Subject: Re: generating log4j.xml 20/08/2004 13:26 Please respond to "Log4J Users List" This reminds me, I made changes to the Log4jAdmin page that I didn't get round to making public yet - I replaced the dropdown box with a set of radio boxes next to each logger, making it much easier (I think) to update the configuration. I also added an "INHERITED" level (just sets the threshold back to null). There's a small bug - if you try to set the level to INHERITED when it's specifically defined to be something else in the log4j.properties file, it won't work - instead, you have to change to something else (eg change from DEBUG -> WARN), hit apply, then try again with the inherited, and second time round it works. I have an idea of where the problem is but haven't had time to fix it yet. I'll attach the source, in case anyone's interested. (See attached file: ConfigurationServlet.java) Cheers, Stephen Nathan Coast <[EMAIL PROTECTED] To: Log4J Users List <[EMAIL PROTECTED]> com> cc: Subject: Re: generating log4j.xml 20/08/2004 13:01 Please respond to "Log4J Users List" I'm about to push out a new version of the Log4J admin web app. With the webapp, you can modify the in-memory configuration but once you reboot, you're back to where you started from. I'd like to add a feature to write the modifications back to the config file. To do this I'll need something to generate a config file from the current runtime configuration. Shapira, Yoav wrote: > Hi, > I'm not that gung-ho about configuration-file-generation tools. We've > had some bitter experiences in the Tomcat area related to this. The > problem is that the code tends to develop faster than the > configuration-file-generation tool and so the configuration file > generator outputs either incomplete or invalid configuration files (at > worst), or just doesn't expose all the functionality of the code (which > is not that bad a scenario). > > If someone wants to develop and maintain it, good for them. I'm not > sure it belongs in the log4j core, at least initially. If it stands the > test of tiem (as a contrib module perhaps, or a sandbox one), and gets > significant usage, then maybe. > > Yoav Shapira > Millennium Research Informatics > > > >>-----Original Message----- >>From: Paul Smith [mailto:[EMAIL PROTECTED] >>Sent: Tuesday, August 17, 2004 11:42 PM >>To: 'Log4J Users List' >>Subject: RE: generating log4j.xml >> >> >>>I'd be glad to volunteer as I need it for the project I'm working on. >>>My concern is that any xml generator would become obsolete with log4j >>>1.3. From the docs, I see that 1.3 xml configuration is achieved > > using > >>>something called the joran configurator >>>http://www.qos.ch/logging/JoranConfigurator.html >>> >>>would it make more sense to develop something like a > > JoranConfigWriter? > >>Well, you could call it that, but the reading and configuring is done > > by > >>JoranConfigurator, but one could think that once a LoggerRepository is >>configured, it's configuration could be output in any form (properties, >>XML, >>whatever). If we have a class that walks the LoggerRepository loggers, >>appenders, and plugins, and outputs the configuration file in some > > format > >>(obviously XML in the format JoranConfigurator can read would be the > > most > >>useful first version) that would be perfect. >>It should be straightforward from a Junit point of view too. Given an > > XML > >>configuration file, use JoranConfigurator to configure, then use >>NathansCoolConfigWriter to write the xml file back out, and then > > compare > >>the >>2 xml files together for success/failure. >> >> >>>I know this has probably been asked a thousand times.... how far off > > is > >>>1.3? a week, a month, a year? >> >>echo "how far off is 1.3?" > /dev/idontknow/ >>cheers, >>Paul Smith >> >> >>--------------------------------------------------------------------- >>To unsubscribe, e-mail: [EMAIL PROTECTED] >>For additional commands, e-mail: [EMAIL PROTECTED] > > > > > > This e-mail, including any attachments, is a confidential business communication, > and may contain information that is confidential, proprietary and/or privileged. > This e-mail is intended only for the individual(s) to whom it is addressed, and may > not be saved, copied, printed, disclosed or used by anyone else. If you are not > the(an) intended recipient, please immediately delete this e-mail from your computer > system and notify the sender. Thank you. > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and destroy this e-mail. Any unauthorized copying, disclosure or distribution of the material in this e-mail is strictly forbidden. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and destroy this e-mail. Any unauthorized copying, disclosure or distribution of the material in this e-mail is strictly forbidden. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]