1.异常类型
在公司使用Canal-Server作为数据同步监听,在同步过程中,会出现各种问题异常,
比如常见一下几种:
1.表结构发生变更,导出BinLog字段对比异常
2.数据库连接失败,账号密码错误, 权限不足等
3.Binlog文件过期或者丢失
2.传统监控手段-ELK
1.应用端按固定格式,把日志写入到log文件中
2.logstash读取日志文件, 写入到ES中
3.通过logstash分析日志,按特定规则配置告警规则,发送钉钉报警
3.轻量级监控手段logback
1.自定义LogDingDingAppende
package com.logtest.appender;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.alibaba.fastjson.JSON;
import com.logtest.appender.endity.DingtalkMessage;
import com.logtest.util.HttpsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class LogDingDingAppender extends UnsynchronizedAppenderBase {
private String pattern = "%leveln%mn%loggern%ex";
private PatternLayout layout;
private String profilesActive = "unknown";
private String dingdingUrl;
private Level nowLevel = Level.ERROR;
private String secret;
private String serverName;
private String excludeThrowableClasses;
public String getProfilesActive() {
return profilesActive;
}
public void setProfilesActive(String profilesActive) {
this.profilesActive = profilesActive;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getPattern() {
return pattern;
}
public PatternLayout getLayout() {
return layout;
}
public void setLayout(PatternLayout layout) {
this.layout = layout;
}
public String getDingdingUrl() {
return dingdingUrl;
}
public void setDingdingUrl(String dingdingUrl) {
this.dingdingUrl = dingdingUrl;
}
public void setLevel(String level) {
this.nowLevel = Level.toLevel(level, Level.ERROR);
}
public void setExcludeThrowableClasses(String excludeThrowableClasses) {
this.excludeThrowableClasses = excludeThrowableClasses;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
@Override
protected void append(LoggingEvent eventObject) {
try {
if (eventObject.getLevel().isGreaterOrEqual(nowLevel)) {
if (excludeThrowableClasses != null && eventObject.getThrowableProxy() != null) {
if (excludeThrowableClasses.contains(eventObject.getThrowableProxy().getClassName())) {
return;
}
}
String toMsg = layout.doLayout(eventObject);
sendMarkDownMsg("Canal-Server监听异常", toMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start() {
//sendStartMsg();
System.out.println("Canal-Server开始监控,应用名:" + getServerName());
PatternLayout patternLayout = new PatternLayout();
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.start();
this.layout = patternLayout;
super.start();
}
public void sendStartMsg() {
String title = "Canal-Server开始监控";
String prefixEnd = " n";
String prefixStart = "####";
String msg = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd;
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(msg);
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
public void sendMarkDownMsg(String title, String msg) {
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(getMarkdown(title, msg));
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
private String getMarkdown(String title, String msg) {
if (StringUtils.isEmpty(msg)) {
return null;
}
String resultStr = "";
//日志格式logback配置%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
String[] msgs = msg.split("\|-\|");
if (msgs.length > 0) {
String prefixEnd = " n";
String prefixStart = "####";
resultStr = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd +
prefixStart + " 类路径:" + msgs[4] + prefixEnd +
prefixStart + " 异常时间:" + msgs[0] + prefixEnd +
prefixStart + " 异常信息:" + msgs[5] + prefixEnd;
}
return resultStr;
}
}
2.配置logback.xml
log-test
%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
*****
ERROR
3.项目所需POM文件
org.springframework.boot
spring-boot-starter-logging
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.58
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-autoconfigure
2.0.1.RELEASE
org.projectlombok
lombok
1.18.16
4.新建SpringBoot项目&测试
package com.logtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class LogTestApplication {
public static void main(String[] args) {
SpringApplication.run(LogTestApplication.class, args);
log.error("测试钉钉日志告警");
}
}
2.logstash读取日志文件, 写入到ES中
3.通过logstash分析日志,按特定规则配置告警规则,发送钉钉报警
3.轻量级监控手段logback
1.自定义LogDingDingAppende
package com.logtest.appender;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.alibaba.fastjson.JSON;
import com.logtest.appender.endity.DingtalkMessage;
import com.logtest.util.HttpsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class LogDingDingAppender extends UnsynchronizedAppenderBase {
private String pattern = "%leveln%mn%loggern%ex";
private PatternLayout layout;
private String profilesActive = "unknown";
private String dingdingUrl;
private Level nowLevel = Level.ERROR;
private String secret;
private String serverName;
private String excludeThrowableClasses;
public String getProfilesActive() {
return profilesActive;
}
public void setProfilesActive(String profilesActive) {
this.profilesActive = profilesActive;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getPattern() {
return pattern;
}
public PatternLayout getLayout() {
return layout;
}
public void setLayout(PatternLayout layout) {
this.layout = layout;
}
public String getDingdingUrl() {
return dingdingUrl;
}
public void setDingdingUrl(String dingdingUrl) {
this.dingdingUrl = dingdingUrl;
}
public void setLevel(String level) {
this.nowLevel = Level.toLevel(level, Level.ERROR);
}
public void setExcludeThrowableClasses(String excludeThrowableClasses) {
this.excludeThrowableClasses = excludeThrowableClasses;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
@Override
protected void append(LoggingEvent eventObject) {
try {
if (eventObject.getLevel().isGreaterOrEqual(nowLevel)) {
if (excludeThrowableClasses != null && eventObject.getThrowableProxy() != null) {
if (excludeThrowableClasses.contains(eventObject.getThrowableProxy().getClassName())) {
return;
}
}
String toMsg = layout.doLayout(eventObject);
sendMarkDownMsg("Canal-Server监听异常", toMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start() {
//sendStartMsg();
System.out.println("Canal-Server开始监控,应用名:" + getServerName());
PatternLayout patternLayout = new PatternLayout();
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.start();
this.layout = patternLayout;
super.start();
}
public void sendStartMsg() {
String title = "Canal-Server开始监控";
String prefixEnd = " n";
String prefixStart = "####";
String msg = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd;
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(msg);
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
public void sendMarkDownMsg(String title, String msg) {
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(getMarkdown(title, msg));
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
private String getMarkdown(String title, String msg) {
if (StringUtils.isEmpty(msg)) {
return null;
}
String resultStr = "";
//日志格式logback配置%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
String[] msgs = msg.split("\|-\|");
if (msgs.length > 0) {
String prefixEnd = " n";
String prefixStart = "####";
resultStr = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd +
prefixStart + " 类路径:" + msgs[4] + prefixEnd +
prefixStart + " 异常时间:" + msgs[0] + prefixEnd +
prefixStart + " 异常信息:" + msgs[5] + prefixEnd;
}
return resultStr;
}
}
2.配置logback.xml
log-test
%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
*****
ERROR
3.项目所需POM文件
org.springframework.boot
spring-boot-starter-logging
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.58
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-autoconfigure
2.0.1.RELEASE
org.projectlombok
lombok
1.18.16
4.新建SpringBoot项目&测试
package com.logtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class LogTestApplication {
public static void main(String[] args) {
SpringApplication.run(LogTestApplication.class, args);
log.error("测试钉钉日志告警");
}
}
3.轻量级监控手段logback
1.自定义LogDingDingAppende
package com.logtest.appender;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.alibaba.fastjson.JSON;
import com.logtest.appender.endity.DingtalkMessage;
import com.logtest.util.HttpsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class LogDingDingAppender extends UnsynchronizedAppenderBase {
private String pattern = "%leveln%mn%loggern%ex";
private PatternLayout layout;
private String profilesActive = "unknown";
private String dingdingUrl;
private Level nowLevel = Level.ERROR;
private String secret;
private String serverName;
private String excludeThrowableClasses;
public String getProfilesActive() {
return profilesActive;
}
public void setProfilesActive(String profilesActive) {
this.profilesActive = profilesActive;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getPattern() {
return pattern;
}
public PatternLayout getLayout() {
return layout;
}
public void setLayout(PatternLayout layout) {
this.layout = layout;
}
public String getDingdingUrl() {
return dingdingUrl;
}
public void setDingdingUrl(String dingdingUrl) {
this.dingdingUrl = dingdingUrl;
}
public void setLevel(String level) {
this.nowLevel = Level.toLevel(level, Level.ERROR);
}
public void setExcludeThrowableClasses(String excludeThrowableClasses) {
this.excludeThrowableClasses = excludeThrowableClasses;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
@Override
protected void append(LoggingEvent eventObject) {
try {
if (eventObject.getLevel().isGreaterOrEqual(nowLevel)) {
if (excludeThrowableClasses != null && eventObject.getThrowableProxy() != null) {
if (excludeThrowableClasses.contains(eventObject.getThrowableProxy().getClassName())) {
return;
}
}
String toMsg = layout.doLayout(eventObject);
sendMarkDownMsg("Canal-Server监听异常", toMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start() {
//sendStartMsg();
System.out.println("Canal-Server开始监控,应用名:" + getServerName());
PatternLayout patternLayout = new PatternLayout();
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.start();
this.layout = patternLayout;
super.start();
}
public void sendStartMsg() {
String title = "Canal-Server开始监控";
String prefixEnd = " n";
String prefixStart = "####";
String msg = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd;
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(msg);
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
public void sendMarkDownMsg(String title, String msg) {
DingtalkMessage message = new DingtalkMessage();
DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown();
markdown.setTitle(title);
markdown.setText(getMarkdown(title, msg));
message.setMarkdown(markdown);
Map header = new HashMap<>();
header.put("Content-Type", "application/json");
String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header);
log.info("钉钉机器人返回:{}" + sendMsgRet);
}
private String getMarkdown(String title, String msg) {
if (StringUtils.isEmpty(msg)) {
return null;
}
String resultStr = "";
//日志格式logback配置%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
String[] msgs = msg.split("\|-\|");
if (msgs.length > 0) {
String prefixEnd = " n";
String prefixStart = "####";
resultStr = "### " + title + prefixEnd +
prefixStart + " 应用名:" + getServerName() + prefixEnd +
prefixStart + " 类路径:" + msgs[4] + prefixEnd +
prefixStart + " 异常时间:" + msgs[0] + prefixEnd +
prefixStart + " 异常信息:" + msgs[5] + prefixEnd;
}
return resultStr;
}
}
2.配置logback.xml
log-test
%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
*****
ERROR
3.项目所需POM文件
org.springframework.boot
spring-boot-starter-logging
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.58
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-autoconfigure
2.0.1.RELEASE
org.projectlombok
lombok
1.18.16
4.新建SpringBoot项目&测试
package com.logtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class LogTestApplication {
public static void main(String[] args) {
SpringApplication.run(LogTestApplication.class, args);
log.error("测试钉钉日志告警");
}
}
package com.logtest.appender; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.PatternLayout; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.UnsynchronizedAppenderBase; import com.alibaba.fastjson.JSON; import com.logtest.appender.endity.DingtalkMessage; import com.logtest.util.HttpsUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import java.util.HashMap; import java.util.Map; @Slf4j public class LogDingDingAppender extends UnsynchronizedAppenderBase{ private String pattern = "%leveln%mn%loggern%ex"; private PatternLayout layout; private String profilesActive = "unknown"; private String dingdingUrl; private Level nowLevel = Level.ERROR; private String secret; private String serverName; private String excludeThrowableClasses; public String getProfilesActive() { return profilesActive; } public void setProfilesActive(String profilesActive) { this.profilesActive = profilesActive; } public void setPattern(String pattern) { this.pattern = pattern; } public String getServerName() { return serverName; } public void setServerName(String serverName) { this.serverName = serverName; } public String getPattern() { return pattern; } public PatternLayout getLayout() { return layout; } public void setLayout(PatternLayout layout) { this.layout = layout; } public String getDingdingUrl() { return dingdingUrl; } public void setDingdingUrl(String dingdingUrl) { this.dingdingUrl = dingdingUrl; } public void setLevel(String level) { this.nowLevel = Level.toLevel(level, Level.ERROR); } public void setExcludeThrowableClasses(String excludeThrowableClasses) { this.excludeThrowableClasses = excludeThrowableClasses; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } @Override protected void append(LoggingEvent eventObject) { try { if (eventObject.getLevel().isGreaterOrEqual(nowLevel)) { if (excludeThrowableClasses != null && eventObject.getThrowableProxy() != null) { if (excludeThrowableClasses.contains(eventObject.getThrowableProxy().getClassName())) { return; } } String toMsg = layout.doLayout(eventObject); sendMarkDownMsg("Canal-Server监听异常", toMsg); } } catch (Exception e) { e.printStackTrace(); } } @Override public void start() { //sendStartMsg(); System.out.println("Canal-Server开始监控,应用名:" + getServerName()); PatternLayout patternLayout = new PatternLayout(); patternLayout.setContext(context); patternLayout.setPattern(getPattern()); patternLayout.start(); this.layout = patternLayout; super.start(); } public void sendStartMsg() { String title = "Canal-Server开始监控"; String prefixEnd = " n"; String prefixStart = "####"; String msg = "### " + title + prefixEnd + prefixStart + " 应用名:" + getServerName() + prefixEnd; DingtalkMessage message = new DingtalkMessage(); DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown(); markdown.setTitle(title); markdown.setText(msg); message.setMarkdown(markdown); Map header = new HashMap<>(); header.put("Content-Type", "application/json"); String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header); log.info("钉钉机器人返回:{}" + sendMsgRet); } public void sendMarkDownMsg(String title, String msg) { DingtalkMessage message = new DingtalkMessage(); DingtalkMessage.Markdown markdown = new DingtalkMessage.Markdown(); markdown.setTitle(title); markdown.setText(getMarkdown(title, msg)); message.setMarkdown(markdown); Map n"; String prefixStart = "####"; resultStr = "### " + title + prefixEnd + prefixStart + " 应用名:" + getServerName() + prefixEnd + prefixStart + " 类路径:" + msgs[4] + prefixEnd + prefixStart + " 异常时间:" + msgs[0] + prefixEnd + prefixStart + " 异常信息:" + msgs[5] + prefixEnd; } return resultStr; } }header = new HashMap<>(); header.put("Content-Type", "application/json"); String sendMsgRet = HttpsUtils.post(dingdingUrl, JSON.toJSONString(message), header); log.info("钉钉机器人返回:{}" + sendMsgRet); } private String getMarkdown(String title, String msg) { if (StringUtils.isEmpty(msg)) { return null; } String resultStr = ""; //日志格式logback配置 %d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n String[] msgs = msg.split("\|-\|"); if (msgs.length > 0) { String prefixEnd = "
2.配置logback.xml
log-test
%d{yyyy-MM-dd HH:mm:ss.SSS}|-|${appName}|-|%thread|-|%level|-|%logger|-|%msg%n
*****
ERROR
3.项目所需POM文件
org.springframework.boot
spring-boot-starter-logging
org.apache.httpcomponents
httpclient
4.5.5
com.alibaba
fastjson
1.2.58
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-autoconfigure
2.0.1.RELEASE
org.projectlombok
lombok
1.18.16
4.新建SpringBoot项目&测试
package com.logtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class LogTestApplication {
public static void main(String[] args) {
SpringApplication.run(LogTestApplication.class, args);
log.error("测试钉钉日志告警");
}
}
org.springframework.boot spring-boot-starter-loggingorg.apache.httpcomponents httpclient4.5.5 com.alibaba fastjson1.2.58 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-testtest org.springframework.boot spring-boot-autoconfigure2.0.1.RELEASE org.projectlombok lombok1.18.16
4.新建SpringBoot项目&测试
package com.logtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication
@Slf4j
public class LogTestApplication {
public static void main(String[] args) {
SpringApplication.run(LogTestApplication.class, args);
log.error("测试钉钉日志告警");
}
}
测试结果如下:
5.项目源码
链接:百度网盘 请输入提取码
提取码:b293



