Well I kinda figured out what was happening.  It didn't work out for me.  I
was experiencing two problems.  First my exception class was never available
from the evt.getThrowableInformation() method.  That method always returned
null.

Second, the message kept wanting to be sent to localhost port 25.  Even
though I had set the smtpHost variable to something different.

Anyway I think i'll go a different route and use jms instead of log4j.

But it might be helpful to make it easier to allow such a thing in future
versions.  Here was an idea that came to mind.  Have the SMTPAppender expose
a hook method that subclasses can override.  Something like
getDynamicMessageSubject(LoggingEvent event);  The default implementation
could just return an empty string

This way I could subclass SMTPAppender and override that one method to
produce the subject I want.  This would assume that the ThowableInformation
was available.

Similar strategies could be used for the to and from fields too.

----- 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]

Reply via email to