Well I tried copying the SMTPAppender code into my own class. It worked
better. Except the ThorwableInformation wasn't available in the
sendBuffer() method.
Anybody know why/how to get this information from the event? Is there a
special way your supposed to log the message on the client side?
Thanks again
----- Original Message -----
From: "Gray Jones" <[EMAIL PROTECTED]>
To: "LOG4J Users Mailing List" <[EMAIL PROTECTED]>
Sent: Thursday, May 31, 2001 10:17 AM
Subject: Re: dynamic subject with smtp appender
> Thanks Jim for the code.
>
> I've been looking at it and am a little confused. In the doPatternSubst()
> method, it looks like it is switching based upon a character. Is this a
> special 'cookie' type character that you are adding to your log message?
> Can you give a little insight as to what is happening here?
>
> Any backgound info would be appreciated.
>
> Thanks,
>
> Gray Jones
>
> ----- Original Message -----
> From: "Jim Moore" <[EMAIL PROTECTED]>
> To: "'LOG4J Users Mailing List'" <[EMAIL PROTECTED]>
> Sent: Wednesday, May 30, 2001 11:16 AM
> Subject: RE: dynamic subject with smtp appender
>
>
> > You can't with what's in the disribution. Here's one I wrote, though.
> Take
> > a look at doPatternSubst.
> >
> > -Jim Moore
> >
> > ===
> >
> > import org.apache.log4j.*;
> > import org.apache.log4j.helpers.*;
> > import org.apache.log4j.spi.*;
> >
> > import java.util.*;
> >
> > import javax.mail.*;
> > import javax.mail.internet.*;
> >
> >
> > /**
> > * Send an e-mail when a specific logging event occurs, typically on
> > 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.
> > */
> > public class SMTPAppender extends AppenderSkeleton {
> > private String to;
> > private String from;
> > private String subject;
> > private String smtpHost;
> > private int bufferSize = 512;
> >
> > private CyclicBuffer _cb;
> > private boolean locationInfo = false;
> >
> > protected TriggeringEventEvaluator evaluator;
> > private Session session;
> >
> >
> > /**
> > * The default constructor will instantiate the appender with a
> > * {@link TriggeringEventEvaluator} that will tirgger on events with
> > * priority ERROR or higher.
> > */
> > public SMTPAppender() {
> > this(new DefaultEvaluator());
> > }
> >
> >
> > /**
> > * Use <code>evaluator</code> passed as parameter as the {@link
> > * TriggeringEventEvaluator} for this SMTPAppender.
> > *
> > * @param evaluator
> > */
> > public SMTPAppender(TriggeringEventEvaluator evaluator) {
> > this.evaluator = evaluator;
> > setCyclicBuffer(new CyclicBuffer(bufferSize));
> > }
> >
> >
> > public void activeOptions() {
> > Properties props = System.getProperties();
> >
> > if (smtpHost != null) {
> > props.put("mail.smtp.host", smtpHost);
> > }
> >
> > session = Session.getDefaultInstance(System.getProperties(), null);
> > // session.setDebug(true);
> >
> > super.activateOptions();
> > }
> >
> >
> > /**
> > * 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.
> > *
> > * @param event
> > */
> > public void append(LoggingEvent event) {
> > if (!checkEntryConditions()) {
> > return;
> > }
> >
> > event.getThreadName();
> > event.getNDC();
> > if (locationInfo) {
> > event.getLocationInformation();
> > }
> > getCyclicBuffer().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.
> > *
> > * @return
> > */
> > protected boolean checkEntryConditions() {
> > 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;
> > }
> >
> >
> > public synchronized void close() {
> > this.closed = true;
> > }
> >
> >
> > protected InternetAddress getAddress(String addressStr) {
> > try {
> > return new InternetAddress(addressStr);
> > }
> > catch (AddressException e) {
> > errorHandler.error("Could not parse address ["+addressStr+"].", e,
> > ErrorCode.ADDRESS_PARSE_FAILURE);
> > return null;
> > }
> > }
> >
> >
> > protected InternetAddress[] parseAddress(String addressStr) {
> > try {
> > return InternetAddress.parse(addressStr, true);
> > }
> > catch (AddressException e) {
> > errorHandler.error("Could not parse address ["+addressStr+"].", e,
> > ErrorCode.ADDRESS_PARSE_FAILURE);
> > return null;
> > }
> > }
> >
> >
> > /**
> > * Returns value of the <b>To</b> option.
> > *
> > * @return
> > */
> > public String getTo() {
> > return to;
> > }
> >
> >
> > /**
> > * The <code>SMTPAppender</code> requires a {@link Layout layout}.
> > *
> > * @return
> > */
> > public boolean requiresLayout() {
> > return true;
> > }
> >
> >
> > /**
> > * Send the contents of the cyclic buffer as an e-mail message.
> > */
> > protected void sendBuffer() {
> > // Note: this code already owns the monitor for this
> > // appender. This frees us from needing to synchronize on 'cb'.
> >
> > try {
> > Message msg = createMessage();
> >
> > try {
> > Transport.send(msg);
> > }
> > catch (MessagingException exp) {
> > LogLog.error("Error occured while sending e-mail notification.",
> > exp);
> > }
> > }
> > catch (MessagingException exp) {
> > // the only thing that could've thrown this is createMessage()
> > LogLog.error("Could not create Message.", exp);
> > }
> > }
> >
> >
> > protected void setMessageFrom(Message msg) throws MessagingException {
> > if (from != null) {
> > msg.setFrom(getAddress(from));
> > }
> > else {
> > msg.setFrom();
> > }
> > }
> >
> >
> > protected void setMessageTo(Message msg) throws MessagingException {
> > msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
> > }
> >
> >
> > protected void setMessageSubject(Message msg) throws
MessagingException
> {
> > if (subject != null) {
> > CyclicBuffer cb = getCyclicBuffer();
> > int length = cb.length();
> >
> > String theSubject;
> > if (length > 0) {
> > theSubject = doPatternSubst(subject, cb.get(length-1));
> > }
> > else {
> > theSubject = subject;
> > }
> >
> > msg.setSubject(theSubject);
> > }
> > else {
> > LogLog.warn("There is no subject set for emails");
> > }
> > }
> >
> >
> > public String doPatternSubst(String source, LoggingEvent evt) {
> > String str = source;
> > StringBuffer sBuf = new StringBuffer();
> >
> > while (true) {
> > int index = str.indexOf('%');
> >
> > if (index < 0 || index == str.length()) {
> > break;
> > }
> >
> > char c = str.charAt(index+1);
> > switch (c) {
> > case 'm':
> > str = appendEventMessage(str, sBuf, index, evt);
> > break;
> > case 's':
> > str = appendExceptionMessage(str, sBuf, index, evt);
> > break;
> > case 'x':
> > str = appendExceptionClassName(str, sBuf, index, evt);
> > break;
> > default:
> > // nothing
> > }
> > }
> >
> > sBuf.append(str);
> >
> > return sBuf.toString();
> > }
> >
> >
> > /**
> > * Appends <tt>str</tt> to <tt>sBuf</tt> through the <tt>index</tt>
> > * and then appends the Throwable class name that's in <tt>evt</tt>.
> > *
> > * @param str the source string
> > *
> > * @param sBuf the StringBuffer to append to
> > *
> > * @param index the index to where the substitution parameter was
> found
> > *
> > * @param evt the LoggingEvent to get the Throwable from
> > *
> > * @return the portion of <tt>str</tt> after the substitution (never
> null)
> > */
> > private static String appendExceptionClassName(String str,
StringBuffer
> > sBuf,
> > int index, LoggingEvent
> > evt) {
> > sBuf.append(str.substring(0, index));
> >
> > ThrowableInformation info = evt.getThrowableInformation();
> >
> > if (info != null) {
> > Throwable throwable = info.getThrowable();
> >
> > if (throwable != null) {
> > sBuf.append(throwable.getClass().getName());
> > }
> > }
> >
> > if (index+2 > str.length()) {
> > return "";
> > }
> >
> > return str.substring(index+2);
> > }
> >
> >
> > /**
> > * Appends <tt>str</tt> to <tt>sBuf</tt> through the <tt>index</tt>
> > * and then appends the Throwable message that's in <tt>evt</tt>.
> > *
> > * @param str the source string
> > *
> > * @param sBuf the StringBuffer to append to
> > *
> > * @param index the index to where the substitution parameter was
> found
> > *
> > * @param evt the LoggingEvent to get the Throwable from
> > *
> > * @return the portion of <tt>str</tt> after the substitution (never
> null)
> > */
> > private static String appendExceptionMessage(String str, StringBuffer
> > sBuf,
> > int index, LoggingEvent
> evt)
> > {
> > sBuf.append(str.substring(0, index));
> >
> > ThrowableInformation info = evt.getThrowableInformation();
> >
> > if (info != null) {
> > Throwable throwable = info.getThrowable();
> >
> > if (throwable != null) {
> > String msg = throwable.getMessage();
> > sBuf.append(msg == null ? "" : msg);
> > }
> > }
> >
> > if (index+2 > str.length()) {
> > return "";
> > }
> >
> > return str.substring(index+2);
> > }
> >
> >
> > /**
> > * Appends <tt>str</tt> to <tt>sBuf</tt> through the <tt>index</tt>
> > * and then appends the message that's in <tt>evt</tt>.
> > *
> > * @param str the source string
> > *
> > * @param sBuf the StringBuffer to append to
> > *
> > * @param index the index to where the substitution parameter was
> found
> > *
> > * @param evt the LoggingEvent to get the message from
> > *
> > * @return the portion of <tt>str</tt> after the substitution (never
> null)
> > */
> > private static String appendEventMessage(String str, StringBuffer
sBuf,
> > int index, LoggingEvent evt)
{
> > sBuf.append(str.substring(0, index));
> >
> > Object msg = evt.getMessage();
> > sBuf.append(msg == null ? "" : msg.toString());
> >
> > if (index+2 > str.length()) {
> > return "";
> > }
> >
> > return str.substring(index+2);
> > }
> >
> >
> > protected void addHeader(StringBuffer sbuf) {
> > String t = layout.getHeader();
> >
> > if (t != null)
> > sbuf.append(t);
> > }
> >
> >
> > protected void addFooter(StringBuffer sbuf) {
> > String t = layout.getFooter();
> >
> > if (t != null)
> > sbuf.append(t);
> > }
> >
> >
> > protected void addLogEvents(StringBuffer sbuf) {
> > CyclicBuffer cb = getCyclicBuffer();
> >
> > int len = cb.length();
> > for (int i = 0; i < len; i++) {
> >
file://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]);
> > }
> > }
> > }
> > }
> > }
> >
> >
> > /**
> > */
> > protected Message createMessage() throws MessagingException {
> > // Note: this code already owns the monitor for this
> > // appender. This frees us from needing to synchronize on 'cb'.
> >
> > MimeMessage msg = new MimeMessage(session);
> >
> > setMessageFrom(msg);
> > setMessageTo(msg);
> > setMessageSubject(msg);
> >
> > StringBuffer sbuf = new StringBuffer();
> >
> > addHeader(sbuf);
> > addLogEvents(sbuf);
> > addFooter(sbuf);
> >
> > MimeBodyPart part = new MimeBodyPart();
> > part.setContent(sbuf.toString(), layout.getContentType());
> >
> > Multipart mp = new MimeMultipart();
> > mp.addBodyPart(part);
> >
> > msg.setContent(mp);
> > msg.setSentDate(new Date());
> >
> > return msg;
> > }
> >
> >
> > /**
> > * Sets the CyclicBuffer this will use for keeping track
> > * of {@link LoggingEvent}s.
> > *
> > * @param cb the CyclicBuffer to store the events in
> > */
> > protected void setCyclicBuffer(CyclicBuffer cb) {
> > _cb = cb;
> > }
> >
> >
> > /**
> > * Returns the CyclicBuffer the {@link LoggingEvent}s are stored in.
> > */
> > protected CyclicBuffer getCyclicBuffer() {
> > return _cb;
> > }
> >
> >
> > /**
> > * Returns value of the <b>EvaluatorClass</b> option.
> > *
> > * @return
> > */
> > public String getEvaluatorClass() {
> > return evaluator == null ? null : evaluator.getClass().getName();
> > }
> >
> >
> > /**
> > * Returns value of the <b>From</b> option.
> > *
> > * @return
> > */
> > public String getFrom() {
> > return from;
> > }
> >
> > /**
> > * Returns value of the <b>Subject</b> option.
> > *
> > * @return
> > */
> > public String getSubject() {
> > return subject;
> > }
> >
> >
> > /**
> > * The <b>From</b> option takes a string value which should be a
> > * e-mail address of the sender.
> > *
> > * @param from
> > */
> > 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.
> > *
> > * @param subject
> > */
> > 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.
> > *
> > * @param bufferSize
> > */
> > public void setBufferSize(int bufferSize) {
> > this.bufferSize = bufferSize;
> > getCyclicBuffer().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.
> > *
> > * @param smtpHost
> > */
> > 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
> > * repsenting 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.
> > *
> > * @param locationInfo
> > */
> > public void setLocationInfo(boolean locationInfo) {
> > this.locationInfo = locationInfo;
> > }
> >
> >
> > /**
> > * Returns value of the <b>LocationInfo</b> option.
> > *
> > * @return
> > */
> > public boolean getLocationInfo() {
> > return locationInfo;
> > }
> >
> >
> > protected static class DefaultEvaluator implements
> > TriggeringEventEvaluator {
> > /**
> > * Is this <code>event</code> the e-mail triggering event?
> > *
> > * <p>This method returns <code>true</code>, if the event priority
> > * has ERROR priority or higher. Otherwisem it returns
> > * <code>false</code>.
> > *
> > * @param event
> > * @return
> > */
> > public boolean isTriggeringEvent(LoggingEvent event) {
> > return event.priority.isGreaterOrEqual(Priority.ERROR);
> > }
> > }
> >
> > }
> >
> >
> >
> > -----Original Message-----
> > From: Gray Jones [mailto:[EMAIL PROTECTED]]
> > Sent: Wednesday, May 30, 2001 11:05 AM
> > To: LOG4J Users Mailing List
> > Subject: dynamic subject with smtp appender
> >
> >
> > Hello,
> >
> > Does anybody know if you can somehow dynamically create the subject
field
> of
> > an smtp log? For instance we are using an smtp appender to send emails
of
> > exceptions to the development group. Our exception class has an id and
> > description field which would be nice to include in the subject field of
> the
> > email message so we can sort, etc.
> >
> > Thanks,
> >
> > Gray Jones
> >
> >
> > ---------------------------------------------------------------------
> > 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]
>
>
> ---------------------------------------------------------------------
> 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]