karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbono...@apache.org
Subject [karaf-decanter] branch master updated: [KARAF-6437] Add templating support in email alerter, including possible properties interpolation
Date Fri, 27 Sep 2019 09:05:47 GMT
This is an automated email from the ASF dual-hosted git repository.

jbonofre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/karaf-decanter.git


The following commit(s) were added to refs/heads/master by this push:
     new 9efbdc8  [KARAF-6437] Add templating support in email alerter, including possible
properties interpolation
     new 3a616ca  Merge pull request #98 from jbonofre/KARAF-6437
9efbdc8 is described below

commit 9efbdc899e51645a7299e1e1f79b8d0a6918fe98
Author: Jean-Baptiste Onofré <jbonofre@apache.org>
AuthorDate: Fri Sep 27 10:08:36 2019 +0200

    [KARAF-6437] Add templating support in email alerter, including possible properties interpolation
---
 alerting/alerter/email/pom.xml                     |  15 +-
 .../decanter/alerting/email/EmailAlerter.java      | 142 ++++++++++--
 .../decanter/alerting/email/EmailAlerterTest.java  | 247 +++++++++++++++++++++
 manual/src/main/asciidoc/user-guide/alerting.adoc  |  15 ++
 4 files changed, 398 insertions(+), 21 deletions(-)

diff --git a/alerting/alerter/email/pom.xml b/alerting/alerter/email/pom.xml
index fd06440..c277d7e 100644
--- a/alerting/alerter/email/pom.xml
+++ b/alerting/alerter/email/pom.xml
@@ -37,7 +37,20 @@
         <dependency>
             <groupId>javax.mail</groupId>
             <artifactId>javax.mail-api</artifactId>
-            <version>1.5.6</version>
+            <version>1.6.0</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+            <version>1.6.0</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 
diff --git a/alerting/alerter/email/src/main/java/org/apache/karaf/decanter/alerting/email/EmailAlerter.java
b/alerting/alerter/email/src/main/java/org/apache/karaf/decanter/alerting/email/EmailAlerter.java
index 02f7568..b0c2ee2 100644
--- a/alerting/alerter/email/src/main/java/org/apache/karaf/decanter/alerting/email/EmailAlerter.java
+++ b/alerting/alerter/email/src/main/java/org/apache/karaf/decanter/alerting/email/EmailAlerter.java
@@ -42,20 +42,29 @@ public class EmailAlerter implements EventHandler {
 
     private final static Logger LOGGER = LoggerFactory.getLogger(EmailAlerter.class);
 
-    private String from;
-    private String to;
+    private String from = null;
+    private String to = null;
+    private String cc = null;
+    private String bcc = null;
+    private String subject = null;
+    private String body = null;
+    private String bodyType = null;
 
     private Properties properties;
 
     @SuppressWarnings("unchecked")
     public void activate(ComponentContext context) throws ConfigurationException {
-        Dictionary<String, Object> config = context.getProperties();
-        requireProperty(config, "from");
-        requireProperty(config, "to");
-        requireProperty(config, "host");
+        activate(context.getProperties());
+    }
 
-        this.from = (String) config.get("from");
-        this.to = (String) config.get("to");
+    protected void activate(Dictionary<String, Object> config) throws ConfigurationException
{
+        from = (config.get("from") != null) ? config.get("from").toString() : null;
+        to = (config.get("to") != null) ? config.get("to").toString() : null;
+        subject = (config.get("subject") != null) ? config.get("subject").toString() : null;
+        body = (config.get("body") != null) ? config.get("body").toString() : null;
+        bodyType = (config.get("body.type") != null) ? config.get("body.type").toString()
: "text/plain";
+        cc = (config.get("cc") != null) ? config.get("cc").toString() : null;
+        bcc = (config.get("bcc")  != null) ? config.get("bcc").toString() : null;
 
         properties = new Properties();
         properties.put("mail.smtp.host", config.get("host"));
@@ -84,18 +93,106 @@ public class EmailAlerter implements EventHandler {
         Session session = Session.getDefaultInstance(properties);
         MimeMessage message = new MimeMessage(session);
         try {
-            message.setFrom(new InternetAddress(from));
-            message.addRecipients(Message.RecipientType.TO, to);
+            // set from
+            if (event.getProperty("from") != null) {
+                message.setFrom(new InternetAddress(event.getProperty("from").toString()));
+            } else if (event.getProperty("alert.email.from") != null) {
+                message.setFrom(new InternetAddress(event.getProperty("alert.email.from").toString()));
+            } else if (from != null){
+                message.setFrom(from);
+            } else {
+                message.setFrom("decanter@karaf.apache.org");
+            }
+            // set to
+            if (event.getProperty("to") != null) {
+                message.addRecipients(Message.RecipientType.TO, event.getProperty("to").toString());
+            } else if (event.getProperty("alert.email.to") != null) {
+                message.addRecipients(Message.RecipientType.TO, event.getProperty("alert.email.to").toString());
+            } else if (to != null) {
+                message.addRecipients(Message.RecipientType.TO, to);
+            } else {
+                LOGGER.warn("to destination is not defined");
+                return;
+            }
+            // set cc
+            if (event.getProperty("cc") != null) {
+                message.addRecipients(Message.RecipientType.CC, event.getProperty("cc").toString());
+            } else if (event.getProperty("alert.email.cc") != null) {
+                message.addRecipients(Message.RecipientType.CC, event.getProperty("alert.email.cc").toString());
+            } else if (cc != null) {
+                message.addRecipients(Message.RecipientType.CC, cc);
+            }
+            // set bcc
+            if (event.getProperty("bcc") != null) {
+                message.addRecipients(Message.RecipientType.BCC, event.getProperty("bcc").toString());
+            } else if (event.getProperty("alert.email.bcc") != null) {
+                message.addRecipients(Message.RecipientType.BCC, event.getProperty("alert.email.bcc").toString());
+            } else if (bcc != null) {
+                message.addRecipients(Message.RecipientType.BCC, bcc);
+            }
+            // set subject
+            setSubject(message, event);
+            // set body
+            setBody(message, event);
+            // send email
+            if (properties.get("mail.smtp.user") != null) {
+                Transport.send(message, (String) properties.get("mail.smtp.user"), (String)
properties.get("mail.smtp.password"));
+            } else {
+                Transport.send(message);
+            }
+        } catch (Exception e) {
+            LOGGER.error("Can't send the alert e-mail", e);
+        }
+    }
+
+    /**
+     * Visible for testing.
+     */
+    protected void setSubject(MimeMessage message, Event event) throws Exception {
+        if (event.getProperty("subject") != null) {
+            message.setSubject(interpolation(event.getProperty("subject").toString(), event));
+        } else if (event.getProperty("alert.email.subject") != null) {
+            message.setSubject(interpolation(event.getProperty("alert.email.subject").toString(),
event));
+        } else if (subject != null) {
+            message.setSubject(interpolation(subject, event));
+        } else {
             String alertLevel = (String) event.getProperty("alertLevel");
             String alertAttribute = (String) event.getProperty("alertAttribute");
             String alertPattern = (String) event.getProperty("alertPattern");
-            boolean recovery = (boolean) event.getProperty("alertBackToNormal");
+            boolean recovery = false;
+            if (event.getProperty("alertBackToNormal") != null) {
+                recovery = (boolean) event.getProperty("alertBackToNormal");
+            }
             if (!recovery) {
                 message.setSubject("[" + alertLevel + "] Alert on " + alertAttribute);
             } else {
                 message.setSubject("Alert on " + alertAttribute + " back to normal");
             }
-            StringBuilder builder = new StringBuilder();
+        }
+    }
+
+    /**
+     * Visible for testing.
+     */
+    protected void setBody(MimeMessage message, Event event) throws Exception {
+        String contentType = bodyType;
+        contentType = (event.getProperty("body.type") != null) ? event.getProperty("body.type").toString()
: contentType;
+        contentType = (event.getProperty("alert.email.body.type") != null) ? event.getProperty("alert.email.body.type").toString()
: contentType;
+        StringBuilder builder = new StringBuilder();
+        if (event.getProperty("body") != null) {
+            builder.append(interpolation(event.getProperty("body").toString(), event));
+        } else if (event.getProperty("alert.email.body") != null) {
+            builder.append(interpolation(event.getProperty("alert.email.body").toString(),
event));
+        } else if (body != null) {
+            builder.append(interpolation(body, event));
+        } else {
+            String alertLevel = (String) event.getProperty("alertLevel");
+            String alertAttribute = (String) event.getProperty("alertAttribute");
+            String alertPattern = (String) event.getProperty("alertPattern");
+            boolean recovery = false;
+            if (event.getProperty("alertBackToNormal") != null) {
+                recovery = (boolean) event.getProperty("alertBackToNormal");
+            }
             if (!recovery) {
                 builder.append(alertLevel + " alert: " + alertAttribute + " is out of the
pattern " + alertPattern + "\n");
             } else {
@@ -106,15 +203,20 @@ public class EmailAlerter implements EventHandler {
             for (String name : event.getPropertyNames()) {
                 builder.append("\t").append(name).append(": ").append(event.getProperty(name)).append("\n");
             }
-            message.setText(builder.toString());
-            if (properties.get("mail.smtp.user") != null) {
-                Transport.send(message, (String) properties.get("mail.smtp.user"), (String)
properties.get("mail.smtp.password"));
-            } else {
-                Transport.send(message);
-            }
-        } catch (Exception e) {
-            LOGGER.error("Can't send the alert e-mail", e);
         }
+        message.setText(builder.toString(), contentType);
+    }
+
+    /**
+     * Visible for testing
+     * @return the interpolated string
+     */
+    protected static String interpolation(String source, Event event) {
+        String interpolated = source;
+        for (String propertyName : event.getPropertyNames()) {
+            interpolated = interpolated.replaceAll("\\$\\{" + propertyName + "\\}", event.getProperty(propertyName).toString());
+        }
+        return interpolated;
     }
 
 }
diff --git a/alerting/alerter/email/src/test/java/org/apache/karaf/decanter/alerting/email/EmailAlerterTest.java
b/alerting/alerter/email/src/test/java/org/apache/karaf/decanter/alerting/email/EmailAlerterTest.java
new file mode 100644
index 0000000..0f6081b
--- /dev/null
+++ b/alerting/alerter/email/src/test/java/org/apache/karaf/decanter/alerting/email/EmailAlerterTest.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.decanter.alerting.email;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+public class EmailAlerterTest {
+
+    @Test
+    public void testInterpolation() throws Exception {
+        String source = "This is ${test} of the ${other} processing";
+        Map<String, Object> data = new HashMap<>();
+        data.put("test", "a test");
+        data.put("other", "interpolation");
+        data.put("not_used", "not_used");
+        Event event = new Event("topic", data);
+        String result = EmailAlerter.interpolation(source, event);
+        Assert.assertEquals("This is a test of the interpolation processing", result);
+    }
+
+    @Test
+    public void testSetSubjectWithEventProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("subject", "Test subject");
+        Event event = new Event("topic", data);
+        emailAlerter.setSubject(message, event);
+        Assert.assertEquals("Test subject", message.getSubject());
+    }
+
+    @Test
+    public void testSetSubjectWithEventInterpolatedProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("subject", "not used subject");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("subject", "Test ${alert} subject");
+        data.put("alert", "alerting");
+        Event event = new Event("topic", data);
+        emailAlerter.setSubject(message, event);
+        Assert.assertEquals("Test alerting subject", message.getSubject());
+    }
+
+    @Test
+    public void testSetSubjectWithComponentProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("subject", "This is my subject");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        Event event = new Event("topic", new HashMap<>());
+        emailAlerter.setSubject(message, event);
+        Assert.assertEquals("This is my subject", message.getSubject());
+    }
+
+    @Test
+    public void testSetSubjectWithComponentInterpolatedProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("subject", "This is my ${my.subject}");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("my.subject", "subject");
+        Event event = new Event("topic", data);
+        emailAlerter.setSubject(message, event);
+        Assert.assertEquals("This is my subject", message.getSubject());
+    }
+
+    @Test
+    public void testSetSubjectFallback() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        Event event = new Event("topic", data);
+        emailAlerter.setSubject(message, event);
+        Assert.assertTrue(message.getSubject().contains("Alert on null"));
+    }
+
+    @Test
+    public void testSetBodyWithEventProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("body", "Test body");
+        Event event = new Event("topic", data);
+        emailAlerter.setBody(message, event);
+        Assert.assertEquals("Test body", message.getContent().toString());
+    }
+
+    @Test
+    public void testSetBodyWithEventInterpolatedProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("body", "not used body");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("body", "Test ${alert} body");
+        data.put("alert", "alerting");
+        Event event = new Event("topic", data);
+        emailAlerter.setBody(message, event);
+        Assert.assertEquals("Test alerting body", message.getContent().toString());
+    }
+
+    @Test
+    public void testSetBodyWithComponentProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("body", "This is the email body");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        Event event = new Event("topic", new HashMap<>());
+        emailAlerter.setBody(message, event);
+        Assert.assertEquals("This is the email body", message.getContent().toString());
+    }
+
+    @Test
+    public void testSetBodyWithComponentInterpolatedProperties() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        componentConfig.put("body", "This is the email ${my.body}");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("my.body", "body");
+        Event event = new Event("topic", data);
+        emailAlerter.setBody(message, event);
+        Assert.assertEquals("This is the email body", message.getContent().toString());
+    }
+
+    @Test
+    public void testSetBodyWithFallback() throws Exception {
+        EmailAlerter emailAlerter = new EmailAlerter();
+        Hashtable<String, Object> componentConfig = new Hashtable<>();
+        componentConfig.put("host", "");
+        componentConfig.put("port", "8888");
+        componentConfig.put("auth", "false");
+        componentConfig.put("starttls", "false");
+        componentConfig.put("ssl", "false");
+        emailAlerter.activate(componentConfig);
+        Properties properties = new Properties();
+        Session session = Session.getDefaultInstance(properties);
+        MimeMessage message = new MimeMessage(session);
+        HashMap<String, Object> data = new HashMap<>();
+        data.put("my.body", "unused");
+        Event event = new Event("topic", data);
+        emailAlerter.setBody(message, event);
+        Assert.assertTrue(message.getContent().toString().contains("out of the pattern"));
+    }
+
+}
diff --git a/manual/src/main/asciidoc/user-guide/alerting.adoc b/manual/src/main/asciidoc/user-guide/alerting.adoc
index 0236cb3..8b02a7e 100644
--- a/manual/src/main/asciidoc/user-guide/alerting.adoc
+++ b/manual/src/main/asciidoc/user-guide/alerting.adoc
@@ -161,6 +161,21 @@ ssl=false
 * the `username` property is optional and specifies the username to connect to the SMTP server
 * the `password` property is optional and specifies the password to connect to the SMTP server
 
+Optionally, you can add:
+
+* `cc` to add email carbon copy
+* `bcc` to add email blind carbon copy
+* `subject` if you want to customize the email subject sent by the alerter
+* `body` if you want to customize the email body sent by the alerter
+* `body.type` if you want to customize the email body type sent by the alerter
+
+The email alerter is also able to use collected data properties.
+
+For instance, `subject` can look like `This is my ${property}` where `${property}` is replaced
by the `property` value.
+
+The email alerter is also able to use collected data properties for subject or body (including
replacement). It looks for
+`body`, `subject`, `alert.email.body`, `alert.email.subject` collected data properties.
+
 ===== Camel
 
 The Decanter Camel alerter sends each alert to a Camel endpoint.


Mime
View raw message