## Triggering an email containing the isoloated logs of selected transactions

Let Dave and Carol be software QA engineers working at a company called Fooware.com. As you might have guessed, Fooware.com sells foos. Yes, foos. Let Buscrit be a business critical back-end system running at Fooware.com. Buscrit is called by a number of applications to make business-critical transactions of various types.

We would like to allow Carol to access the logging data generated by Buscrit as conveniently as possible. Carol could access the log files directly on the server where Buscrit runs. Let us assume that accessing the log files is somehow impractical because one or ore more of the following conditions holds true:

1. Buscrit runs on multiple hosts and it is difficult to identify the host where a particular transaction was executed
2. Carol does not (or does not wish to) have access to the hosts where Byscrit runs
3. Buscrit is tested by multiple testers, e.g. Dave and Carol and others, simultanesouly so that it is hard to indetify and track an individual transaction in the log files

Given the above circumstances, let us create a logback configuration so that Carol receives an email message at the end of every transaction. We will iteratively refine this configuration so that Carol will receive an email containing the logs of each transaction in isolation and only for the transactions she explicitly selects.

### Triggering an email message at the end of each transaction

We will be using `SMTPAppender` to generate emails containing logging data. Please refer to the appropriate section of the manual to familiarize yourself with `SMTPAppender` and its properties.

The logback-demo project contains a Struts action called `PrimeAction`. It can factorize integers. Here is the pertinent structure of `PrimeAction`'s code:

    package ch.qos.logback.demo.prime;

    import org.apache.struts.action.Action;
    ...
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class PrimeAction extends Action {

      Logger logger = LoggerFactory.getLogger(PrimeAction.class);
      Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");

      public ActionForward execute(ActionMapping actionMapping,
                                   ActionForm actionForm, HttpServletRequest request,
                                   HttpServletResponse response) throws Exception {

        PrimeForm form = (PrimeForm) actionForm;

        Long number = form.getNumber();
        try {
          NumberCruncher nc = new NumberCruncherImpl();
          Long start = System.currentTimeMillis();
          Long[] result = nc.factor(number);
          Long duration = System.currentTimeMillis() - start;
          logger.info("Results computed in {} ms", duration);

          ...
        } finally {
          logger.info(SMTP_TRIGGER, "Prime computation ended");
        }
      }
    }

In a real world application, a transaction would involve systems external to the application, e.g. a database or a messaging queue. For the sake of this example, let us consider each factorization request as a transaciton. At the end of each factorization request, i.e. each transaction, the logger of the `PrimeAction` instance is invoked with the SMTP_TRIGGER marker and the message "Prime computation ended". We can capitalize on this logging request to clearly identify the end of every transaction in order to trigger an outgoing message.

Here is a configuration file which uses `JaninoEventEvaluator` to trigger an outgoing email for logging event marked with SMTP_TRIGGER.

    <configuration scan="true" scanPeriod="3 seconds">

      <!-- always a good idea to have an OnConsoleStatusListener -->
      <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

      <appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
        <SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
        <To>...</To>
        <From>...</From>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
          <pattern>%date%level%logger{24}%msg</pattern>
        </layout>

        <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
          <expression>
            marker != null  && marker.contains("SMTP_TRIGGER")
          </expression>
        </evaluator>
      </appender>

      <root level="DEBUG">
        <appender-ref ref="SMTP" />
      </root>

    </configuration>

### Transaction isolation

    <configuration scan="true" scanPeriod="3 seconds">

      <!-- always a good idea to have an OnConsoleStatusListener -->

      <appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
        <SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
        <To>com</To>
        <From></From>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
           <pattern>%date%level%logger{24}%msg</pattern>
        </layout>

        <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
          <key>uuid</key>
          <defaultValue>default</defaultValue>
        </discriminator>

        <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
          <expression>
            marker != null && marker.contains("SMTP_TRIGGER")
          </expression>
        </evaluator>

        <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
          <key>uuid</key>
          <defaultValue>default</defaultValue>
        </discriminator>

      </appender>

### Selective triggering & Transaction isolation

    <configuration scan="true" scanPeriod="3 seconds">

      <!-- always a good idea to have an OnConsoleStatusListener -->

      <appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
        <SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
        <To>com</To>
        <From></From>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
           <pattern>%date%level%logger{24}%msg</pattern>
        </layout>

        <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
          <key>uuid</key>
          <defaultValue>default</defaultValue>
        </discriminator>

        <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
          <expression>
            (mdc != null && mdc.get("txUser") != null &&
                 ((String) mdc.get("txUser")).contains("Mickey") )
            &&
            (marker != null  && marker.contains("SMTP_TRIGGER") )
          </expression>
        </evaluator>

        <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
          <key>uuid</key>
          <defaultValue>default</defaultValue>
        </discriminator>

      </appender>