<commit_before>/*
 * Copyright 1999-2005 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.log4j.net;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.TriggeringEventEvaluator;
import java.util.Properties;
import java.util.Date;

import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.Multipart;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;

/**
   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 <NAME>uml;lc&uuml;
   @since 1.0 */
public class SMTPAppender extends AppenderSkeleton {
  private String to;
  /**
   * Comma separated list of cc recipients.
   */
  private String cc;  
  /**
   * Comma separated list of bcc recipients.
   */
  private String bcc;  
  private String from;
  private String subject;
  private String smtpHost;
  private int bufferSize = 512;
  private boolean locationInfo = false;

  protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
  protected Message msg;

  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() {
    Properties props = new Properties (System.getProperties());
    if (smtpHost != null)
      props.put("mail.smtp.host", smtpHost);


    Session session = Session.getInstance(props, null);
    //session.setDebug(true);
    msg = new MimeMessage(session);

     try {
        addressMessage(msg);
        if(subject != null) {
	       msg.setSubject(subject);
	    }
     } catch(MessagingException e) {
       LogLog.error("Could not activate SMTPAppender options.", e );
     }
  }
  
  /**
   *   Address message.
   *   @param msg message, may not be null.
   *   @throws MessagingException thrown if error addressing message. 
   */
  protected void addressMessage(final Message msg) throws MessagingException {
       if (from != null) {
	 		msg.setFrom(getAddress(from));
       } else {
	 		msg.setFrom();
	   }

       if (to != null && to.length() > 0) {
             msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
       }

      //Add CC receipients if defined.
	  if (cc != null && cc.length() > 0) {
		msg.setRecipients(Message.RecipientType.CC, parseAddress(cc));
	  }

      //Add BCC receipients if defined.
	  if (bcc != null && bcc.length() > 0) {
		msg.setRecipients(Message.RecipientType.BCC, parseAddress(bcc));
	  }
  }

  /**
     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;
  }

  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;
    }
  }

  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.
   */
  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() {

    // Note: this code already owns the monitor for this
    // appender. This frees us from needing to synchronize on 'cb'.
    try {
      MimeBodyPart part = new MimeBodyPart();

      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);
      part.setContent(sbuf.toString(), layout.getContentType());

      Multipart mp = new MimeMultipart();
      mp.addBodyPart(part);
      msg.setContent(mp);

      msg.setSentDate(new Date());
      Transport.send(msg);
    } 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;
  }
  
   /**
      Set the cc recipient addresses.
      @param addresses recipient addresses as comma separated string, may be null.
    */
   public void setCc(final String addresses) {
     this.cc = addresses;
   }

   /**
      Get the cc recipient addresses.
      @return recipient addresses as comma separated string, may be null.
    */
    public String getCc() {
     return cc;
    }

   /**
      Set the bcc recipient addresses.
      @param addresses recipient addresses as comma separated string, may be null.
    */
   public void setBcc(final String addresses) {
     this.bcc = addresses;
   }

   /**
      Get the bcc recipient addresses.
      @return recipient addresses as comma separated string, may be null.
    */
    public String getBcc() {
     return bcc;
    }

  
}

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);
  }
}
<commit_msg>Bug 16922: MDC with SMTPAppender doesn't work<commit_after>/*
 * Copyright 1999-2005 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.log4j.net;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.CyclicBuffer;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.TriggeringEventEvaluator;
import java.util.Properties;
import java.util.Date;

import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.Multipart;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;

/**
   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 <NAME>uml;lc&uuml;
   @since 1.0 */
public class SMTPAppender extends AppenderSkeleton {
  private String to;
  /**
   * Comma separated list of cc recipients.
   */
  private String cc;  
  /**
   * Comma separated list of bcc recipients.
   */
  private String bcc;  
  private String from;
  private String subject;
  private String smtpHost;
  private int bufferSize = 512;
  private boolean locationInfo = false;

  protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
  protected Message msg;

  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() {
    Properties props = new Properties (System.getProperties());
    if (smtpHost != null)
      props.put("mail.smtp.host", smtpHost);


    Session session = Session.getInstance(props, null);
    //session.setDebug(true);
    msg = new MimeMessage(session);

     try {
        addressMessage(msg);
        if(subject != null) {
	       msg.setSubject(subject);
	    }
     } catch(MessagingException e) {
       LogLog.error("Could not activate SMTPAppender options.", e );
     }
  }
  
  /**
   *   Address message.
   *   @param msg message, may not be null.
   *   @throws MessagingException thrown if error addressing message. 
   */
  protected void addressMessage(final Message msg) throws MessagingException {
       if (from != null) {
	 		msg.setFrom(getAddress(from));
       } else {
	 		msg.setFrom();
	   }

       if (to != null && to.length() > 0) {
             msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
       }

      //Add CC receipients if defined.
	  if (cc != null && cc.length() > 0) {
		msg.setRecipients(Message.RecipientType.CC, parseAddress(cc));
	  }

      //Add BCC receipients if defined.
	  if (bcc != null && bcc.length() > 0) {
		msg.setRecipients(Message.RecipientType.BCC, parseAddress(bcc));
	  }
  }

  /**
     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();
    event.getMDCCopy();
    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;
  }

  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;
    }
  }

  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.
   */
  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() {

    // Note: this code already owns the monitor for this
    // appender. This frees us from needing to synchronize on 'cb'.
    try {
      MimeBodyPart part = new MimeBodyPart();

      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);
      part.setContent(sbuf.toString(), layout.getContentType());

      Multipart mp = new MimeMultipart();
      mp.addBodyPart(part);
      msg.setContent(mp);

      msg.setSentDate(new Date());
      Transport.send(msg);
    } 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;
  }
  
   /**
      Set the cc recipient addresses.
      @param addresses recipient addresses as comma separated string, may be null.
    */
   public void setCc(final String addresses) {
     this.cc = addresses;
   }

   /**
      Get the cc recipient addresses.
      @return recipient addresses as comma separated string, may be null.
    */
    public String getCc() {
     return cc;
    }

   /**
      Set the bcc recipient addresses.
      @param addresses recipient addresses as comma separated string, may be null.
    */
   public void setBcc(final String addresses) {
     this.bcc = addresses;
   }

   /**
      Get the bcc recipient addresses.
      @return recipient addresses as comma separated string, may be null.
    */
    public String getBcc() {
     return bcc;
    }

  
}

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);
  }
}

{'fraction_non_alphanumeric': 0.10017385545161023, 'fraction_numerical': 0.0031045616358970113, 'mean_word_length': 2.818397344713134, 'pattern_counts': {'":': 0, '<': 113, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1880413', 'n_tokens_mistral': 7407, 'n_tokens_neox': 7126, 'n_words': 2289}