Quellcode durchsuchen

fix #2448 slack notification

Shinsuke Sugaya vor 5 Jahren
Ursprung
Commit
855adb6520

+ 2 - 0
src/main/java/org/codelibs/fess/Constants.java

@@ -136,6 +136,8 @@ public class Constants extends CoreLibConstants {
 
     public static final String NOTIFICATION_TO_PROPERTY = "notification.to";
 
+    public static final String SLACK_WEBHOOK_URLS_PROPERTY = "slack.webhook.urls";
+
     public static final String USE_BROWSER_LOCALE_FOR_SEARCH_PROPERTY = "search.use.browser.locale";
 
     public static final String SUGGEST_SEARCH_LOG_PROPERTY = "suggest.searchlog";

+ 46 - 28
src/main/java/org/codelibs/fess/exec/Crawler.java

@@ -53,6 +53,7 @@ import org.codelibs.fess.exception.ContainerNotAvailableException;
 import org.codelibs.fess.helper.CrawlingInfoHelper;
 import org.codelibs.fess.helper.DataIndexHelper;
 import org.codelibs.fess.helper.DuplicateHostHelper;
+import org.codelibs.fess.helper.NotificationHelper;
 import org.codelibs.fess.helper.PathMappingHelper;
 import org.codelibs.fess.helper.WebFsIndexHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
@@ -60,6 +61,7 @@ import org.codelibs.fess.mylasta.mail.CrawlerPostcard;
 import org.codelibs.fess.timer.SystemMonitorTarget;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.ThreadDumpUtil;
+import org.dbflute.mail.send.hook.SMailCallbackContext;
 import org.elasticsearch.monitor.jvm.JvmInfo;
 import org.elasticsearch.monitor.os.OsProbe;
 import org.elasticsearch.monitor.process.ProcessProbe;
@@ -378,9 +380,7 @@ public class Crawler {
 
     protected void sendMail(final Map<String, String> infoMap) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
-        final String toStrs = fessConfig.getNotificationTo();
-        if (StringUtil.isNotBlank(toStrs)) {
-            final String[] toAddresses = toStrs.split(",");
+        if (fessConfig.hasNotification()) {
             final Map<String, String> dataMap = new HashMap<>();
             for (final Map.Entry<String, String> entry : infoMap.entrySet()) {
                 dataMap.put(StringUtil.decapitalize(entry.getKey()), entry.getValue());
@@ -395,34 +395,52 @@ public class Crawler {
             logger.debug("\ninfoMap: {}\ndataMap: {}", infoMap, dataMap);
 
             final DynamicProperties systemProperties = ComponentUtil.getSystemProperties();
+            final String toStrs = fessConfig.getNotificationTo();
             final Postbox postbox = ComponentUtil.getComponent(Postbox.class);
-            CrawlerPostcard.droppedInto(postbox, postcard -> {
-                postcard.setFrom(fessConfig.getMailFromAddress(), fessConfig.getMailFromName());
-                postcard.addReplyTo(fessConfig.getMailReturnPath());
-                stream(toAddresses).of(stream -> stream.forEach(address -> {
-                    postcard.addTo(address);
-                }));
-                postcard.setCrawlerEndTime(getValueFromMap(dataMap, "crawlerEndTime", StringUtil.EMPTY));
-                postcard.setCrawlerExecTime(getValueFromMap(dataMap, "crawlerExecTime", "0"));
-                postcard.setCrawlerStartTime(getValueFromMap(dataMap, "crawlerStartTime", StringUtil.EMPTY));
-                postcard.setDataCrawlEndTime(getValueFromMap(dataMap, "dataCrawlEndTime", StringUtil.EMPTY));
-                postcard.setDataCrawlExecTime(getValueFromMap(dataMap, "dataCrawlExecTime", "0"));
-                postcard.setDataCrawlStartTime(getValueFromMap(dataMap, "dataCrawlStartTime", StringUtil.EMPTY));
-                postcard.setDataIndexSize(getValueFromMap(dataMap, "dataIndexSize", "0"));
-                postcard.setDataIndexExecTime(getValueFromMap(dataMap, "dataIndexExecTime", "0"));
-                postcard.setHostname(getValueFromMap(dataMap, "hostname", StringUtil.EMPTY));
-                postcard.setWebFsCrawlEndTime(getValueFromMap(dataMap, "webFsCrawlEndTime", StringUtil.EMPTY));
-                postcard.setWebFsCrawlExecTime(getValueFromMap(dataMap, "webFsCrawlExecTime", "0"));
-                postcard.setWebFsCrawlStartTime(getValueFromMap(dataMap, "webFsCrawlStartTime", StringUtil.EMPTY));
-                postcard.setWebFsIndexExecTime(getValueFromMap(dataMap, "webFsIndexExecTime", "0"));
-                postcard.setWebFsIndexSize(getValueFromMap(dataMap, "webFsIndexSize", "0"));
-                if (Constants.TRUE.equalsIgnoreCase(infoMap.get(Constants.CRAWLER_STATUS))) {
-                    postcard.setStatus(Constants.OK);
+            try {
+                final String[] toAddresses;
+                if (StringUtil.isNotBlank(toStrs)) {
+                    toAddresses = toStrs.split(",");
                 } else {
-                    postcard.setStatus(Constants.FAIL);
+                    toAddresses = StringUtil.EMPTY_STRINGS;
                 }
-                postcard.setJobname(systemProperties.getProperty("job.runtime.name", StringUtil.EMPTY));
-            });
+                final NotificationHelper notificationHelper = ComponentUtil.getNotificationHelper();
+                SMailCallbackContext.setPreparedMessageHookOnThread(notificationHelper::send);
+                CrawlerPostcard.droppedInto(postbox, postcard -> {
+                    postcard.setFrom(fessConfig.getMailFromAddress(), fessConfig.getMailFromName());
+                    postcard.addReplyTo(fessConfig.getMailReturnPath());
+                    if (toAddresses.length > 0) {
+                        stream(toAddresses).of(stream -> stream.map(String::trim).forEach(address -> {
+                            postcard.addTo(address);
+                        }));
+                    } else {
+                        postcard.addTo(fessConfig.getMailFromAddress());
+                        postcard.dryrun();
+                    }
+                    postcard.setCrawlerEndTime(getValueFromMap(dataMap, "crawlerEndTime", StringUtil.EMPTY));
+                    postcard.setCrawlerExecTime(getValueFromMap(dataMap, "crawlerExecTime", "0"));
+                    postcard.setCrawlerStartTime(getValueFromMap(dataMap, "crawlerStartTime", StringUtil.EMPTY));
+                    postcard.setDataCrawlEndTime(getValueFromMap(dataMap, "dataCrawlEndTime", StringUtil.EMPTY));
+                    postcard.setDataCrawlExecTime(getValueFromMap(dataMap, "dataCrawlExecTime", "0"));
+                    postcard.setDataCrawlStartTime(getValueFromMap(dataMap, "dataCrawlStartTime", StringUtil.EMPTY));
+                    postcard.setDataIndexSize(getValueFromMap(dataMap, "dataIndexSize", "0"));
+                    postcard.setDataIndexExecTime(getValueFromMap(dataMap, "dataIndexExecTime", "0"));
+                    postcard.setHostname(getValueFromMap(dataMap, "hostname", StringUtil.EMPTY));
+                    postcard.setWebFsCrawlEndTime(getValueFromMap(dataMap, "webFsCrawlEndTime", StringUtil.EMPTY));
+                    postcard.setWebFsCrawlExecTime(getValueFromMap(dataMap, "webFsCrawlExecTime", "0"));
+                    postcard.setWebFsCrawlStartTime(getValueFromMap(dataMap, "webFsCrawlStartTime", StringUtil.EMPTY));
+                    postcard.setWebFsIndexExecTime(getValueFromMap(dataMap, "webFsIndexExecTime", "0"));
+                    postcard.setWebFsIndexSize(getValueFromMap(dataMap, "webFsIndexSize", "0"));
+                    if (Constants.TRUE.equalsIgnoreCase(infoMap.get(Constants.CRAWLER_STATUS))) {
+                        postcard.setStatus(Constants.OK);
+                    } else {
+                        postcard.setStatus(Constants.FAIL);
+                    }
+                    postcard.setJobname(systemProperties.getProperty("job.runtime.name", StringUtil.EMPTY));
+                });
+            } finally {
+                SMailCallbackContext.clearPreparedMessageHookOnThread();
+            }
         }
     }
 

+ 78 - 0
src/main/java/org/codelibs/fess/helper/NotificationHelper.java

@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2020 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.helper;
+
+import java.io.IOException;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.codelibs.core.lang.StringUtil;
+import org.codelibs.core.stream.StreamUtil;
+import org.codelibs.curl.Curl;
+import org.codelibs.curl.CurlResponse;
+import org.codelibs.fess.mylasta.direction.FessConfig;
+import org.codelibs.fess.util.ComponentUtil;
+import org.dbflute.mail.CardView;
+import org.dbflute.mail.send.supplement.SMailPostingDiscloser;
+
+public class NotificationHelper {
+    private static final Logger logger = LogManager.getLogger(NotificationHelper.class);
+
+    protected static final String LF = "\n";
+
+    public void send(final CardView cardView, final SMailPostingDiscloser discloser) {
+        sendToSlack(cardView, discloser);
+    }
+
+    protected void sendToSlack(CardView cardView, SMailPostingDiscloser discloser) {
+        // https://api.slack.com/messaging/webhooks#posting_with_webhooks
+        final FessConfig fessConfig = ComponentUtil.getFessConfig();
+        final String slackWebhookUrls = fessConfig.getSlackWebhookUrls();
+        if (StringUtil.isBlank(slackWebhookUrls)) {
+            return;
+        }
+        final StringBuilder buf = new StringBuilder();
+        final String body =
+                buf.append("{\"text\":\"").append(StringEscapeUtils.escapeJson(toSlackMessage(discloser))).append("\"}").toString();
+        StreamUtil.split(slackWebhookUrls, "[,\\s]").of(
+                stream -> stream.filter(StringUtil::isNotBlank).forEach(
+                        url -> {
+                            try (CurlResponse response = Curl.post(url).header("Content-Type", "application/json").body(body).execute()) {
+                                if (response.getHttpStatusCode() == 200) {
+                                    if (logger.isDebugEnabled()) {
+                                        logger.debug("Sent {} to {}.", body, url);
+                                    }
+                                } else {
+                                    logger.warn("Failed to send {} to {}. HTTP Status is {}. {}", body, url, response.getHttpStatusCode(),
+                                            response.getContentAsString());
+                                }
+                            } catch (final IOException e) {
+                                logger.warn("Failed to send {} to {}.", body, url, e);
+                            }
+                        }));
+    }
+
+    protected String toSlackMessage(final SMailPostingDiscloser discloser) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append(LF).append(discloser.getSavedSubject().orElse(StringUtil.EMPTY).trim());
+        sb.append(LF).append("```");
+        sb.append(LF).append(discloser.getSavedPlainText().orElse(StringUtil.EMPTY).trim());
+        sb.append(LF).append("```");
+        return sb.toString();
+
+    }
+}

+ 24 - 3
src/main/java/org/codelibs/fess/job/PingEsJob.java

@@ -15,15 +15,19 @@
  */
 package org.codelibs.fess.job;
 
+import static org.codelibs.core.stream.StreamUtil.stream;
+
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.codelibs.core.lang.StringUtil;
 import org.codelibs.fess.entity.PingResponse;
 import org.codelibs.fess.es.client.FessEsClient;
+import org.codelibs.fess.helper.NotificationHelper;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.mylasta.mail.EsStatusPostcard;
 import org.codelibs.fess.util.ComponentUtil;
+import org.dbflute.mail.send.hook.SMailCallbackContext;
 import org.lastaflute.core.mail.Postbox;
 
 public class PingEsJob {
@@ -37,23 +41,40 @@ public class PingEsJob {
 
         final StringBuilder resultBuf = new StringBuilder();
 
-        final String notificationTo = fessConfig.getNotificationTo();
         final PingResponse ping = fessEsClient.ping();
         final int status = ping.getStatus();
         if (systemHelper.isChangedClusterState(status)) {
-            if (StringUtil.isNotBlank(notificationTo)) {
+            if (fessConfig.hasNotification()) {
+                final String toStrs = fessConfig.getNotificationTo();
+                final String[] toAddresses;
+                if (StringUtil.isNotBlank(toStrs)) {
+                    toAddresses = toStrs.split(",");
+                } else {
+                    toAddresses = StringUtil.EMPTY_STRINGS;
+                }
                 final Postbox postbox = ComponentUtil.getComponent(Postbox.class);
                 try {
+                    final NotificationHelper notificationHelper = ComponentUtil.getNotificationHelper();
+                    SMailCallbackContext.setPreparedMessageHookOnThread(notificationHelper::send);
                     EsStatusPostcard.droppedInto(postbox, postcard -> {
                         postcard.setFrom(fessConfig.getMailFromAddress(), fessConfig.getMailFromName());
                         postcard.addReplyTo(fessConfig.getMailReturnPath());
-                        postcard.addTo(notificationTo);
+                        if (toAddresses.length > 0) {
+                            stream(toAddresses).of(stream -> stream.map(String::trim).forEach(address -> {
+                                postcard.addTo(address);
+                            }));
+                        } else {
+                            postcard.addTo(fessConfig.getMailFromAddress());
+                            postcard.dryrun();
+                        }
                         postcard.setHostname(systemHelper.getHostname());
                         postcard.setClustername(ping.getClusterName());
                         postcard.setClusterstatus(ping.getClusterStatus());
                     });
                 } catch (final Exception e) {
                     logger.warn("Failed to send a test mail.", e);
+                } finally {
+                    SMailCallbackContext.clearPreparedMessageHookOnThread();
                 }
             }
             resultBuf.append("Status of ").append(ping.getClusterName()).append(" is changed to ").append(ping.getClusterStatus())

+ 12 - 0
src/main/java/org/codelibs/fess/mylasta/direction/FessProp.java

@@ -501,6 +501,18 @@ public interface FessProp {
         return getSystemProperty(Constants.PURGE_BY_BOTS_PROPERTY, Constants.DEFAULT_PURGE_BY_BOTS);
     }
 
+    default boolean hasNotification() {
+        return StringUtil.isNotBlank(getNotificationTo()) || StringUtil.isNotBlank(getSlackWebhookUrls());
+    }
+
+    default void getSlackWebhookUrls(final String value) {
+        setSystemProperty(Constants.SLACK_WEBHOOK_URLS_PROPERTY, value);
+    }
+
+    default String getSlackWebhookUrls() {
+        return getSystemProperty(Constants.SLACK_WEBHOOK_URLS_PROPERTY, StringUtil.EMPTY);
+    }
+
     default void setNotificationTo(final String value) {
         setSystemProperty(Constants.NOTIFICATION_TO_PROPERTY, value);
     }

+ 1 - 2
src/main/java/org/codelibs/fess/mylasta/direction/sponsor/FessMailDeliveryDepartmentCreator.java

@@ -82,7 +82,6 @@ public class FessMailDeliveryDepartmentCreator {
     }
 
     protected SMailDogmaticPostalPersonnel createDogmaticPostalPersonnel() { // #ext_point e.g. locale, database
-        final String testPrefix = fessConfig.getMailSubjectTestPrefix();
         final AsyncManager asyncManager = getAsyncManager();
         final MessageManager messageManager = getMessageManager();
         return new SMailDogmaticPostalPersonnel() {
@@ -96,7 +95,7 @@ public class FessMailDeliveryDepartmentCreator {
 
             @Override
             protected OptionalThing<SMailSubjectFilter> createSubjectFilter() {
-                return OptionalThing.of((view, subject) -> testPrefix + subject);
+                return OptionalThing.of((view, subject) -> subject);
             }
 
             @Override

+ 7 - 0
src/main/java/org/codelibs/fess/util/ComponentUtil.java

@@ -51,6 +51,7 @@ import org.codelibs.fess.helper.JobHelper;
 import org.codelibs.fess.helper.KeyMatchHelper;
 import org.codelibs.fess.helper.LabelTypeHelper;
 import org.codelibs.fess.helper.LanguageHelper;
+import org.codelibs.fess.helper.NotificationHelper;
 import org.codelibs.fess.helper.PathMappingHelper;
 import org.codelibs.fess.helper.PermissionHelper;
 import org.codelibs.fess.helper.PluginHelper;
@@ -93,6 +94,8 @@ public final class ComponentUtil {
 
     private static Map<String, Object> componentMap = new HashMap<>();
 
+    private static final String NOTIFICATION_HELPER = "notificationHelper";
+
     private static final String SEARCH_HELPER = "searchHelper";
 
     private static final String THEME_HELPER = "themeHelper";
@@ -467,6 +470,10 @@ public final class ComponentUtil {
         return getComponent(SEARCH_HELPER);
     }
 
+    public static NotificationHelper getNotificationHelper() {
+        return getComponent(NOTIFICATION_HELPER);
+    }
+
     public static <T> T getComponent(final Class<T> clazz) {
         try {
             return SingletonLaContainer.getComponent(clazz);

+ 2 - 0
src/main/resources/fess.xml

@@ -31,6 +31,8 @@
 	</component>
 	<component name="indexingHelper" class="org.codelibs.fess.helper.IndexingHelper">
 	</component>
+	<component name="notificationHelper" class="org.codelibs.fess.helper.NotificationHelper">
+	</component>
 	<component name="pathMappingHelper" class="org.codelibs.fess.helper.PathMappingHelper">
 	</component>
 	<component name="processHelper" class="org.codelibs.fess.helper.ProcessHelper">