PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/graylog2-server/src/main/java/org/graylog2/alerts/StaticEmailAlertSender.java

http://github.com/Graylog2/graylog2-server
Java | 260 lines | 196 code | 43 blank | 21 comment | 39 complexity | 0ac80e214ee347a98197f0a3ec6ebaec MD5 | raw file
Possible License(s): GPL-3.0
  1. /**
  2. * This file is part of Graylog.
  3. *
  4. * Graylog is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * Graylog is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with Graylog. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. package org.graylog2.alerts;
  18. import com.google.common.base.Splitter;
  19. import com.google.common.base.Strings;
  20. import com.google.common.collect.ImmutableSet;
  21. import org.apache.commons.mail.DefaultAuthenticator;
  22. import org.apache.commons.mail.Email;
  23. import org.apache.commons.mail.EmailConstants;
  24. import org.apache.commons.mail.EmailException;
  25. import org.apache.commons.mail.SimpleEmail;
  26. import org.graylog2.configuration.EmailConfiguration;
  27. import org.graylog2.database.NotFoundException;
  28. import org.graylog2.notifications.Notification;
  29. import org.graylog2.notifications.NotificationService;
  30. import org.graylog2.plugin.Message;
  31. import org.graylog2.plugin.Tools;
  32. import org.graylog2.plugin.alarms.AlertCondition;
  33. import org.graylog2.plugin.alarms.transports.TransportConfigurationException;
  34. import org.graylog2.plugin.configuration.Configuration;
  35. import org.graylog2.plugin.database.users.User;
  36. import org.graylog2.plugin.streams.Stream;
  37. import org.graylog2.plugin.system.NodeId;
  38. import org.graylog2.shared.users.UserService;
  39. import org.graylog2.streams.StreamRuleService;
  40. import org.joda.time.DateTime;
  41. import org.slf4j.Logger;
  42. import org.slf4j.LoggerFactory;
  43. import javax.inject.Inject;
  44. import java.net.URI;
  45. import java.util.List;
  46. import java.util.Set;
  47. import static com.google.common.base.Strings.isNullOrEmpty;
  48. public class StaticEmailAlertSender implements AlertSender {
  49. private static final Logger LOG = LoggerFactory.getLogger(StaticEmailAlertSender.class);
  50. private final StreamRuleService streamRuleService;
  51. protected final EmailConfiguration configuration;
  52. private final UserService userService;
  53. private final NotificationService notificationService;
  54. private final NodeId nodeId;
  55. private Configuration pluginConfig;
  56. @Inject
  57. public StaticEmailAlertSender(EmailConfiguration configuration,
  58. StreamRuleService streamRuleService,
  59. UserService userService,
  60. NotificationService notificationService,
  61. NodeId nodeId) {
  62. this.configuration = configuration;
  63. this.streamRuleService = streamRuleService;
  64. this.userService = userService;
  65. this.notificationService = notificationService;
  66. this.nodeId = nodeId;
  67. }
  68. @Override
  69. public void initialize(org.graylog2.plugin.configuration.Configuration configuration) {
  70. this.pluginConfig = configuration;
  71. }
  72. @Override
  73. public void sendEmails(Stream stream, AlertCondition.CheckResult checkResult) throws TransportConfigurationException, EmailException {
  74. sendEmails(stream, checkResult, null);
  75. }
  76. private void sendEmail(String emailAddress, Stream stream, AlertCondition.CheckResult checkResult, List<Message> backlog) throws TransportConfigurationException, EmailException {
  77. LOG.debug("Sending mail to " + emailAddress);
  78. if(!configuration.isEnabled()) {
  79. throw new TransportConfigurationException("Email transport is not enabled in server configuration file!");
  80. }
  81. final Email email = new SimpleEmail();
  82. email.setCharset(EmailConstants.UTF_8);
  83. if (Strings.isNullOrEmpty(configuration.getHostname())) {
  84. throw new TransportConfigurationException("No hostname configured for email transport while trying to send alert email!");
  85. } else {
  86. email.setHostName(configuration.getHostname());
  87. }
  88. email.setSmtpPort(configuration.getPort());
  89. if (configuration.isUseSsl()) {
  90. email.setSslSmtpPort(Integer.toString(configuration.getPort()));
  91. }
  92. if(configuration.isUseAuth()) {
  93. email.setAuthenticator(new DefaultAuthenticator(
  94. Strings.nullToEmpty(configuration.getUsername()),
  95. Strings.nullToEmpty(configuration.getPassword())
  96. ));
  97. }
  98. email.setSSLOnConnect(configuration.isUseSsl());
  99. email.setStartTLSEnabled(configuration.isUseTls());
  100. if (pluginConfig != null && !Strings.isNullOrEmpty(pluginConfig.getString("sender"))) {
  101. email.setFrom(pluginConfig.getString("sender"));
  102. } else {
  103. email.setFrom(configuration.getFromEmail());
  104. }
  105. email.setSubject(buildSubject(stream, checkResult, backlog));
  106. email.setMsg(buildBody(stream, checkResult, backlog));
  107. email.addTo(emailAddress);
  108. email.send();
  109. }
  110. protected String buildSubject(Stream stream, AlertCondition.CheckResult checkResult, List<Message> backlog) {
  111. StringBuilder sb = new StringBuilder();
  112. final String subjectPrefix = configuration.getSubjectPrefix();
  113. if (!isNullOrEmpty(subjectPrefix)) {
  114. sb.append(subjectPrefix).append(" ");
  115. }
  116. sb.append("Graylog alert for stream: ").append(stream.getTitle());
  117. return sb.toString();
  118. }
  119. protected String buildBody(Stream stream, AlertCondition.CheckResult checkResult, List<Message> backlog) {
  120. StringBuilder sb = new StringBuilder();
  121. sb.append(checkResult.getResultDescription());
  122. sb.append("\n\n");
  123. sb.append("##########\n");
  124. sb.append("Date: ").append(Tools.nowUTC().toString()).append("\n");
  125. sb.append("Stream ID: ").append(stream.getId()).append("\n");
  126. sb.append("Stream title: ").append(stream.getTitle()).append("\n");
  127. sb.append("Stream URL: ").append(buildStreamDetailsURL(configuration.getWebInterfaceUri(), checkResult, stream)).append("\n");
  128. try {
  129. sb.append("Stream rules: ").append(streamRuleService.loadForStream(stream)).append("\n");
  130. } catch (NotFoundException e) {
  131. LOG.error("Unable to find stream rules for stream: " + stream.getId(), e);
  132. }
  133. sb.append("Alert triggered at: ").append(checkResult.getTriggeredAt()).append("\n");
  134. sb.append("Triggered condition: ").append(checkResult.getTriggeredCondition()).append("\n");
  135. sb.append("##########");
  136. if (backlog != null) {
  137. sb.append(buildBacklogSummary(backlog));
  138. }
  139. return sb.toString();
  140. }
  141. protected String buildStreamDetailsURL(URI baseUri, AlertCondition.CheckResult checkResult, Stream stream) {
  142. // Return an informational message if the web interface URL hasn't been set
  143. if (baseUri == null || isNullOrEmpty(baseUri.getHost())) {
  144. return "Please configure 'transport_email_web_interface_url' in your Graylog configuration file.";
  145. }
  146. int time = 5;
  147. if (checkResult.getTriggeredCondition().getParameters().get("time") != null) {
  148. time = (int) checkResult.getTriggeredCondition().getParameters().get("time");
  149. }
  150. DateTime dateAlertEnd = checkResult.getTriggeredAt();
  151. DateTime dateAlertStart = dateAlertEnd.minusMinutes(time);
  152. String alertStart = Tools.getISO8601String(dateAlertStart);
  153. String alertEnd = Tools.getISO8601String(dateAlertEnd);
  154. return baseUri + "/streams/" + stream.getId() + "/messages?rangetype=absolute&from=" + alertStart + "&to=" + alertEnd + "&q=*";
  155. }
  156. protected String buildBacklogSummary(List<Message> backlog) {
  157. if (backlog == null || backlog.isEmpty())
  158. return "";
  159. final StringBuilder sb = new StringBuilder();
  160. MessageFormatter messageFormatter = new MessageFormatter();
  161. sb.append("\n\nLast ");
  162. if (backlog.size() > 1)
  163. sb.append(backlog.size()).append(" relevant messages:\n");
  164. else
  165. sb.append("relevant message:\n");
  166. sb.append("======================\n\n");
  167. for (final Message message : backlog) {
  168. sb.append(messageFormatter.formatForMail(message));
  169. sb.append("\n");
  170. }
  171. return sb.toString();
  172. }
  173. @Override
  174. public void sendEmails(Stream stream, AlertCondition.CheckResult checkResult, List<Message> backlog) throws TransportConfigurationException, EmailException {
  175. if(!configuration.isEnabled()) {
  176. throw new TransportConfigurationException("Email transport is not enabled in server configuration file!");
  177. }
  178. if (stream.getAlertReceivers() == null || stream.getAlertReceivers().isEmpty()) {
  179. throw new RuntimeException("Stream [" + stream + "] has no alert receivers.");
  180. }
  181. final ImmutableSet.Builder<String> recipientsBuilder = ImmutableSet.builder();
  182. // Send emails to subscribed users.
  183. final List<String> userNames = stream.getAlertReceivers().get("users");
  184. if(userNames != null) {
  185. for (String username : userNames) {
  186. final User user = userService.load(username);
  187. if(user != null && !isNullOrEmpty(user.getEmail())) {
  188. // LDAP users might have multiple email addresses defined.
  189. // See: https://github.com/Graylog2/graylog2-server/issues/1439
  190. final Iterable<String> addresses = Splitter.on(",").omitEmptyStrings().trimResults().split(user.getEmail());
  191. recipientsBuilder.addAll(addresses);
  192. }
  193. }
  194. }
  195. // Send emails to directly subscribed email addresses.
  196. if(stream.getAlertReceivers().get("emails") != null) {
  197. for (String email : stream.getAlertReceivers().get("emails")) {
  198. if(!email.isEmpty()) {
  199. recipientsBuilder.add(email);
  200. }
  201. }
  202. }
  203. final Set<String> recipients = recipientsBuilder.build();
  204. if (recipients.size() == 0) {
  205. final Notification notification = notificationService.buildNow()
  206. .addNode(nodeId.toString())
  207. .addType(Notification.Type.GENERIC)
  208. .addSeverity(Notification.Severity.NORMAL)
  209. .addDetail("title", "Stream \"" + stream.getTitle() + "\" is alerted, but no recipients have been defined!")
  210. .addDetail("description", "To fix this, go to the alerting configuration of the stream and add at least one alert recipient.");
  211. notificationService.publishIfFirst(notification);
  212. }
  213. for (String email : recipients) {
  214. sendEmail(email, stream, checkResult, backlog);
  215. }
  216. }
  217. }