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.plugins.Plugin;
30  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
31  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
32  import org.apache.logging.log4j.core.config.plugins.PluginElement;
33  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
35  import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
36  import org.apache.logging.log4j.core.filter.ThresholdFilter;
37  import org.apache.logging.log4j.core.layout.HtmlLayout;
38  import org.apache.logging.log4j.core.net.SmtpManager;
39  import org.apache.logging.log4j.core.util.Booleans;
40  
41  /**
42   * Send an e-mail when a specific logging event occurs, typically on errors or
43   * fatal errors.
44   *
45   * <p>
46   * The number of logging events delivered in this e-mail depend on the value of
47   * <b>BufferSize</b> option. The <code>SmtpAppender</code> keeps only the last
48   * <code>BufferSize</code> logging events in its cyclic buffer. This keeps
49   * memory requirements at a reasonable level while still delivering useful
50   * application context.
51   *
52   * By default, an email message will formatted as HTML. This can be modified by
53   * setting a layout for the appender.
54   *
55   * By default, an email message will be sent when an ERROR or higher severity
56   * message is appended. This can be modified by setting a filter for the
57   * appender.
58   */
59  @Plugin(name = "SMTP", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
60  public final class SmtpAppender extends AbstractAppender {
61  
62      private static final int DEFAULT_BUFFER_SIZE = 512;
63  
64      /** The SMTP Manager */
65      private final SmtpManager manager;
66  
67      private SmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, final SmtpManager manager,
68                           final boolean ignoreExceptions) {
69          super(name, filter, layout, ignoreExceptions);
70          this.manager = manager;
71      }
72  
73      /**
74       * Create a SmtpAppender.
75       *
76       * @param name
77       *            The name of the Appender.
78       * @param to
79       *            The comma-separated list of recipient email addresses.
80       * @param cc
81       *            The comma-separated list of CC email addresses.
82       * @param bcc
83       *            The comma-separated list of BCC email addresses.
84       * @param from
85       *            The email address of the sender.
86       * @param replyTo
87       *            The comma-separated list of reply-to email addresses.
88       * @param subject The subject of the email message.
89       * @param smtpProtocol The SMTP transport protocol (such as "smtps", defaults to "smtp").
90       * @param smtpHost
91       *            The SMTP hostname to send to.
92       * @param smtpPortStr
93       *            The SMTP port to send to.
94       * @param smtpUsername
95       *            The username required to authenticate against the SMTP server.
96       * @param smtpPassword
97       *            The password required to authenticate against the SMTP server.
98       * @param smtpDebug
99       *            Enable mail session debuging on STDOUT.
100      * @param bufferSizeStr
101      *            How many log events should be buffered for inclusion in the
102      *            message?
103      * @param layout
104      *            The layout to use (defaults to HtmlLayout).
105      * @param filter
106      *            The Filter or null (defaults to ThresholdFilter, level of
107      *            ERROR).
108      * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
109      *               they are propagated to the caller.
110      * @return The SmtpAppender.
111      */
112     @PluginFactory
113     public static SmtpAppender createAppender(
114             @PluginConfiguration final Configuration config,
115             @PluginAttribute("name") @Required final String name,
116             @PluginAttribute("to") final String to,
117             @PluginAttribute("cc") final String cc,
118             @PluginAttribute("bcc") final String bcc,
119             @PluginAttribute("from") final String from,
120             @PluginAttribute("replyTo") final String replyTo,
121             @PluginAttribute("subject") final String subject,
122             @PluginAttribute("smtpProtocol") final String smtpProtocol,
123             @PluginAttribute("smtpHost") final String smtpHost,
124             @PluginAttribute(value = "smtpPort", defaultString = "0") @ValidPort final String smtpPortStr,
125             @PluginAttribute("smtpUsername") final String smtpUsername,
126             @PluginAttribute(value = "smtpPassword", sensitive = true) final String smtpPassword,
127             @PluginAttribute("smtpDebug") final String smtpDebug,
128             @PluginAttribute("bufferSize") final String bufferSizeStr,
129             @PluginElement("Layout") Layout<? extends Serializable> layout,
130             @PluginElement("Filter") Filter filter,
131             @PluginAttribute("ignoreExceptions") final String ignore) {
132         if (name == null) {
133             LOGGER.error("No name provided for SmtpAppender");
134             return null;
135         }
136 
137         final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
138         final int smtpPort = AbstractAppender.parseInt(smtpPortStr, 0);
139         final boolean isSmtpDebug = Boolean.parseBoolean(smtpDebug);
140         final int bufferSize = bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integer.parseInt(bufferSizeStr);
141 
142         if (layout == null) {
143             layout = HtmlLayout.createDefaultLayout();
144         }
145         if (filter == null) {
146             filter = ThresholdFilter.createFilter(null, null, null);
147         }
148         final Configuration configuration = config != null ? config : new DefaultConfiguration();
149 
150         final SmtpManager manager = SmtpManager.getSmtpManager(configuration, to, cc, bcc, from, replyTo, subject, smtpProtocol,
151             smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(),  bufferSize);
152         if (manager == null) {
153             return null;
154         }
155 
156         return new SmtpAppender(name, filter, layout, manager, ignoreExceptions);
157     }
158 
159     /**
160      * Capture all events in CyclicBuffer.
161      * @param event The Log event.
162      * @return true if the event should be filtered.
163      */
164     @Override
165     public boolean isFiltered(final LogEvent event) {
166         final boolean filtered = super.isFiltered(event);
167         if (filtered) {
168             manager.add(event);
169         }
170         return filtered;
171     }
172 
173     /**
174      * Perform SmtpAppender specific appending actions, mainly adding the event
175      * to a cyclic buffer and checking if the event triggers an e-mail to be
176      * sent.
177      * @param event The Log event.
178      */
179     @Override
180     public void append(final LogEvent event) {
181         manager.sendEvents(getLayout(), event);
182     }
183 }