Fork me on GitHub

Pinpoint 设置微信或者钉钉预警

本文基于 Pinpoint 2.1.0 版本 本文大部分内容来自:侠梦的开发笔记 ,但是原文的版本和我的不一致,放在2.1.0是跑不起来的,但是大概逻辑和思路基本一致。

一、接入预警大概思路

官方预警相关文档: https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html

在pinpoint 2.X中引入了默认的告警实现类DefaultAlarmMessageSender。所以我们只需要实现短信发送的接口即可。

img

上述类封装了发送邮件和短信的方法,目前短信方法的实现仍是空,不过打印了一句话。

 logger.info("can not send sms message.");

然而,邮件发送是有一个实现类来帮我们做告警邮件发送的。他就是:SpringSmtpMailSender。

我们接入预警的大概思路就是实现短信发送,然后当短信发送的时候,调用我们写的模块,然后实现微信/钉钉预警。 微信钉钉预警都是通过一个接口给到我们进行调用即可。下面我就说说微信预警(钉钉预警一致)。

我们接入微信预警分为三大块:

  1. 加入 微信预警模块
  2. 将调用 短信发送改成调用 微信预警
  3. 增加一个 bean 引入配置
  4. 配置文件增加微信预警URL 配置

二、具体实现

2.1、加入预警模块

将这个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 + '\'' +
                    '}';
        }
    }
}

2.2、开启微信预警调用

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);

2.3、增加一个 bean 引入配置

applicationContext-web.xml中增加一个bean

    <bean id="dingTalkAndWechatMessageSender" class="com.navercorp.pinpoint.web.alarm.Pinpoint2DingTalkSmsSender" >
        <property name="dingTalkUrl" value="${web.wechat.alarm.url:}"/>
    </bean>

2.4、配置文件增加微信预警URL 配置

该步骤可以在web容器启动后,然后进入到容器中编辑配置文件,然后重启 web 容器即可。

pinpoint-web.properties 增加配置

web.wechat.alarm.url=https://oapi.dingtalk.com/robot/send?

三、实现预警

3.1、创建用户和创建用户组

image-20201121173811573

3.2、创建预警规则

预警的是针对不同的应用(服务)来配置,可以设置对应的统计规则,和阈值,接收预警的只能是用户组,不能是用户, 预警的方式可以选择 sms 和 email.

补充下预警规则, 默认策略,是每3分钟统计一次,统计最近5分钟的数据,这个可以更改,具体更改方式见 :

https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html

image-20201121174005196

四、邮件预警

见官网 https://pinpoint-apm.github.io/pinpoint/2.1.0/alarm.html

五、预警相关问题和注意事项

5.1、告警发送异常,缺少参数

原因是:我们在配置预警的用户信息的时候,并没有全都配置,虽然有些配置不是必填的,但是我们还是需要都填入则预警信息发送不出来,并且出现下面的错误。

image-20201121173516668

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

如果出现上面的报错会一致出现,清除的方式,我是进行清除数据库(慎重)。

posted @ 2020-11-25 08:46  自由早晚乱余生  阅读(1192)  评论(1编辑  收藏  举报