Author: leif Date: Fri Jul 30 00:46:30 2004 New Revision: 30969 Modified: avalon/trunk/runtime/index.xml avalon/trunk/runtime/logkit/src/java/org/apache/log/output/net/SMTPOutputLogTarget.java Log: Modify the SMTPOutputLogTarget so it is not possible to have it send batched groups of log events in a single message. This was possible before, but the message would never be sent until a predetermined number of messages had arrived. These changes make it possible to set a timeout where the message will be sent if no more log events are received within a specified time period. In other words, it is great at keeping groups of messages together while at the same time making sure they are delivered in a timely fashion.
Modified: avalon/trunk/runtime/index.xml ============================================================================== --- avalon/trunk/runtime/index.xml (original) +++ avalon/trunk/runtime/index.xml Fri Jul 30 00:46:30 2004 @@ -63,7 +63,7 @@ <info> <group>avalon/logkit</group> <name>avalon-logkit</name> - <version>2.0.0</version> + <version>2.0.1</version> </info> <dependencies> <include key="mailapi" runtime="false"/> Modified: avalon/trunk/runtime/logkit/src/java/org/apache/log/output/net/SMTPOutputLogTarget.java ============================================================================== --- avalon/trunk/runtime/logkit/src/java/org/apache/log/output/net/SMTPOutputLogTarget.java (original) +++ avalon/trunk/runtime/logkit/src/java/org/apache/log/output/net/SMTPOutputLogTarget.java Fri Jul 30 00:46:30 2004 @@ -35,29 +35,43 @@ */ public class SMTPOutputLogTarget extends AbstractOutputTarget { - // Mail session + /** Mail session. */ private final Session m_session; - // Message to be sent + /** Message to be sent. */ private Message m_message; - // Address to sent mail to + /** Address to sent mail to. */ private final Address[] m_toAddresses; - // Address to mail is to be listed as sent from + /** Address to mail is to be listed as sent from. */ private final Address m_fromAddress; - // Mail subject + /** Mail subject. */ private final String m_subject; - // Current size of mail, in units of log events + /** Current size of mail, in units of log events. */ private int m_msgSize; - // Maximum size of mail, in units of log events + /** Maximum size of mail, in units of log events. */ private final int m_maxMsgSize; - // Buffer containing current mail + /** Buffer containing current mail. */ private StringBuffer m_buffer; + + /** The time that the first log entry in the current buffer arrived. */ + private long m_bufferTime; + + /** The maximun delay that a message will be allowed to wait in the queue + * before being sent. */ + private long m_maxDelayTime; + + /** Runner thread which is responsible for sending batched log entries in + * the background. */ + private Thread m_runner; + + /** Flag which will be set in the close method when it is time to shutdown. */ + private boolean m_shutdown; /** SMTPOutputLogTarget constructor. * @@ -68,7 +82,17 @@ * @param toAddresses addresses logs should be sent to * @param fromAddress address logs say they come from * @param subject subject line logs should use - * @param maxMsgSize maximum size of any log mail, in units of log events + * @param maxMsgSize maximum size of any log mail, in units of log events. + * If this is greater than one but maxDelayTime is 0 then + * log events may stay queued for a long period of time + * if less than the specified number of messages are + * logged. Any unset messages will be sent when the + * target is closed. + * @param maxDelayTime specifies the longest delay in seconds that a log + * entry will be queued before being sent. Setting + * this to a value larger than 0 will cause a + * background thread to be used to queue up and send + * messages. Ignored if maxMsgSize is 1 or less. * @param formatter log formatter to use */ public SMTPOutputLogTarget( @@ -77,6 +101,7 @@ final Address fromAddress, final String subject, final int maxMsgSize, + final int maxDelayTime, final Formatter formatter ) { super( formatter ); @@ -87,11 +112,103 @@ m_fromAddress = fromAddress; m_subject = subject; m_session = session; + m_maxDelayTime = maxDelayTime * 1000; + + if ( ( m_maxDelayTime > 0 ) && ( m_maxMsgSize > 1 ) ) + { + // Create a runner thread which will + m_runner = new Thread( "SMTPOutputLogTarget_Queue_Daemon" ) + { + public void run() + { + try + { + //System.out.println( "SMTPOutputLogTarget runner Started." ); + synchronized( SMTPOutputLogTarget.this ) + { + try + { + do + { + // Wait up to a second for notification that a message is + // available. + try + { + SMTPOutputLogTarget.this.wait( 1000 ); + } + catch ( InterruptedException e ) + { + // Ignore. + } + + // Is a message waiting? + if ( m_message != null ) + { + // Is the message big enough to send or been + // waiting long enough? + long now = System.currentTimeMillis(); + if ( m_shutdown || ( m_msgSize >= m_maxMsgSize ) || + ( now - m_bufferTime >= m_maxDelayTime ) ) + { + // Time to send the message. + send(); + } + } + } + while ( !m_shutdown ); + } + finally + { + //System.out.println( "SMTPOutputLogTarget runner Completed." ); + m_runner = null; + + // The close method waits for this to complete. + SMTPOutputLogTarget.this.notifyAll(); + } + } + } + catch ( Throwable t ) + { + getErrorHandler().error( + "Unexpected error in the SMTPOutputLogTarget queue daemon", t, null ); + } + } + }; + m_runner.setDaemon( true ); + m_runner.start(); + } // ready for business open(); } + /** SMTPOutputLogTarget constructor. + * + * It creates a logkit output target capable of logging to SMTP + * (ie. email, email gateway) targets. + * + * @param session mail session to be used + * @param toAddresses addresses logs should be sent to + * @param fromAddress address logs say they come from + * @param subject subject line logs should use + * @param maxMsgSize maximum size of any log mail, in units of log events. + * Log events may stay queued for a long period of time + * if less than the specified number of messages are + * logged. Any unset messages will be sent when the + * target is closed. + * @param formatter log formatter to use + */ + public SMTPOutputLogTarget( + final Session session, + final Address[] toAddresses, + final Address fromAddress, + final String subject, + final int maxMsgSize, + final Formatter formatter ) + { + this( session, toAddresses, fromAddress, subject, maxMsgSize, 0, formatter ); + } + /** Method to write data to the log target. * * Logging data is stored in @@ -101,36 +218,52 @@ * * @param data logging data to be written to target */ - protected void write( final String data ) + protected synchronized void write( final String data ) { - try + // If this is the first log entry then start a new Message. + if ( m_message == null ) { - // ensure we have a message object available - if( m_message == null ) + try { m_message = new MimeMessage( m_session ); m_message.setFrom( m_fromAddress ); m_message.setRecipients( Message.RecipientType.TO, m_toAddresses ); m_message.setSubject( m_subject ); m_message.setSentDate( new Date() ); - m_msgSize = 0; - m_buffer = new StringBuffer(); } + catch( MessagingException e ) + { + getErrorHandler().error( "Error creating message", e, null ); + } + + m_buffer = new StringBuffer(); + m_bufferTime = System.currentTimeMillis(); + m_msgSize = 0; + } + + // Add the new log entry to the buffer. + m_buffer.append( data ); + if ( !data.endsWith( "\n" ) ) + { + m_buffer.append( "\n" ); + } + m_msgSize++; + + // Decide what to do with the message. + if ( m_runner == null ) + { + // Messages are sent in line. - // add the data to the buffer, separated by a newline - m_buffer.append( data ); - m_buffer.append( '\n' ); - ++m_msgSize; - - // send mail if message size has reached it's size limit - if( m_msgSize >= m_maxMsgSize ) + // Send mail if message size has reached it's size limit + if ( m_msgSize >= m_maxMsgSize ) { send(); } } - catch( MessagingException e ) + else { - getErrorHandler().error( "Error creating message", e, null ); + // Messages are sent by the runner thread. + notifyAll(); } } @@ -140,8 +273,36 @@ */ public synchronized void close() { + //System.out.println( "SMTPOutputLogTarget close Started." ); + super.close(); - send(); + + if ( m_runner == null ) + { + // Log Events are being handled in line. + send(); + } + else + { + // Log Events are being handled by a background thread. Signal it + // and then wait for it to complete. + m_shutdown = true; + notifyAll(); + + while ( m_runner != null ) + { + try + { + wait(); + } + catch ( InterruptedException e ) + { + // Ignore. + } + } + } + + //System.out.println( "SMTPOutputLogTarget close Completed." ); } /** @@ -157,6 +318,8 @@ /** * Helper method to send the currently buffered message, * if existing. + * <p> + * Only called when synchronized. */ private void send() { --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]