View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  
18  package org.apache.logging.log4j.core.appender;
19  
20  import java.io.Serializable;
21  
22  import org.apache.logging.log4j.core.Appender;
23  import org.apache.logging.log4j.core.Core;
24  import org.apache.logging.log4j.core.Filter;
25  import org.apache.logging.log4j.core.Layout;
26  import org.apache.logging.log4j.core.LogEvent;
27  import org.apache.logging.log4j.core.config.Configuration;
28  import org.apache.logging.log4j.core.config.DefaultConfiguration;
29  import org.apache.logging.log4j.core.config.Property;
30  import org.apache.logging.log4j.core.config.plugins.Plugin;
31  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
32  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
33  import org.apache.logging.log4j.core.config.plugins.PluginElement;
34  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
35  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
36  import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
37  import org.apache.logging.log4j.core.filter.ThresholdFilter;
38  import org.apache.logging.log4j.core.layout.HtmlLayout;
39  import org.apache.logging.log4j.core.net.SmtpManager;
40  import org.apache.logging.log4j.core.util.Booleans;
41  
42  /**
43   * Send an e-mail when a specific logging event occurs, typically on errors or
44   * fatal errors.
45   *
46   * <p>
47   * The number of logging events delivered in this e-mail depend on the value of
48   * <b>BufferSize</b> option. The <code>SmtpAppender</code> keeps only the last
49   * <code>BufferSize</code> logging events in its cyclic buffer. This keeps
50   * memory requirements at a reasonable level while still delivering useful
51   * application context.
52   *
53   * By default, an email message will formatted as HTML. This can be modified by
54   * setting a layout for the appender.
55   *
56   * By default, an email message will be sent when an ERROR or higher severity
57   * message is appended. This can be modified by setting a filter for the
58   * appender.
59   */
60  @Plugin(name = "SMTP", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
61  public final class SmtpAppender extends AbstractAppender {
62  
63      private static final int DEFAULT_BUFFER_SIZE = 512;
64  
65      /** The SMTP Manager */
66      private final SmtpManager manager;
67  
68      private SmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
69              final SmtpManager manager, final boolean ignoreExceptions, final Property[] properties) {
70          super(name, filter, layout, ignoreExceptions, properties);
71          this.manager = manager;
72      }
73  
74      /**
75       * Create a SmtpAppender.
76       *
77       * @param name
78       *            The name of the Appender.
79       * @param to
80       *            The comma-separated list of recipient email addresses.
81       * @param cc
82       *            The comma-separated list of CC email addresses.
83       * @param bcc
84       *            The comma-separated list of BCC email addresses.
85       * @param from
86       *            The email address of the sender.
87       * @param replyTo
88       *            The comma-separated list of reply-to email addresses.
89       * @param subject The subject of the email message.
90       * @param smtpProtocol The SMTP transport protocol (such as "smtps", defaults to "smtp").
91       * @param smtpHost
92       *            The SMTP hostname to send to.
93       * @param smtpPortStr
94       *            The SMTP port to send to.
95       * @param smtpUsername
96       *            The username required to authenticate against the SMTP server.
97       * @param smtpPassword
98       *            The password required to authenticate against the SMTP server.
99       * @param smtpDebug
100      *            Enable mail session debuging on STDOUT.
101      * @param bufferSizeStr
102      *            How many log events should be buffered for inclusion in the
103      *            message?
104      * @param layout
105      *            The layout to use (defaults to HtmlLayout).
106      * @param filter
107      *            The Filter or null (defaults to ThresholdFilter, level of
108      *            ERROR).
109      * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
110      *               they are propagated to the caller.
111      * @return The SmtpAppender.
112      */
113     @PluginFactory
114     public static SmtpAppender createAppender(
115             @PluginConfiguration final Configuration config,
116             @PluginAttribute("name") @Required final String name,
117             @PluginAttribute("to") final String to,
118             @PluginAttribute("cc") final String cc,
119             @PluginAttribute("bcc") final String bcc,
120             @PluginAttribute("from") final String from,
121             @PluginAttribute("replyTo") final String replyTo,
122             @PluginAttribute("subject") final String subject,
123             @PluginAttribute("smtpProtocol") final String smtpProtocol,
124             @PluginAttribute("smtpHost") final String smtpHost,
125             @PluginAttribute(value = "smtpPort", defaultString = "0") @ValidPort final String smtpPortStr,
126             @PluginAttribute("smtpUsername") final String smtpUsername,
127             @PluginAttribute(value = "smtpPassword", sensitive = true) final String smtpPassword,
128             @PluginAttribute("smtpDebug") final String smtpDebug,
129             @PluginAttribute("bufferSize") final String bufferSizeStr,
130             @PluginElement("Layout") Layout<? extends Serializable> layout,
131             @PluginElement("Filter") Filter filter,
132             @PluginAttribute("ignoreExceptions") final String ignore) {
133         if (name == null) {
134             LOGGER.error("No name provided for SmtpAppender");
135             return null;
136         }
137 
138         final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
139         final int smtpPort = AbstractAppender.parseInt(smtpPortStr, 0);
140         final boolean isSmtpDebug = Boolean.parseBoolean(smtpDebug);
141         final int bufferSize = bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integer.parseInt(bufferSizeStr);
142 
143         if (layout == null) {
144             layout = HtmlLayout.createDefaultLayout();
145         }
146         if (filter == null) {
147             filter = ThresholdFilter.createFilter(null, null, null);
148         }
149         final Configuration configuration = config != null ? config : new DefaultConfiguration();
150 
151         final SmtpManager manager = SmtpManager.getSmtpManager(configuration, to, cc, bcc, from, replyTo, subject, smtpProtocol,
152             smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(),  bufferSize);
153         if (manager == null) {
154             return null;
155         }
156 
157         return new SmtpAppender(name, filter, layout, manager, ignoreExceptions, null);
158     }
159 
160     /**
161      * Capture all events in CyclicBuffer.
162      * @param event The Log event.
163      * @return true if the event should be filtered.
164      */
165     @Override
166     public boolean isFiltered(final LogEvent event) {
167         final boolean filtered = super.isFiltered(event);
168         if (filtered) {
169             manager.add(event);
170         }
171         return filtered;
172     }
173 
174     /**
175      * Perform SmtpAppender specific appending actions, mainly adding the event
176      * to a cyclic buffer and checking if the event triggers an e-mail to be
177      * sent.
178      * @param event The Log event.
179      */
180     @Override
181     public void append(final LogEvent event) {
182         manager.sendEvents(getLayout(), event);
183     }
184 }