Logback email notification

Usually we use logging systems just to write our application logs to the console and/or to a file in the filesystem, forgetting that most of the logging libraries offers more functionality than just the mentioned.

In this post I am going to explain how we used Logback to easily fulfill the requirement of sending error/warning emails under certain critical conditions that happens in our applications.

On the way we are going to use a docker image that comes in handy for testing whether our emails are being sent out as expected.

Adding the required libraries to our pom.xml

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.0.11</version>
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.0.11</version>
</dependency>

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

<dependency>
    <groupId>janino</groupId>
    <artifactId>janino</artifactId>
    <version>2.5.10</version>
</dependency>

Configuring the email appender

The first thing we have to do is to create a new SMTP appender in the logback.xml configuration file.

<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">

    <smtpHost>localhost</smtpHost>
    <to>main_app_users@bestapp.com</to>
    <to>on_call_service@bestapp.com</to>
    <from>critical-errors@bestapp.com</from>
    <subject>App Problems</subject>

    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>

    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
        <!-- send just one log entry per email -->
        <bufferSize>1</bufferSize>
    </cyclicBufferTracker>

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

</appender>

 

and add the just created appender to the root logger

<root level="debug">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="EMAIL"/>
</root>

The buffer size defines how many logs should be logged before the email is sent.

The evaluator is useful when we want to somehow signal which logs do we really want to trigger the emailing event in our code. Just have a look at the next section to understand what I mean.

Writing a simple main method to exercise the logging system

Once we have the appender correctly set up, we are going to write some logs in a simple static main method.

public class EmailLogging {

    static Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");

    public static void main(String[] args) throws InterruptedException {
        Logger logger = LoggerFactory.getLogger(EmailLogging.class);
        logger.debug("Hello world.");
        logger.error("error #1");
        logger.error("error #2");
        logger.info(SMTP_TRIGGER, "Fatal error #3 - This should be reported");
    }
}

Since probably we only want to send the email upon relevant application events, we have to somehow signal the logger which log will trigger the mail sending action. This is achieved by the so called Marker. Notice that we obtain the Marker we defined in the logback.xml configuration through the provided MarkerFarctory, and afterwards, we make use of it in the log statements we want to trigger the the emailing event.

In this example, we expect the Fatal error #3 to trigger the email sending.

Starting the docker container

Let’s start the docker container that will allow us to test that the email that we expect to be sent will be actually sent. You can find the docker image to be used here.

I am assuming here that you already know what Docker is and you have docker already installed in your system.


sudo docker run -d -p 1025:1025 -p 8025:8025  mailhog/mailhog

  • In port 1025 is listening the SMTP server.
  • In port 8025 we have the nice web interface that visually allows us to check whether any email hits our inbox.

Running the application and checking the email coming

Now its time check that our implementation works. Lets run the main method and check that we receive the expected email.

22:40:54.324 [main] DEBUG com.jlsoler.EmailLogging - Hello world.
22:40:54,327 |-INFO in ch.qos.logback.classic.net.SMTPAppender[EMAIL] - SMTPAppender [EMAIL] is tracking [1] buffers
22:40:54.327 [main] ERROR com.jlsoler.EmailLogging - error #1
22:40:54.327 [main] ERROR com.jlsoler.EmailLogging - error #2
22:40:54.327 [main] INFO com.jlsoler.EmailLogging - Fatal error #3 - This should be reported
22:40:54,397 |-INFO in ch.qos.logback.classic.net.SMTPAppender[EMAIL] - Sent out SMTP message "App Problems" to [main_app_users@bestapp.com, on_call_service@bestapp.com]

Leave a reply:

Your email address will not be published.

Site Footer