001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 018package org.apache.logging.log4j.core.appender; 019 020import org.apache.logging.log4j.Level; 021import org.apache.logging.log4j.core.Filter; 022import org.apache.logging.log4j.core.Layout; 023import org.apache.logging.log4j.core.LogEvent; 024import org.apache.logging.log4j.core.config.plugins.Plugin; 025import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 026import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 027import org.apache.logging.log4j.core.config.plugins.PluginElement; 028import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 029import org.apache.logging.log4j.core.filter.ThresholdFilter; 030import org.apache.logging.log4j.core.layout.HtmlLayout; 031import org.apache.logging.log4j.core.net.SmtpManager; 032import org.apache.logging.log4j.core.net.ssl.SslConfiguration; 033import org.apache.logging.log4j.core.util.Booleans; 034 035import java.io.Serializable; 036 037/** 038 * Send an e-mail when a specific logging event occurs, typically on errors or 039 * fatal errors. 040 * 041 * <p> 042 * The number of logging events delivered in this e-mail depend on the value of 043 * <b>BufferSize</b> option. The <code>SmtpAppender</code> keeps only the last 044 * <code>BufferSize</code> logging events in its cyclic buffer. This keeps 045 * memory requirements at a reasonable level while still delivering useful 046 * application context. 047 * 048 * By default, an email message will formatted as HTML. This can be modified by 049 * setting a layout for the appender. 050 * 051 * By default, an email message will be sent when an ERROR or higher severity 052 * message is appended. This can be modified by setting a filter for the 053 * appender. 054 */ 055@Plugin(name = "SMTP", category = "Core", elementType = "appender", printObject = true) 056public final class SmtpAppender extends AbstractAppender { 057 058 private static final long serialVersionUID = 1L; 059 private static final int DEFAULT_BUFFER_SIZE = 512; 060 061 /** The SMTP Manager */ 062 private final SmtpManager manager; 063 064 private SmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, final SmtpManager manager, 065 final boolean ignoreExceptions) { 066 super(name, filter, layout, ignoreExceptions); 067 this.manager = manager; 068 } 069 070 public static class Builder implements org.apache.logging.log4j.core.util.Builder<SmtpAppender> { 071 @PluginBuilderAttribute 072 @Required(message = "No name provided for SmtpAppender") 073 private String name; 074 075 @PluginElement("Filter") 076 private Filter filter = ThresholdFilter.createFilter(null, null, null); 077 078 @PluginElement("Layout") 079 private Layout<? extends Serializable> layout = HtmlLayout.createDefaultLayout(); 080 081 @PluginBuilderAttribute 082 private boolean ignoreExceptions = true; 083 084 @PluginBuilderAttribute 085 private String to; 086 087 @PluginBuilderAttribute 088 private String cc; 089 090 @PluginBuilderAttribute 091 private String bcc; 092 093 @PluginBuilderAttribute 094 private String from; 095 096 @PluginBuilderAttribute 097 private String replyTo; 098 099 @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}