|
From: <fg...@us...> - 2008-03-11 15:56:24
|
Revision: 734
http://openutils.svn.sourceforge.net/openutils/?rev=734&view=rev
Author: fgiust
Date: 2008-03-11 08:56:29 -0700 (Tue, 11 Mar 2008)
Log Message:
-----------
[maven-release-plugin] copy for tag openutils-log4j-2.0.1
Added Paths:
-----------
tags/openutils-log4j-2.0.1/
tags/openutils-log4j-2.0.1/pom.xml
tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java
Removed Paths:
-------------
tags/openutils-log4j-2.0.1/pom.xml
tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java
Copied: tags/openutils-log4j-2.0.1 (from rev 731, trunk/openutils-log4j)
Deleted: tags/openutils-log4j-2.0.1/pom.xml
===================================================================
--- trunk/openutils-log4j/pom.xml 2008-03-11 15:24:20 UTC (rev 731)
+++ tags/openutils-log4j-2.0.1/pom.xml 2008-03-11 15:56:29 UTC (rev 734)
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>net.sourceforge.openutils</groupId>
- <artifactId>openutils</artifactId>
- <version>7</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>openutils-log4j</artifactId>
- <packaging>jar</packaging>
- <version>2.0.1-SNAPSHOT</version>
- <name>openutils for Log4j</name>
- <description>openutils log4j extensions</description>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.3</version>
- </dependency>
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4</version>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.4</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.0</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-</project>
Copied: tags/openutils-log4j-2.0.1/pom.xml (from rev 733, trunk/openutils-log4j/pom.xml)
===================================================================
--- tags/openutils-log4j-2.0.1/pom.xml (rev 0)
+++ tags/openutils-log4j-2.0.1/pom.xml 2008-03-11 15:56:29 UTC (rev 734)
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>net.sourceforge.openutils</groupId>
+ <artifactId>openutils</artifactId>
+ <version>7</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <artifactId>openutils-log4j</artifactId>
+ <packaging>jar</packaging>
+ <version>2.0.1</version>
+ <name>openutils for Log4j</name>
+ <description>openutils log4j extensions</description>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <scm>
+ <connection>scm:svn:https://openutils.svn.sourceforge.net/svnroot/openutils/tags/openutils-log4j-2.0.1</connection>
+ <developerConnection>scm:svn:https://openutils.svn.sourceforge.net/svnroot/openutils/tags/openutils-log4j-2.0.1</developerConnection>
+ <url>http://openutils.svn.sourceforge.net/viewcvs.cgi/openutils/tags/openutils-log4j-2.0.1</url>
+ </scm>
+</project>
Deleted: tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java
===================================================================
--- trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java 2008-03-11 15:24:20 UTC (rev 731)
+++ tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java 2008-03-11 15:56:29 UTC (rev 734)
@@ -1,685 +0,0 @@
-/*
- * Copyright Openmind http://www.openmindonline.it
- *
- * 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 it.openutils.log4j;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimeUtility;
-
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Level;
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.helpers.OptionConverter;
-import org.apache.log4j.spi.ErrorCode;
-import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.spi.TriggeringEventEvaluator;
-
-
-/**
- * An alternative of <code>org.apache.log4j.net.SMTPAppender</code> with few differences:
- * <ul>
- * <li>allow customizing the mail subject using a pattern</li>
- * <li>can be configured with a timeout (in seconds), it will only send messages after this timeout</li>
- * <li>it will send a mail for every single message (bufferSize is not supported), but it will aggregate any identical
- * log event received during the timeout. Identical events are log with same message and same stack trace</li>
- * </ul>
- *
- * <pre>
- * <appender name="mail" class="it.openutils.log4j.AlternateSMTPAppender">
- * <param name="Threshold" value="ERROR" />
- * <param name="To" value="lo...@ex..." />
- * <param name="From" value="in...@ex..." />
- * <param name="SMTPHost" value="localhost" />
- * <param name="Timeout" value="180" />
- * <param name="Subject" value="[EXAMPLE] %m" />
- * <layout class="it.openutils.log4j.FilteredPatternLayout">
- * <param name="ConversionPattern" value="%-5p %c %d{dd.MM.yyyy HH:mm:ss} -- %m%n" />
- * <param name="Header"
- * value="
- * ===================================
- * Myapp (production environment)
- * Date: %d{dd.MM.yyyy HH:mm:ss}
- * ===================================
- * " />
- * </layout>
- * </appender>
- * </pre>
- *
- * @author Fabrizio Giustina
- * @version $Id: $
- */
-public class AlternateSMTPAppender extends AppenderSkeleton
-{
-
- private String to;
-
- private String from;
-
- private Layout subjectLayout;
-
- private String smtpHost;
-
- private boolean locationInfo;
-
- private Timer timer = new Timer("log4j mail appender", true);
-
- private TimerTask timerTask;
-
- private int timeout;
-
- protected Map<LoggingEventAggregator, LoggingEventAggregator> events = new LinkedHashMap<LoggingEventAggregator, LoggingEventAggregator>()
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public LoggingEventAggregator put(LoggingEventAggregator key, LoggingEventAggregator value)
- {
- LoggingEventAggregator lea = this.get(key);
- if (lea != null)
- {
- lea.incrementCount();
- return lea;
- }
-
- return super.put(key, value);
- }
-
- };
-
- 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 AlternateSMTPAppender()
- {
- this(new DefaultEvaluator());
-
- // force loading this class
- MimeBodyPart.class.getName();
- MimeUtility.class.getName();
- }
-
- /**
- * Use <code>evaluator</code> passed as parameter as the {@link TriggeringEventEvaluator} for this SMTPAppender.
- */
- public AlternateSMTPAppender(TriggeringEventEvaluator evaluator)
- {
- this.evaluator = evaluator;
- }
-
- /**
- * Activate the specified options, such as the smtp host, the recipient, from, etc.
- */
- @Override
- 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
- {
- if (from != null)
- {
- msg.setFrom(getAddress(from));
- }
- else
- {
- msg.setFrom();
- }
-
- msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
- }
- catch (MessagingException e)
- {
- LogLog.error("Could not activate SMTPAppender options.", e);
- }
- }
-
- /**
- * 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.
- */
- @Override
- public void append(LoggingEvent event)
- {
-
- if (!checkEntryConditions())
- {
- return;
- }
-
- event.getThreadName();
- event.getNDC();
- if (locationInfo)
- {
- event.getLocationInformation();
- }
-
- LoggingEventAggregator leg = new LoggingEventAggregator(event);
-
- if (evaluator.isTriggeringEvent(event))
- {
- if (timeout == 0)
- {
- // send immediately
- synchronized (events)
- {
- Collection<LoggingEventAggregator> le = new ArrayList<LoggingEventAggregator>();
- le.add(leg);
- sendBuffer(le);
- }
- return;
- }
- else
- {
- events.put(leg, leg);
-
- if (timerTask == null)
-
- {
-
- timerTask = new TimerTask()
- {
-
- @Override
- public void run()
- {
- Collection<LoggingEventAggregator> le;
- synchronized (events)
- {
- le = new ArrayList<LoggingEventAggregator>(events.values());
- events.clear();
- timerTask = null;
- }
-
- sendBuffer(le);
- }
- };
-
- this.timer.schedule(this.timerTask, this.timeout * 1000L);
-
- }
- }
- }
- }
-
- /**
- * 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;
- }
-
- @Override
- public synchronized 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}.
- */
- @Override
- public boolean requiresLayout()
- {
- return true;
- }
-
- /**
- * Send the contents of the cyclic buffer as an e-mail message.
- */
- protected void sendBuffer(Collection<LoggingEventAggregator> eventsCollection)
- {
-
- // Note: this code already owns the monitor for this
- // appender. This frees us from needing to synchronize on 'cb'.
- try
- {
-
- for (LoggingEventAggregator lea : eventsCollection)
- {
- MimeBodyPart part = new MimeBodyPart();
-
- StringBuffer sbuf = new StringBuffer();
- String t = layout.getHeader();
- if (t != null)
- {
- t = StringUtils.replace(t, "%o", Integer.toString(lea.getCount()));
- t = StringUtils.replace(t, "%n", Layout.LINE_SEP);
- sbuf.append(t);
- sbuf.append("\n");
- }
-
- LoggingEvent event = lea.getLoggingEvent();
-
- if (this.subjectLayout != null)
- {
- String subject = this.subjectLayout.format(event);
-
- if (subject != null)
- {
- subject = subject.trim();
- if (subject.indexOf("\n") > 0)
- {
- subject = subject.substring(0, subject.indexOf("\n"));
- }
- }
-
- this.msg.setSubject(subject);
- }
-
- sbuf.append(layout.format(event));
- if (layout.ignoresThrowable())
- {
- String[] s = event.getThrowableStrRep();
- if (s != null)
- {
- for (String element : s)
- {
- sbuf.append(element);
- }
- }
- }
- t = layout.getFooter();
- if (t != null)
- {
- t = StringUtils.replace(t, "%n", Layout.LINE_SEP);
- 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 subjectLayout.toString();
- }
-
- /**
- * 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 subjectPattern)
- {
- this.subjectLayout = new PatternLayout(subjectPattern);
- }
-
- /**
- * This option is ignored!
- */
- @Deprecated
- public void setBufferSize(int bufferSize)
- {
- // kept as deprecated
- LogLog.warn("BufferSize property is deprecated for " + getClass().getName());
- }
-
- /**
- * 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 0;
- }
-
- /**
- * 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);
- }
-
- /**
- * @param value
- */
- public void setEvaluator(TriggeringEventEvaluator value)
- {
- evaluator = value;
- }
-
- /**
- * 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;
- }
-
- /**
- * Returns the timeout.
- * @return the timeout
- */
- public int getTimeout()
- {
- return timeout;
- }
-
- /**
- * Sets the timeout.
- * @param timeout the timeout to set
- */
- public void setTimeout(int timeout)
- {
- this.timeout = timeout;
- }
-}
-
-
-class LoggingEventAggregator
-{
-
- private LoggingEvent loggingEvent;
-
- private int count;
-
- public LoggingEventAggregator(LoggingEvent loggingEvent)
- {
- this.loggingEvent = loggingEvent;
- this.count = 1;
- }
-
- /**
- * Returns the loggingEvent.
- * @return the loggingEvent
- */
- public LoggingEvent getLoggingEvent()
- {
- return loggingEvent;
- }
-
- /**
- * Returns the count.
- * @return the count
- */
- public int getCount()
- {
- return count;
- }
-
- /**
- * Sets the count.
- * @param count the count to set
- */
- public void setCount(int count)
- {
- this.count = count;
- }
-
- public void incrementCount()
- {
- count++;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
-
- Object lem = loggingEvent.getMessage();
- String[] thstr = loggingEvent.getThrowableStrRep();
- result = prime * result + ((lem == null) ? 0 : lem.hashCode());
- result = prime * result + Arrays.hashCode(thstr);
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (getClass() != obj.getClass())
- {
- return false;
- }
- final LoggingEventAggregator other = (LoggingEventAggregator) obj;
-
- Object lem = loggingEvent.getMessage();
- String[] thstr = loggingEvent.getThrowableStrRep();
-
- Object otherLem = other.loggingEvent.getMessage();
- String[] otherThstr = other.loggingEvent.getThrowableStrRep();
-
- int length = Math.min(otherThstr.length, thstr.length);
- length = Math.min(10, length);
-
- otherThstr = (String[]) ArrayUtils.subarray(otherThstr, 0, length);
- String[] thisThstr = (String[]) ArrayUtils.subarray(thstr, 0, length);
-
- if (lem == null)
- {
- if (otherLem != null)
- {
- return false;
- }
- }
-
- else if (!lem.equals(otherLem))
- {
- return false;
- }
- if (!Arrays.equals(thisThstr, otherThstr))
- {
- return false;
- }
- return true;
- }
-
-}
-
-
-class DefaultEvaluator implements TriggeringEventEvaluator
-{
-
- public boolean isTriggeringEvent(LoggingEvent event)
- {
- return event.getLevel().isGreaterOrEqual(Level.ERROR);
- }
-}
\ No newline at end of file
Copied: tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java (from rev 732, trunk/openutils-log4j/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java)
===================================================================
--- tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java (rev 0)
+++ tags/openutils-log4j-2.0.1/src/main/java/it/openutils/log4j/AlternateSMTPAppender.java 2008-03-11 15:56:29 UTC (rev 734)
@@ -0,0 +1,685 @@
+/*
+ * Copyright Openmind http://www.openmindonline.it
+ *
+ * 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 it.openutils.log4j;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Level;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.ErrorCode;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.TriggeringEventEvaluator;
+
+
+/**
+ * An alternative of <code>org.apache.log4j.net.SMTPAppender</code> with few differences:
+ * <ul>
+ * <li>allow customizing the mail subject using a pattern</li>
+ * <li>can be configured with a timeout (in seconds), it will only send messages after this timeout</li>
+ * <li>it will send a mail for every single message (bufferSize is not supported), but it will aggregate any identical
+ * log event received during the timeout. Identical events are log with same message and same stack trace</li>
+ * </ul>
+ *
+ * <pre>
+ * <appender name="mail" class="it.openutils.log4j.AlternateSMTPAppender">
+ * <param name="Threshold" value="ERROR" />
+ * <param name="To" value="lo...@ex..." />
+ * <param name="From" value="in...@ex..." />
+ * <param name="SMTPHost" value="localhost" />
+ * <param name="Timeout" value="180" />
+ * <param name="Subject" value="[EXAMPLE] %m" />
+ * <layout class="it.openutils.log4j.FilteredPatternLayout">
+ * <param name="ConversionPattern" value="%-5p %c %d{dd.MM.yyyy HH:mm:ss} -- %m%n" />
+ * <param name="Header"
+ * value="
+ * ===================================
+ * Myapp (production environment)
+ * Date: %d{dd.MM.yyyy HH:mm:ss}
+ * ===================================
+ * " />
+ * </layout>
+ * </appender>
+ * </pre>
+ *
+ * @author Fabrizio Giustina
+ * @version $Id$
+ */
+public class AlternateSMTPAppender extends AppenderSkeleton
+{
+
+ protected Map<LoggingEventAggregator, LoggingEventAggregator> events = new LinkedHashMap<LoggingEventAggregator, LoggingEventAggregator>()
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public LoggingEventAggregator put(LoggingEventAggregator key, LoggingEventAggregator value)
+ {
+ LoggingEventAggregator lea = this.get(key);
+ if (lea != null)
+ {
+ lea.incrementCount();
+ return lea;
+ }
+
+ return super.put(key, value);
+ }
+
+ };
+
+ protected Message msg;
+
+ protected TriggeringEventEvaluator evaluator;
+
+ private String to;
+
+ private String from;
+
+ private Layout subjectLayout;
+
+ private String smtpHost;
+
+ private boolean locationInfo;
+
+ private Timer timer = new Timer("log4j mail appender", true);
+
+ private TimerTask timerTask;
+
+ private int timeout;
+
+ /**
+ * The default constructor will instantiate the appender with a {@link TriggeringEventEvaluator} that will trigger
+ * on events with level ERROR or higher.
+ */
+ public AlternateSMTPAppender()
+ {
+ this(new DefaultEvaluator());
+
+ // force loading this class
+ MimeBodyPart.class.getName();
+ MimeUtility.class.getName();
+ }
+
+ /**
+ * Use <code>evaluator</code> passed as parameter as the {@link TriggeringEventEvaluator} for this SMTPAppender.
+ */
+ public AlternateSMTPAppender(TriggeringEventEvaluator evaluator)
+ {
+ this.evaluator = evaluator;
+ }
+
+ /**
+ * Activate the specified options, such as the smtp host, the recipient, from, etc.
+ */
+ @Override
+ 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
+ {
+ if (from != null)
+ {
+ msg.setFrom(getAddress(from));
+ }
+ else
+ {
+ msg.setFrom();
+ }
+
+ msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
+ }
+ catch (MessagingException e)
+ {
+ LogLog.error("Could not activate SMTPAppender options.", e);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ @Override
+ public void append(LoggingEvent event)
+ {
+
+ if (!checkEntryConditions())
+ {
+ return;
+ }
+
+ event.getThreadName();
+ event.getNDC();
+ if (locationInfo)
+ {
+ event.getLocationInformation();
+ }
+
+ LoggingEventAggregator leg = new LoggingEventAggregator(event);
+
+ if (evaluator.isTriggeringEvent(event))
+ {
+ if (timeout == 0)
+ {
+ // send immediately
+ synchronized (events)
+ {
+ Collection<LoggingEventAggregator> le = new ArrayList<LoggingEventAggregator>();
+ le.add(leg);
+ sendBuffer(le);
+ }
+ return;
+ }
+ else
+ {
+ events.put(leg, leg);
+
+ if (timerTask == null)
+
+ {
+
+ timerTask = new TimerTask()
+ {
+
+ @Override
+ public void run()
+ {
+ Collection<LoggingEventAggregator> le;
+ synchronized (events)
+ {
+ le = new ArrayList<LoggingEventAggregator>(events.values());
+ events.clear();
+ timerTask = null;
+ }
+
+ sendBuffer(le);
+ }
+ };
+
+ this.timer.schedule(this.timerTask, this.timeout * 1000L);
+
+ }
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ @Override
+ public synchronized 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}.
+ */
+ @Override
+ public boolean requiresLayout()
+ {
+ return true;
+ }
+
+ /**
+ * Send the contents of the cyclic buffer as an e-mail message.
+ */
+ protected void sendBuffer(Collection<LoggingEventAggregator> eventsCollection)
+ {
+
+ // Note: this code already owns the monitor for this
+ // appender. This frees us from needing to synchronize on 'cb'.
+ try
+ {
+
+ for (LoggingEventAggregator lea : eventsCollection)
+ {
+ MimeBodyPart part = new MimeBodyPart();
+
+ StringBuffer sbuf = new StringBuffer();
+ String t = layout.getHeader();
+ if (t != null)
+ {
+ t = StringUtils.replace(t, "%o", Integer.toString(lea.getCount()));
+ t = StringUtils.replace(t, "%n", Layout.LINE_SEP);
+ sbuf.append(t);
+ sbuf.append("\n");
+ }
+
+ LoggingEvent event = lea.getLoggingEvent();
+
+ if (this.subjectLayout != null)
+ {
+ String subject = this.subjectLayout.format(event);
+
+ if (subject != null)
+ {
+ subject = subject.trim();
+ if (subject.indexOf("\n") > 0)
+ {
+ subject = subject.substring(0, subject.indexOf("\n"));
+ }
+ }
+
+ this.msg.setSubject(subject);
+ }
+
+ sbuf.append(layout.format(event));
+ if (layout.ignoresThrowable())
+ {
+ String[] s = event.getThrowableStrRep();
+ if (s != null)
+ {
+ for (String element : s)
+ {
+ sbuf.append(element);
+ }
+ }
+ }
+ t = layout.getFooter();
+ if (t != null)
+ {
+ t = StringUtils.replace(t, "%n", Layout.LINE_SEP);
+ 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 subjectLayout.toString();
+ }
+
+ /**
+ * 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 subjectPattern)
+ {
+ this.subjectLayout = new PatternLayout(subjectPattern);
+ }
+
+ /**
+ * This option is ignored!
+ */
+ @Deprecated
+ public void setBufferSize(int bufferSize)
+ {
+ // kept as deprecated
+ LogLog.warn("BufferSize property is deprecated for " + getClass().getName());
+ }
+
+ /**
+ * 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 0;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * @param value
+ */
+ public void setEvaluator(TriggeringEventEvaluator value)
+ {
+ evaluator = value;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns the timeout.
+ * @return the timeout
+ */
+ public int getTimeout()
+ {
+ return timeout;
+ }
+
+ /**
+ * Sets the timeout.
+ * @param timeout the timeout to set
+ */
+ public void setTimeout(int timeout)
+ {
+ this.timeout = timeout;
+ }
+}
+
+
+class LoggingEventAggregator
+{
+
+ private LoggingEvent loggingEvent;
+
+ private int count;
+
+ public LoggingEventAggregator(LoggingEvent loggingEvent)
+ {
+ this.loggingEvent = loggingEvent;
+ this.count = 1;
+ }
+
+ /**
+ * Returns the loggingEvent.
+ * @return the loggingEvent
+ */
+ public LoggingEvent getLoggingEvent()
+ {
+ return loggingEvent;
+ }
+
+ /**
+ * Returns the count.
+ * @return the count
+ */
+ public int getCount()
+ {
+ return count;
+ }
+
+ /**
+ * Sets the count.
+ * @param count the count to set
+ */
+ public void setCount(int count)
+ {
+ this.count = count;
+ }
+
+ public void incrementCount()
+ {
+ count++;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+
+ Object lem = loggingEvent.getMessage();
+ String[] thstr = loggingEvent.getThrowableStrRep();
+ result = prime * result + ((lem == null) ? 0 : lem.hashCode());
+ result = prime * result + Arrays.hashCode(thstr);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ final LoggingEventAggregator other = (LoggingEventAggregator) obj;
+
+ Object lem = loggingEvent.getMessage();
+ String[] thstr = loggingEvent.getThrowableStrRep();
+
+ Object otherLem = other.loggingEvent.getMessage();
+ String[] otherThstr = other.loggingEvent.getThrowableStrRep();
+
+ int length = Math.min(otherThstr.length, thstr.length);
+ length = Math.min(10, length);
+
+ otherThstr = (String[]) ArrayUtils.subarray(otherThstr, 0, length);
+ String[] thisThstr = (String[]) ArrayUtils.subarray(thstr, 0, length);
+
+ if (lem == null)
+ {
+ if (otherLem != null)
+ {
+ return false;
+ }
+ }
+
+ else if (!lem.equals(otherLem))
+ {
+ return false;
+ }
+ if (!Arrays.equals(thisThstr, otherThstr))
+ {
+ return false;
+ }
+ return true;
+ }
+
+}
+
+
+class DefaultEvaluator implements TriggeringEventEvaluator
+{
+
+ public boolean isTriggeringEvent(LoggingEvent event)
+ {
+ return event.getLevel().isGreaterOrEqual(Level.ERROR);
+ }
+}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|