Uploaded image for project: 'Log4j 2'
  1. Log4j 2
  2. LOG4J2-1039

SmtpAppender needs the ability to filter out logging events that contain a specific Marker



    • Flags:


      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/>
       * &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.
        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.
        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) {
          else {
            filtered = super.isFiltered(event);
            if (filtered) {
              final boolean isMarkerFilter = filter instanceof MarkerFilter;
              if (!isMarkerFilter) {
          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.
        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"
                    smtpHost="${smtpHost}" smtpPort="${smtpPort}" smtpProtocol="${smtpProtocol}"
                    smtpUsername="${smtpUsername}" smtpPassword="${smtpPassword}"
            <Layout type="PatternLayout">
              <MarkerFilter marker="PRIVATE" onMatch="DENY" onMismatch="NEUTRAL"/>
              <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>


        1. FilteredSmtpAppender.java
          8 kB
          Tony DeFusco
        2. SmtpAppender.patch
          2 kB
          Tony DeFusco



            • Assignee:
              tonedef71 Tony DeFusco
            • Votes:
              0 Vote for this issue
              3 Start watching this issue


              • Created: