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]

Reply via email to