You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@logging.apache.org by "Ron Grabowski (Jira)" <ji...@apache.org> on 2022/01/30 16:55:00 UTC

[jira] [Assigned] (LOG4J2-1039) SmtpAppender needs the ability to filter out logging events that contain a specific Marker

     [ https://issues.apache.org/jira/browse/LOG4J2-1039?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Ron Grabowski reassigned LOG4J2-1039:
-------------------------------------

    Assignee: Ron Grabowski

> SmtpAppender needs the ability to filter out logging events that contain a specific Marker
> ------------------------------------------------------------------------------------------
>
>                 Key: LOG4J2-1039
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-1039
>             Project: Log4j 2
>          Issue Type: Improvement
>          Components: Appenders, Filters
>    Affects Versions: 2.3
>            Reporter: Tony DeFusco
>            Assignee: Ron Grabowski
>            Priority: Major
>              Labels: easyfix, features, patch
>         Attachments: FilteredSmtpAppender.java, SmtpAppender.patch
>
>
> 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:
> {code:title=org.apache.logging.log4j.core.appender.FilteredSmtpAppender.java}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/>
>  * &lt;Filters&gt;
>  *   &lt;MarkerFilter marker="PRIVATE" onMatch="DENY" onMismatch="NEUTRAL"/&gt;
>  *   &lt;ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/&gt;
>  * &lt;/Filters&gt;
>  * <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);
>   }
> }{code}
> 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:
> {code:xml}<?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>
> ...{code}



--
This message was sent by Atlassian Jira
(v8.20.1#820001)