Details
Description
I have a use case where some of my logged events have been marked with a custom Marker (e.g. "PRIVATE"). When the SMTP Appender sends out an e-mail with the triggering event and its cyclic buffer of collected log events, I do not want the log events that have been set with a custom Marker to be included in the e-mail.
What follows is the source code for a custom SMTP appender plugin that I created to support the above use case:
package org.apache.logging.log4j.core.appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.filter.CompositeFilter; import org.apache.logging.log4j.core.filter.MarkerFilter; import org.apache.logging.log4j.core.filter.ThresholdFilter; import org.apache.logging.log4j.core.layout.HtmlLayout; import org.apache.logging.log4j.core.net.SmtpManager; import org.apache.logging.log4j.core.util.Booleans; import java.io.Serializable; import java.util.List; /** * Send an e-mail when a specific logging event occurs, typically on errors or * fatal errors. Unlike the vanilla SmtpAppender, this variation allows for * using a MarkerFilter to filter out certain logging events from appearing in * the e-mail. * <p/> * <Filters> * <MarkerFilter marker="PRIVATE" onMatch="DENY" onMismatch="NEUTRAL"/> * <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> * </Filters> * <p/> * The number of logging events delivered in this e-mail depend on the value of * <b>BufferSize</b> option. The <code>SmtpAppender</code> keeps only the last * <code>BufferSize</code> logging events in its cyclic buffer. This keeps * memory requirements at a reasonable level while still delivering useful * application context. * <p/> * By default, an email message will be formatted as HTML. This can be modified * by setting a layout for the appender. * <p/> * By default, an email message will be sent when an ERROR or higher severity * message is appended. This can be modified by setting a filter for the * appender. */ @Plugin(name = "FilteredSMTP", category = "Core", elementType = "appender", printObject = true) public class FilteredSmtpAppender extends AbstractAppender { private static final long serialVersionUID = 1L; private static final int DEFAULT_BUFFER_SIZE = 512; /** * The SMTP Manager */ private final SmtpManager manager; /** * Constructor. * * @param name The Appender name. * @param filter The Filter to associate with the Appender. * @param layout The layout to use to format the event. * @param manager The SmtpManager to use to format and send the e-mail. * @param ignoreExceptions If true, exceptions will be logged and suppressed. If false errors will be propagated. */ protected FilteredSmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, final SmtpManager manager, final boolean ignoreExceptions) { super(name, filter, layout, ignoreExceptions); this.manager = manager; } /** * Create a FilteredSmtpAppender. * * @param name The name of the Appender. * @param to The comma-separated list of recipient email addresses. * @param cc The comma-separated list of CC email addresses. * @param bcc The comma-separated list of BCC email addresses. * @param from The email address of the sender. * @param replyTo The comma-separated list of reply-to email addresses. * @param subject The subject of the email message. * @param smtpProtocol The SMTP transport protocol (such as "smtps", defaults to "smtp"). * @param smtpHost The SMTP hostname to send to. * @param smtpPortStr The SMTP port to send to. * @param smtpUsername The username required to authenticate against the SMTP server. * @param smtpPassword The password required to authenticate against the SMTP server. * @param smtpDebug Enable mail session debuging on STDOUT. * @param bufferSizeStr How many log events should be buffered for inclusion in the * message? * @param layout The layout to use (defaults to HtmlLayout). * @param filter The Filter or null (defaults to ThresholdFilter, level of * ERROR). * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise * they are propagated to the caller. * * @return The FilteredSmtpAppender. */ @PluginFactory public static FilteredSmtpAppender createAppender( @PluginAttribute("name") final String name, @PluginAttribute("to") final String to, @PluginAttribute("cc") final String cc, @PluginAttribute("bcc") final String bcc, @PluginAttribute("from") final String from, @PluginAttribute("replyTo") final String replyTo, @PluginAttribute("subject") final String subject, @PluginAttribute("smtpProtocol") final String smtpProtocol, @PluginAttribute("smtpHost") final String smtpHost, @PluginAttribute("smtpPort") final String smtpPortStr, @PluginAttribute("smtpUsername") final String smtpUsername, @PluginAttribute("smtpPassword") final String smtpPassword, @PluginAttribute("smtpDebug") final String smtpDebug, @PluginAttribute("bufferSize") final String bufferSizeStr, @PluginElement("Layout") Layout<? extends Serializable> layout, @PluginElement("Filter") Filter filter, @PluginAttribute("ignoreExceptions") final String ignore) { if (name == null) { LOGGER.error("No name provided for FilteredSmtpAppender"); return null; } final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true); final int smtpPort = AbstractAppender.parseInt(smtpPortStr, 0); final boolean isSmtpDebug = Boolean.parseBoolean(smtpDebug); final int bufferSize = bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integer.parseInt(bufferSizeStr); if (layout == null) { layout = HtmlLayout.createDefaultLayout(); } if (filter == null) { filter = ThresholdFilter.createFilter(null, null, null); } final SmtpManager manager = SmtpManager.getSMTPManager(to, cc, bcc, from, replyTo, subject, smtpProtocol, smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(), bufferSize); if (manager == null) { return null; } return new FilteredSmtpAppender(name, filter, layout, manager, ignoreExceptions); } /** * Capture all events in CyclicBuffer. Ignore events that are denied by a * MarkerFilter. * * @param event The Log event. * * @return true if the event should be filtered. */ @Override public boolean isFiltered(final LogEvent event) { boolean filtered = false; final Filter filter = this.getFilter(); if (filter instanceof CompositeFilter) { final List<Filter> filters = ((CompositeFilter)filter).getFilters(); for (final Filter aFilter : filters) { final Filter.Result filterResult = (aFilter != null) ? aFilter.filter(event) : Filter.Result.NEUTRAL; if (!Filter.Result.NEUTRAL.equals(filterResult)) { filtered = (Filter.Result.DENY.equals(filterResult)); if (filtered) { final boolean isMarkerFilter = aFilter instanceof MarkerFilter; // Ignore events that are denied by a MarkerFilter. if (!isMarkerFilter) { manager.add(event); } } break; } } } else { filtered = super.isFiltered(event); if (filtered) { final boolean isMarkerFilter = filter instanceof MarkerFilter; if (!isMarkerFilter) { manager.add(event); } } } return filtered; } /** * Perform FilterableSmtpAppender specific appending actions, mainly adding * the event to a cyclic buffer and checking if the event triggers an e-mail * to be sent. * * @param event The Log event. */ @Override public void append(final LogEvent event) { manager.sendEvents(getLayout(), event); } }
Such a use case could be configured as follows for the custom Filtered SMTP Appender plugin. Here it is configured to accept only logging events of WARN level or greater:
<?xml version="1.0" encoding="UTF-8"?> ... <Appender type="FilteredSMTP" name="filteredSmtp" bufferSize="5" smtpHost="${smtpHost}" smtpPort="${smtpPort}" smtpProtocol="${smtpProtocol}" smtpUsername="${smtpUsername}" smtpPassword="${smtpPassword}" subject="${emailSubject}" from="${emailFrom}" to="${emailTo}" replyTo="${emailReplyTo}" cc="${emailCc}" bcc="${emailBcc}" > <Layout type="PatternLayout"> <Pattern>%m</Pattern> </Layout> <Filters> <MarkerFilter marker="PRIVATE" onMatch="DENY" onMismatch="NEUTRAL"/> <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/> </Filters> </Appender> ...
Attachments
Attachments
Issue Links
- is caused by
-
LOG4J2-131 Create SMTPAppender
- Resolved