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 org.apache.logging.log4j.Level;
21  import org.apache.logging.log4j.core.Filter;
22  import org.apache.logging.log4j.core.Layout;
23  import org.apache.logging.log4j.core.LogEvent;
24  import org.apache.logging.log4j.core.config.plugins.Plugin;
25  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
26  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
27  import org.apache.logging.log4j.core.config.plugins.PluginElement;
28  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
29  import org.apache.logging.log4j.core.filter.ThresholdFilter;
30  import org.apache.logging.log4j.core.layout.HtmlLayout;
31  import org.apache.logging.log4j.core.net.SmtpManager;
32  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
33  import org.apache.logging.log4j.core.util.Booleans;
34  
35  import java.io.Serializable;
36  
37  /**
38   * Send an e-mail when a specific logging event occurs, typically on errors or
39   * fatal errors.
40   *
41   * <p>
42   * The number of logging events delivered in this e-mail depend on the value of
43   * <b>BufferSize</b> option. The <code>SmtpAppender</code> keeps only the last
44   * <code>BufferSize</code> logging events in its cyclic buffer. This keeps
45   * memory requirements at a reasonable level while still delivering useful
46   * application context.
47   *
48   * By default, an email message will formatted as HTML. This can be modified by
49   * setting a layout for the appender.
50   *
51   * By default, an email message will be sent when an ERROR or higher severity
52   * message is appended. This can be modified by setting a filter for the
53   * appender.
54   */
55  @Plugin(name = "SMTP", category = "Core", elementType = "appender", printObject = true)
56  public final class SmtpAppender extends AbstractAppender {
57  
58      private static final long serialVersionUID = 1L;
59      private static final int DEFAULT_BUFFER_SIZE = 512;
60  
61      /** The SMTP Manager */
62      private final SmtpManager manager;
63  
64      private SmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, final SmtpManager manager,
65                           final boolean ignoreExceptions) {
66          super(name, filter, layout, ignoreExceptions);
67          this.manager = manager;
68      }
69  
70      public static class Builder implements org.apache.logging.log4j.core.util.Builder<SmtpAppender> {
71          @PluginBuilderAttribute
72          @Required(message = "No name provided for SmtpAppender")
73          private String name;
74  
75          @PluginElement("Filter")
76          private Filter filter = ThresholdFilter.createFilter(null, null, null);
77  
78          @PluginElement("Layout")
79          private Layout<? extends Serializable> layout = HtmlLayout.createDefaultLayout();
80  
81          @PluginBuilderAttribute
82          private boolean ignoreExceptions = true;
83  
84          @PluginBuilderAttribute
85          private String to;
86  
87          @PluginBuilderAttribute
88          private String cc;
89  
90          @PluginBuilderAttribute
91          private String bcc;
92  
93          @PluginBuilderAttribute
94          private String from;
95  
96          @PluginBuilderAttribute
97          private String replyTo;
98  
99          @PluginBuilderAttribute
100         private String subject;
101 
102         @PluginBuilderAttribute
103         private String smtpProtocol = "smtp";
104 
105         @PluginBuilderAttribute
106         private String smtpHost;
107 
108         @PluginBuilderAttribute
109         private int smtpPort;
110 
111         @PluginBuilderAttribute
112         private String smtpUsername;
113 
114         @PluginBuilderAttribute(sensitive = true)
115         private String smtpPassword;
116 
117         @PluginBuilderAttribute
118         private boolean smtpDebug;
119 
120         @PluginBuilderAttribute
121         private int bufferSize = DEFAULT_BUFFER_SIZE;
122 
123         @PluginElement("SSL")
124         private SslConfiguration sslConfiguration;
125 
126         /**
127          * Name of the SmtpAppender.
128          */
129         public Builder setName(final String name) {
130             this.name = name;
131             return this;
132         }
133 
134         /**
135          * Overrides the default filter. Default filter is a {@link ThresholdFilter} of level {@link Level#ERROR}.
136          */
137         public Builder setFilter(final Filter filter) {
138             this.filter = filter;
139             return this;
140         }
141 
142         /**
143          * Overrides the default layout. Default layout is the {@linkplain HtmlLayout#createDefaultLayout() default HTML layout}.
144          */
145         public Builder setLayout(final Layout<? extends Serializable> layout) {
146             this.layout = layout;
147             return this;
148         }
149 
150         /**
151          * Whether to ignore exceptions thrown by the SmtpAppender. Defaults to {@code true}.
152          */
153         public Builder setIgnoreExceptions(final boolean ignoreExceptions) {
154             this.ignoreExceptions = ignoreExceptions;
155             return this;
156         }
157 
158         /**
159          * Comma-separated list of recipient email addresses.
160          */
161         public Builder setTo(final String to) {
162             this.to = to;
163             return this;
164         }
165 
166         /**
167          * Comma-separated list of CC email addresses.
168          */
169         public Builder setCc(final String cc) {
170             this.cc = cc;
171             return this;
172         }
173 
174         /**
175          * Comma-separated list of BCC email addresses.
176          */
177         public Builder setBcc(final String bcc) {
178             this.bcc = bcc;
179             return this;
180         }
181 
182         /**
183          * Email address of the sender.
184          */
185         public Builder setFrom(final String from) {
186             this.from = from;
187             return this;
188         }
189 
190         /**
191          * Comma-separated list of Reply-To email addresses.
192          */
193         public Builder setReplyTo(final String replyTo) {
194             this.replyTo = replyTo;
195             return this;
196         }
197 
198         /**
199          * Subject template for the email messages.
200          * @see org.apache.logging.log4j.core.layout.PatternLayout
201          */
202         public Builder setSubject(final String subject) {
203             this.subject = subject;
204             return this;
205         }
206 
207         /**
208          * Transport protocol to use for SMTP such as "smtp" or "smtps". Defaults to "smtp".
209          */
210         public Builder setSmtpProtocol(final String smtpProtocol) {
211             this.smtpProtocol = smtpProtocol;
212             return this;
213         }
214 
215         /**
216          * Host name of SMTP server to send messages through.
217          */
218         public Builder setSmtpHost(final String smtpHost) {
219             this.smtpHost = smtpHost;
220             return this;
221         }
222 
223         /**
224          * Port number of SMTP server to send messages through.
225          */
226         public Builder setSmtpPort(final int smtpPort) {
227             this.smtpPort = smtpPort;
228             return this;
229         }
230 
231         /**
232          * Username to authenticate with SMTP server.
233          */
234         public Builder setSmtpUsername(final String smtpUsername) {
235             this.smtpUsername = smtpUsername;
236             return this;
237         }
238 
239         /**
240          * Password to authenticate with SMTP server.
241          */
242         public Builder setSmtpPassword(final String smtpPassword) {
243             this.smtpPassword = smtpPassword;
244             return this;
245         }
246 
247         /**
248          * Enables or disables mail session debugging on STDOUT. Disabled by default.
249          */
250         public Builder setSmtpDebug(final boolean smtpDebug) {
251             this.smtpDebug = smtpDebug;
252             return this;
253         }
254 
255         /**
256          * Number of log events to buffer before sending an email. Defaults to {@value #DEFAULT_BUFFER_SIZE}.
257          */
258         public Builder setBufferSize(final int bufferSize) {
259             this.bufferSize = bufferSize;
260             return this;
261         }
262 
263         /**
264          * Specifies an SSL configuration for smtps connections.
265          */
266         public Builder setSslConfiguration(final SslConfiguration sslConfiguration) {
267             this.sslConfiguration = sslConfiguration;
268             return this;
269         }
270 
271         @Override
272         public SmtpAppender build() {
273             if (layout == null) {
274                 layout = HtmlLayout.createDefaultLayout();
275             }
276             if (filter == null) {
277                 filter = ThresholdFilter.createFilter(null, null, null);
278             }
279             final SmtpManager smtpManager =
280                     SmtpManager.getSMTPManager(to, cc, bcc, from, replyTo, subject, smtpProtocol, smtpHost, smtpPort,
281                             smtpUsername, smtpPassword, smtpDebug, filter.toString(), bufferSize, sslConfiguration);
282             return new SmtpAppender(name, filter, layout, smtpManager, ignoreExceptions);
283         }
284     }
285 
286     @PluginBuilderFactory
287     public static Builder newBuilder() {
288         return new Builder();
289     }
290 
291     @Deprecated
292     public static SmtpAppender createAppender(final String name, final String to, final String cc, final String bcc,
293             final String from, final String replyTo, final String subject, final String smtpProtocol, final String smtpHost,
294             final String smtpPortStr, final String smtpUsername, final String smtpPassword, final String smtpDebug,
295             final String bufferSizeStr, Layout<? extends Serializable> layout, Filter filter, final String ignore) {
296         if (name == null) {
297             LOGGER.error("No name provided for SmtpAppender");
298             return null;
299         }
300 
301         final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
302         final int smtpPort = AbstractAppender.parseInt(smtpPortStr, 0);
303         final boolean isSmtpDebug = Boolean.parseBoolean(smtpDebug);
304         final int bufferSize = bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integer.parseInt(bufferSizeStr);
305 
306         if (layout == null) {
307             layout = HtmlLayout.createDefaultLayout();
308         }
309         if (filter == null) {
310             filter = ThresholdFilter.createFilter(null, null, null);
311         }
312 
313         final SmtpManager manager = SmtpManager.getSMTPManager(to, cc, bcc, from, replyTo, subject, smtpProtocol,
314             smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(),  bufferSize);
315         if (manager == null) {
316             return null;
317         }
318 
319         return new SmtpAppender(name, filter, layout, manager, ignoreExceptions);
320     }
321 
322     /**
323      * Capture all events in CyclicBuffer.
324      * @param event The Log event.
325      * @return true if the event should be filtered.
326      */
327     @Override
328     public boolean isFiltered(final LogEvent event) {
329         final boolean filtered = super.isFiltered(event);
330         if (filtered) {
331             manager.add(event);
332         }
333         return filtered;
334     }
335 
336     /**
337      * Perform SmtpAppender specific appending actions, mainly adding the event
338      * to a cyclic buffer and checking if the event triggers an e-mail to be
339      * sent.
340      * @param event The Log event.
341      */
342     @Override
343     public void append(final LogEvent event) {
344         manager.sendEvents(getLayout(), event);
345     }
346 }