本文基于 Pinpoint 2.1.0 版本 本文大部分内容來自:俠夢的開發筆記 ,但是原文的版本和我的不一緻,放在2.1.0是跑不起來的,但是大概邏輯和思路基本一緻。
目錄
- 一、接入預警大概思路
- 二、具體實作
- 2.1、加入預警子產品
- 2.2、開啟微信預警調用
- 2.3、增加一個 bean 引入配置
- 2.4、配置檔案增加微信預警URL 配置
- 三、實作預警
- 3.1、建立使用者和建立使用者組
- 3.2、建立預警規則
- 四、郵件預警
- 五、預警相關問題和注意事項
- 5.1、告警發送異常,缺少參數
官方預警相關文檔: https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html
在pinpoint 2.X中引入了預設的告警實作類
DefaultAlarmMessageSender
。是以我們隻需要實作短信發送的接口即可。

上述類封裝了發送郵件和短信的方法,目前短信方法的實作仍是空,不過列印了一句話。
logger.info("can not send sms message.");
然而,郵件發送是有一個實作類來幫我們做告警郵件發送的。他就是:SpringSmtpMailSender。
我們接入預警的大概思路就是實作短信發送,然後當短信發送的時候,調用我們寫的子產品,然後實作微信/釘釘預警。 微信釘釘預警都是通過一個接口給到我們進行調用即可。下面我就說說微信預警(釘釘預警一緻)。
我們接入微信預警分為三大塊:
- 加入 微信預警子產品
- 将調用 短信發送改成調用 微信預警
- 增加一個 bean 引入配置
- 配置檔案增加微信預警URL 配置
将這個
Pinpoint2DingTalkSmsSender.java
檔案加入到
/web/src/main/java/com/navercorp/pinpoint/web/alarm
檔案内容如下所示。
package com.navercorp.pinpoint.web.alarm;
import com.navercorp.pinpoint.web.alarm.checker.AlarmChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.StepExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class Pinpoint2DingTalkSmsSender implements SmsSender {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void sendSms(AlarmChecker checker, int sequenceCount, StepExecution stepExecution) {
if(StringUtils.isEmpty(dingTalkUrl)){
logger.warn("web.ding.talk.url is not set!");
return;
}
List smsMessage = checker.getSmsMessage();
String textMsg = String.join("\r\n", smsMessage);
send(textMsg);
}
@Autowired
private RestTemplate restTemplate;
private String dingTalkUrl;
private static String DING_ALARM_PREFIX= "【告警】";
public Pinpoint2DingTalkSmsSender(){
logger.info("init DingTalkSmsSender,{}",dingTalkUrl);
}
public void send(String textMsg){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map map = dingMap(textMsg);
HttpEntity<Map<String, Object>> request = new HttpEntity<Map<String, Object>>(map, headers);
ResponseEntity<DingResponse> responseEntity = restTemplate.postForEntity(dingTalkUrl, request, DingResponse.class);
DingResponse dingResponse = Optional.ofNullable(responseEntity).map(ResponseEntity::getBody).orElse(null);
logger.info("send alarm msg: {},dingtalk result: {} ",map,dingResponse);
}
public static Map dingMap(String message){
Map textMap = new HashMap();
textMap.put("content",DING_ALARM_PREFIX + message);
Map result = new HashMap();
result.put("msgtype","text");
result.put("text",textMap);
return result;
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getDingTalkUrl() {
return dingTalkUrl;
}
public void setDingTalkUrl(String dingTalkUrl) {
this.dingTalkUrl = dingTalkUrl;
}
static class DingResponse{
private int errcode;
private String errmsg;
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
@Override
public String toString() {
return "DingResponse{" +
"errcode=" + errcode +
", errmsg='" + errmsg + '\'' +
'}';
}
}
}
web/src/main/java/com/navercorp/pinpoint/web/alarm/DefaultAlarmMessageSender.java
将調用
EmptySmsSender
注釋。 增加調用
Pinpoint2DingTalkSmsSender
//this.smsSender = smsSender.orElseGet(EmptySmsSender::new);
this.smsSender = smsSender.orElseGet(Pinpoint2DingTalkSmsSender::new);
在
applicationContext-web.xml
中增加一個
bean
<bean id="dingTalkAndWechatMessageSender" class="com.navercorp.pinpoint.web.alarm.Pinpoint2DingTalkSmsSender" >
<property name="dingTalkUrl" value="${web.wechat.alarm.url:}"/>
</bean>
該步驟可以在web容器啟動後,然後進入到容器中編輯配置檔案,然後重新開機 web 容器即可。
pinpoint-web.properties
增加配置
web.wechat.alarm.url=https://oapi.dingtalk.com/robot/send?
預警的是針對不同的應用(服務)來配置,可以設定對應的統計規則,和門檻值,接收預警的隻能是使用者組,不能是使用者, 預警的方式可以選擇 sms 和 email.
補充下預警規則, 預設政策,是每3分鐘統計一次,統計最近5分鐘的資料,這個可以更改,具體更改方式見 :
https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html
見官網 https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html
原因是:我們在配置預警的使用者資訊的時候,并沒有全都配置,雖然有些配置不是必填的,但是我們還是需要都填入則預警資訊發送不出來,并且出現下面的錯誤。
11-18 10:24:00.000 [ scheduler-3] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler -- Unexpected error occurred in scheduled task
java.lang.IllegalStateException: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={schedule.date=1605666240000}. If you want to run this job again, change the parameters.
at com.navercorp.pinpoint.web.batch.JobLaunchSupport.run(JobLaunchSupport.java:52) ~[classes!/:2.1.0]
at com.navercorp.pinpoint.web.batch.BatchJobLauncher.alarmJob(BatchJobLauncher.java:50) ~[classes!/:2.1.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_212]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_212]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) [spring-context-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93) [spring-context-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_212]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_212]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_212]
Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={schedule.date=1605666240000}. If you want to run this job again, change the parameters.
at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:131) ~[spring-batch-core-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_212]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_212]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367) ~[spring-tx-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:181) ~[spring-batch-core-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.7.RELEASE.jar!/:5.2.7.RELEASE]
at com.sun.proxy.$Proxy96.createJobExecution(Unknown Source) ~[?:?]
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:137) ~[spring-batch-core-4.2.4.RELEASE.jar!/:4.2.4.RELEASE]
at com.navercorp.pinpoint.web.batch.JobLaunchSupport.run(JobLaunchSupport.java:50) ~[classes!/:2.1.0]
... 15 more
如果出現上面的報錯會一緻出現,清除的方式,我是進行清除資料庫(慎重)。
作者:理想三旬
出處:
如果覺得文章寫得不錯,或者幫助到您了,請點個贊,加個關注哦。運維學習交流群:544692191
本文版權歸作者所有,歡迎轉載,如果文章有寫的不足的地方,或者是寫得錯誤的地方,請你一定要指出,因為這樣不光是對我寫文章的一種促進,也是一份對後面看此文章的人的責任。謝謝。