1,增加一个Druid过滤器
/**
* @Project
* @Description 大事务监控
* @Date 2022/10/1 下午3:52
*/
public class MyDruidTxMonitorFilter extends FilterEventAdapter {
//记录事务状态与事务开启时间
private static final ThreadLocal<Long> TX_BEGIN_TIME = new ThreadLocal<>();
//记录事务过程中执行的sql(保留执行顺序)
private static final ThreadLocal<List<String>> TX_SQL_LIST = new ThreadLocal<List<String>>();
@Override
public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit)
throws SQLException {
super.connection_setAutoCommit(chain, connection, autoCommit);
if (!autoCommit) {
monitorReady();
}
}
@Override
protected void statementExecuteBefore(StatementProxy statement, String sql) {
monitorSql(sql);
}
@Override
protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {
monitorSql(sql);
}
@Override
protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
monitorSql(sql);
}
@Override
public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException {
try {
super.connection_commit(chain, connection);
//提交完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
monitorTransactionTime();
} finally {
monitorRemove();
}
}
@Override
public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException {
try {
super.connection_rollback(chain, connection);
//回滚完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
monitorTransactionTime();
} finally {
monitorRemove();
}
}
@Override
public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savepoint)
throws SQLException {
try {
super.connection_rollback(chain, connection, savepoint);
//回滚完成后清理本次事务的开始时间、执行的sql等线程绑定的内容
monitorTransactionTime();
} finally {
monitorRemove();
}
}
/**
* 监控准备
*/
private void monitorReady() {
try {
if (monitorUnable()) return;
long beginTime = System.currentTimeMillis();
TX_BEGIN_TIME.set(beginTime);
LinkedList<String> list = new LinkedList<>();
list.add("transaction begin time:"+beginTime);
TX_SQL_LIST.set(list);
}catch (Throwable e){
e.printStackTrace();
}
}
/**
* 是否已禁用
* @return
*/
private boolean monitorUnable() {
LongTxMonitor config = SpringUtil.getBean(LongTxMonitor.class);
if (!config.getHealthCheckLongTxEnable()) {
return true;
}
return false;
}
/**
* sql记录
* @param sql
*/
private void monitorSql(String sql) {
try {
if (monitorUnable()) return;
if (TX_BEGIN_TIME.get() != null) {
//只记录开启了事务的sql
TX_SQL_LIST.get().add("current time:"+System.currentTimeMillis()+",");
TX_SQL_LIST.get().add(sql+";");
}
}catch (Throwable e){
e.printStackTrace();
}
}
/**
* 清理
*/
private void monitorRemove() {
try {
if (monitorUnable()) return;
TX_BEGIN_TIME.remove();
TX_SQL_LIST.remove();
}catch (Throwable e){
e.printStackTrace();
}
}
/**
* 监控事务持续时间
*/
private void monitorTransactionTime() {
try {
if (monitorUnable()) return;
//1、计算本次事务持续时间 2、长事务告警(记录本次事务涉及到的sql+记录本次事务的应用层调用栈)
if (TX_BEGIN_TIME.get()!=null) {
long currentTime = System.currentTimeMillis();
long timeCost = currentTime - TX_BEGIN_TIME.get().longValue();
LongTxMonitor config = SpringUtil.getBean(LongTxMonitor.class);
if (config.getHealthCheckLongTxEnable()) {
if (timeCost>=config.getHealthCheckLongTx()) {
//长事务告警
CommonEvent.CommonDto commonDto = new CommonEvent.CommonDto();
commonDto.setEventTime(LocalDateTime.now().toString());
commonDto.setEventType("长事务");
StringBuilder sqls = new StringBuilder("SQL详情:");
TX_SQL_LIST.get().forEach((sql)->{sqls.append(sql);});
commonDto.setArgs(sqls.toString());
commonDto.setTimeCost(timeCost);
commonDto.setLogId(ThreadContext.get(CommonConst.logId));
//获取调用方接口名称和方法
commonDto.setStackTraceElements(HealthCheckUtil.getCurrentTTKThreadTrace());
SpringUtil.getApplicationEventPublisher().publishEvent(new CommonEvent(commonDto));
}
}
}
}catch (Throwable e){
e.printStackTrace();
}
}
}
2,配置拦截器,使其生效
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="proxyFilters">
<list>
<bean id="txMonitor" class="com.xxx.MyDruidTxMonitorFilter" />
</list>
</property>
</bean>
正文完