You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2019/09/27 09:05:47 UTC
[karaf-decanter] branch master updated: [KARAF-6437] Add templating
support in email alerter, including possible properties interpolation
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é <jb...@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.