Skip to content

Commit

Permalink
告警支持钉钉
Browse files Browse the repository at this point in the history
  • Loading branch information
lujiali authored and lujiali committed Dec 20, 2023
1 parent 3f28774 commit 43409a7
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 io.datavines.notification.plugin.dingtalk;

public class DingTalkConstants {

private DingTalkConstants() {
throw new IllegalStateException(DingTalkConstants.class.getName());
}

static final String DING_TALK_MSG_TYPE_TEXT = "text";
static final String DING_TALK_MSG_TYPE_MARKDOWN = "markdown";


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* 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 io.datavines.notification.plugin.dingtalk;

import io.datavines.common.utils.JSONUtils;
import io.datavines.notification.api.entity.SlaNotificationResultRecord;
import io.datavines.notification.api.entity.SlaSenderMessage;
import io.datavines.notification.plugin.dingtalk.entity.ReceiverConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Objects.requireNonNull;

@Slf4j
@EqualsAndHashCode
@Data
public class DingTalkSender {

private String msgType;
private String webHook;
private String keyWord;

private String mustNotNull = " must not be null";

public DingTalkSender(SlaSenderMessage senderMessage) {

String configString = senderMessage.getConfig();
Map<String, String> config = JSONUtils.toMap(configString);

msgType=config.get("msgType");

webHook=config.get("webHook");
requireNonNull(webHook, "dingtalk webHook" + mustNotNull);
keyWord=config.get("keyWord");
requireNonNull(keyWord, "dingtalk keyWord" + mustNotNull);

}

public SlaNotificationResultRecord sendCardMsg(Set<ReceiverConfig> receiverSet, String subject, String message){
SlaNotificationResultRecord result = new SlaNotificationResultRecord();
if (CollectionUtils.isEmpty(receiverSet)) {
return result;
}
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
Set<ReceiverConfig> failToReceivers = new HashSet<>();
for(ReceiverConfig receiverConfig : receiverSet){
try {
String msg = generateMsgJson(subject, message, receiverConfig);
HttpPost httpPost = constructHttpPost(webHook, msg);
CloseableHttpClient httpClient = getDefaultClient();
try {
CloseableHttpResponse response = httpClient.execute(httpPost);
String resp;
try {
HttpEntity entity = response.getEntity();
resp = EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
} finally {
response.close();
}
log.info("Ding Talk send msg :{}, resp: {}", msg, resp);
} finally {
httpClient.close();
}
} catch (Exception e) {
failToReceivers.add(receiverConfig);
log.error("dingtalk send error", e);
}
}

if (!CollectionUtils.isEmpty(failToReceivers)) {
String recordMessage = String.format("send to %s fail", String.join(",", failToReceivers.stream().map(ReceiverConfig::getAtMobiles).collect(Collectors.toList())));
result.setStatus(false);
result.setMessage(recordMessage);
}else{
result.setStatus(true);
}
return result;
}
private String generateMsgJson(String title, String content,ReceiverConfig receiverConfig) {

final String atMobiles = receiverConfig.getAtMobiles();
final String atUserIds = receiverConfig.getAtUserIds();
final Boolean isAtAll = receiverConfig.getIsAtAll();

if (org.apache.commons.lang3.StringUtils.isBlank(msgType)) {
msgType = DingTalkConstants.DING_TALK_MSG_TYPE_TEXT;
}
Map<String, Object> items = new HashMap<>();
items.put("msgtype", msgType);
Map<String, Object> text = new HashMap<>();
items.put(msgType, text);

if (DingTalkConstants.DING_TALK_MSG_TYPE_MARKDOWN.equals(msgType)) {
StringBuilder builder = new StringBuilder(content);
if (org.apache.commons.lang3.StringUtils.isNotBlank(keyWord)) {
builder.append(" ");
builder.append(keyWord);
}
builder.append("\n\n");
if (org.apache.commons.lang3.StringUtils.isNotBlank(atMobiles)) {
Arrays.stream(atMobiles.split(",")).forEach(value -> {
builder.append("@");
builder.append(value);
builder.append(" ");
});
}
if (org.apache.commons.lang3.StringUtils.isNotBlank(atUserIds)) {
Arrays.stream(atUserIds.split(",")).forEach(value -> {
builder.append("@");
builder.append(value);
builder.append(" ");
});
}
byte[] byt = StringUtils.getBytesUtf8(builder.toString());
String txt = StringUtils.newStringUtf8(byt);
text.put("title", title);
text.put("text", txt);
} else {
StringBuilder builder = new StringBuilder(title);
builder.append("\n");
builder.append(content);
if (org.apache.commons.lang3.StringUtils.isNotBlank(keyWord)) {
builder.append(" ");
builder.append(keyWord);
}
byte[] byt = StringUtils.getBytesUtf8(builder.toString());
String txt = StringUtils.newStringUtf8(byt);
text.put("content", txt);
}

Map<String, Object> at = new HashMap<>();

String[] atMobileArray =
org.apache.commons.lang3.StringUtils.isNotBlank(atMobiles) ? atMobiles.split(",")
: new String[0];
String[] atUserArray =
org.apache.commons.lang3.StringUtils.isNotBlank(atUserIds) ? atUserIds.split(",")
: new String[0];
at.put("atMobiles", atMobileArray);
at.put("atUserIds", atUserArray);
at.put("isAtAll", isAtAll);

items.put("at", at);

return JSONUtils.toJsonString(items);

}
private static HttpPost constructHttpPost(String url, String msg) {
HttpPost post = new HttpPost(url);
StringEntity entity = new StringEntity(msg, StandardCharsets.UTF_8);
post.setEntity(entity);
post.addHeader("Content-Type", "application/json; charset=utf-8");
return post;
}

private static CloseableHttpClient getDefaultClient() {
return HttpClients.createDefault();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 io.datavines.notification.plugin.dingtalk.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@Data
@EqualsAndHashCode
@ToString
public class NotificationConfig {

private String receiverType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 io.datavines.notification.plugin.dingtalk.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.util.Objects;

@Data
@EqualsAndHashCode
@ToString
public class ReceiverConfig {

private String atMobiles;

private String atUserIds;

private Boolean isAtAll;

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ReceiverConfig that = (ReceiverConfig) o;
return Objects.equals(atMobiles, that.atMobiles) && isAtAll == that.isAtAll;
}

@Override
public int hashCode() {
return Objects.hash(atMobiles, atUserIds);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dingtalk=io.datavines.notification.plugin.dingtalk.DingTalkSlasHandlerPlugin
2 changes: 2 additions & 0 deletions datavines-notification/datavines-notification-plugins/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
<module>datavines-notification-plugin-email</module>
<module>datavines-notification-plugin-lark</module>
<module>datavines-notification-plugin-wecombot</module>
<module>datavines-notification-plugin-dingtalk</module>

</modules>

<properties>
Expand Down
6 changes: 6 additions & 0 deletions datavines-runner/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>io.datavines</groupId>
<artifactId>datavines-notification-plugin-dingtalk</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>io.datavines</groupId>
<artifactId>datavines-notification-plugin-wecombot</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions datavines-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,11 @@
<artifactId>datavines-notification-plugin-lark</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.datavines</groupId>
<artifactId>datavines-notification-plugin-dingtalk</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>io.datavines</groupId>
Expand Down

0 comments on commit 43409a7

Please sign in to comment.