Como melhorar as mensagens logadas pelo Log4J?

Pessoal,
Eu tenho o stack trace

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/Agencia].[action] [2007-02-28 09:30:12,529] ERROR - Servlet.service() for servlet action threw exception javax.servlet.ServletException: A URL do menu é inválida at br.com.xxxx.agencia.controle.AutorizacaoFilter.doFilter(AutorizacaoFilter.java:127)
O log4j só está registrando via JDBCAppender a mensagem

O que não ajuda em nada a identificar o erro. E até pode ser descartado.

Gostaria de saber se há como tratar melhor as mensagens que vão para o banco de dados?

Obrigado

Você tem que brincar o o log4j.properties e formatar a mensagem da forma que deseja.

Aqui alguns tutoriais:
http://www.mobilefish.com/developer/log4j/log4j_quickguide_layouts.html
http://www.vipan.com/htdocs/log4jhelp.html

Obrigado Lipe.

Eu adotei uma solução diferente.
Criei uma classe estendendo JDBCAppender e sobreescrevi o metodo getLogStatement(LoggingEvent evt)
através do parametro evt eu consigo todas as informações para serem postas na mensagem.

[code]protected String getLogStatement(LoggingEvent arg0) {
String[] throwableStrRep = arg0.getThrowableStrRep();
String mensagem = arg0.getMessage() + " \n ";

	if (throwableStrRep != null)
		for (int i = 0; i < throwableStrRep.length; i++) {
			mensagem += throwableStrRep[i] + "\n";
		}

	String sql = "{call ROBERTO.PROC_LOG('" + mensagem + "')}";
	return sql;
}[/code]

Também gostaria de postar minha sugestão com log4j.
Fiz uma alteração no smtpAppender que aceita autenticação do Ceki Gulcu.

package br.com.drogaraia.recweb.service.util;

import java.util.Date;

import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;

/**
 * Send an e-mail when a specific logging event occurs, typically on errors or
 * fatal errors.
 * 
 * <p>
 * The number of logging events delivered in this e-mail depend on the value of
 * <b>BufferSize</b> option. The <code>SMTPAppender</code> keeps only the
 * last <code>BufferSize</code> logging events in its cyclic buffer. This
 * keeps memory requirements at a reasonable level while still delivering useful
 * application context.
 * 
 * @author Ceki G&uuml;lc&uuml;
 * @since 1.0
 */
public class SMTPAppender extends AppenderSkeleton {
	
	private String to;
	
	private String cc;

	private String from;

	private String subject;

	private String smtpHost;
	
	private int bufferSize = 512;

	private boolean locationInfo = false;
	
	private String user;
	
	private String password;
	
	private String mustAuthentication;

	protected CyclicBuffer cb = new CyclicBuffer(bufferSize);

//	protected Message msg;
	private MultiPartEmail email = new MultiPartEmail();

	protected TriggeringEventEvaluator evaluator;

	/**
	 * The default constructor will instantiate the appender with a
	 * {@link TriggeringEventEvaluator} that will trigger on events with level
	 * ERROR or higher.
	 */
	public SMTPAppender() {
		this(new DefaultEvaluator());
	}

	/**
	 * Use <code>evaluator</code> passed as parameter as the {@link
	 * TriggeringEventEvaluator} for this SMTPAppender.
	 */
	public SMTPAppender(TriggeringEventEvaluator evaluator) {
		this.evaluator = evaluator;
	}

	/**
	 * Activate the specified options, such as the smtp host, the recipient,
	 * from, etc.
	 */
	public void activateOptions() {
		email.setCharset(Email.ISO_8859_1);
		if (smtpHost != null){
			email.setHostName(smtpHost);
		}
		if (needAuthentication()){
			email.setAuthentication(user, password);
		}
				
		try {
			if (from != null){
				email.setFrom(from);
			}
			else{
				email.setFrom("algum@lugar.com.br");
			}
			email.addTo(to);
			if (cc != null)	{
				email.addTo(cc);	
			}
			
			if (subject != null){
				email.setSubject(subject);
			} else {
				email.setSubject("Qual é o seu problema?");
			}
		} catch (EmailException e) {
			LogLog.error("Could not activate SMTPAppender options.", e);
		}
	}

	private boolean needAuthentication() {
		if (mustAuthentication != null){
			String upperCase = mustAuthentication.toUpperCase();
			return upperCase.equals("TRUE");
		}
		return false;
	}

	/**
	 * Perform SMTPAppender specific appending actions, mainly adding the event
	 * to a cyclic buffer and checking if the event triggers an e-mail to be
	 * sent.
	 */
	public void append(LoggingEvent event) {

		if (!checkEntryConditions()) {
			return;
		}

		event.getThreadName();
		event.getNDC();
		if (locationInfo) {
			event.getLocationInformation();
		}
		cb.add(event);
		if (evaluator.isTriggeringEvent(event)) {
			sendBuffer();
		}
	}

	/**
	 * This method determines if there is a sense in attempting to append.
	 * 
	 * <p>
	 * It checks whether there is a set output target and also if there is a set
	 * layout. If these checks fail, then the boolean value <code>false</code>
	 * is returned.
	 */
	protected boolean checkEntryConditions() {
/*		if (this.msg == null) {
			errorHandler.error("Message object not configured.");
			return false;
		}*/

		if (this.evaluator == null) {
			errorHandler.error("No TriggeringEventEvaluator is set for appender [" + name + "].");
			return false;
		}

		if (this.layout == null) {
			errorHandler.error("No layout set for appender named [" + name + "].");
			return false;
		}
		return true;
	}

	synchronized public void close() {
		this.closed = true;
	}

	/**
	 * Returns value of the <b>To</b> option.
	 */
	public String getTo() {
		return to;
	}

	/**
	 * The <code>SMTPAppender</code> requires a {@link org.apache.log4j.Layout
	 * layout}.
	 */
	public boolean requiresLayout() {
		return true;
	}

	/**
	 * Send the contents of the cyclic buffer as an e-mail message.
	 */
	protected void sendBuffer() {

		try {

			StringBuffer sbuf = new StringBuffer();
			String t = layout.getHeader();
			if (t != null)
				sbuf.append(t);
			int len = cb.length();
			for (int i = 0; i < len; i++) {
				// sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
				LoggingEvent event = cb.get();
				sbuf.append(layout.format(event));
				if (layout.ignoresThrowable()) {
					String[] s = event.getThrowableStrRep();
					if (s != null) {
						for (int j = 0; j < s.length; j++) {
							sbuf.append(s[j]);
						}
					}
				}
			}
			t = layout.getFooter();
			if (t != null)
				sbuf.append(t);

			email.setSentDate(new Date());
			email.setMsg(sbuf.toString());
			
			email.buildMimeMessage();
			//msg.setSentDate(new Date());
			email.send();
		} catch (Exception e) {
			LogLog.error("Error occured while sending e-mail notification.", e);
		}
	}

	/**
	 * Returns value of the <b>EvaluatorClass</b> option.
	 */
	public String getEvaluatorClass() {
		return evaluator == null ? null : evaluator.getClass().getName();
	}

	/**
	 * Returns value of the <b>From</b> option.
	 */
	public String getFrom() {
		return from;
	}

	/**
	 * Returns value of the <b>Subject</b> option.
	 */
	public String getSubject() {
		return subject;
	}

	/**
	 * The <b>From</b> option takes a string value which should be a e-mail
	 * address of the sender.
	 */
	public void setFrom(String from) {
		this.from = from;
	}

	/**
	 * The <b>Subject</b> option takes a string value which should be a the
	 * subject of the e-mail message.
	 */
	public void setSubject(String subject) {
		this.subject = subject;
	}

	/**
	 * The <b>BufferSize</b> option takes a positive integer representing the
	 * maximum number of logging events to collect in a cyclic buffer. When the
	 * <code>BufferSize</code> is reached, oldest events are deleted as new
	 * events are added to the buffer. By default the size of the cyclic buffer
	 * is 512 events.
	 */
	public void setBufferSize(int bufferSize) {
		this.bufferSize = bufferSize;
		cb.resize(bufferSize);
	}

	/**
	 * The <b>SMTPHost</b> option takes a string value which should be a the
	 * host name of the SMTP server that will send the e-mail message.
	 */
	public void setSMTPHost(String smtpHost) {
		this.smtpHost = smtpHost;
	}

	/**
	 * Returns value of the <b>SMTPHost</b> option.
	 */
	public String getSMTPHost() {
		return smtpHost;
	}

	/**
	 * The <b>To</b> option takes a string value which should be a comma
	 * separated list of e-mail address of the recipients.
	 */
	public void setTo(String to) {
		this.to = to;
	}

	/**
	 * Returns value of the <b>BufferSize</b> option.
	 */
	public int getBufferSize() {
		return bufferSize;
	}

	/**
	 * The <b>EvaluatorClass</b> option takes a string value representing the
	 * name of the class implementing the {@link TriggeringEventEvaluator}
	 * interface. A corresponding object will be instantiated and assigned as
	 * the triggering event evaluator for the SMTPAppender.
	 */
	public void setEvaluatorClass(String value) {
		evaluator = (TriggeringEventEvaluator) OptionConverter.instantiateByClassName(value,
				TriggeringEventEvaluator.class, evaluator);
	}

	/**
	 * The <b>LocationInfo</b> option takes a boolean value. By default, it is
	 * set to false which means there will be no effort to extract the location
	 * information related to the event. As a result, the layout that formats
	 * the events as they are sent out in an e-mail is likely to place the wrong
	 * location information (if present in the format).
	 * 
	 * <p>
	 * Location information extraction is comparatively very slow and should be
	 * avoided unless performance is not a concern.
	 */
	public void setLocationInfo(boolean locationInfo) {
		this.locationInfo = locationInfo;
	}

	/**
	 * Returns value of the <b>LocationInfo</b> option.
	 */
	public boolean getLocationInfo() {
		return locationInfo;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getMustAuthentication() {
		return mustAuthentication;
	}

	public void setMustAuthentication(String mustAuthentication) {
		this.mustAuthentication = mustAuthentication;
	}

	public String getCc() {
		return cc;
	}

	public void setCc(String cc) {
		this.cc = cc;
	}
}

class DefaultEvaluator implements TriggeringEventEvaluator {
	/**
	 * Is this <code>event</code> the e-mail triggering event?
	 * 
	 * <p>
	 * This method returns <code>true</code>, if the event level has ERROR
	 * level or higher. Otherwise it returns <code>false</code>.
	 */
	public boolean isTriggeringEvent(LoggingEvent event) {
		return event.getLevel().isGreaterOrEqual(Level.ERROR);
	}
}