惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google DeepMind News
Google DeepMind News
T
Tenable Blog
博客园_首页
S
Securelist
Spread Privacy
Spread Privacy
Google Online Security Blog
Google Online Security Blog
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
U
Unit 42
L
LINUX DO - 热门话题
量子位
T
Threat Research - Cisco Blogs
博客园 - 【当耐特】
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
Martin Fowler
Martin Fowler
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Latest
Security Latest
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
I
InfoQ
Know Your Adversary
Know Your Adversary
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
V2EX - 技术
V2EX - 技术
T
Tailwind CSS Blog
月光博客
月光博客
Recent Announcements
Recent Announcements
G
Google Developers Blog
F
Full Disclosure
W
WeLiveSecurity
宝玉的分享
宝玉的分享
腾讯CDC
G
GRAHAM CLULEY
Vercel News
Vercel News
Simon Willison's Weblog
Simon Willison's Weblog
美团技术团队
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security

博客园 - Doyourself!

rocketmq 启动后 在mq console界面的consumer的Quantity数量显示为0 问题记录 python 切换版本后 提示 无法在python 3.11(.venv)(D:/my_rag_bot/.venv/Scripts/python.exe)设置 python sdk,该sdk似乎无效 记录一次日志告警随着nacos文件动态刷新而失效的问题 多个WebMvcConfigurer配置Jackson2ObjectMapperBuilder不生效问题记录 自定义拦截器不生效问题记录 记录一次nginx能通但是请求一直不了的问题 idea远程连接并本地打包到远程服务器 记一次生产环境内存溢出记录 凤凰架构总结 sentinel接入记录 JVM虚拟机总结 记录一次首页优化的经历 使用sharding-jdbc做分库分表记录 记录一次 maven 子模块相互依赖导致的父模块无法动态升级的问题 'parent.relativePath' points at wrong local POM 雪花算法snowflakeIdWorker使用记录 全局调用链路traceId网关到业务层、feign调用统一问题记录 Spring Cloud 的ribbon的饥饿加载机制 打印mq异常消息记录 根据druid将慢sql通过钉钉的方式进行告警功能记录
使用druid自定义拦截器
Doyourself! · 2023-11-24 · via 博客园 - Doyourself!

         使用druid自定义的拦截器StatFilter,是可以通过日志进行慢sql打印的。但是如果想要把慢sql放入DB,或者通过钉钉告警的方式进行实时打印,则需要实现自定义的拦截器。

         第一步:重新自定义拦截器

package com.example.demo.filter;

@Component
public class SlowSqlTestFilter extends FilterEventAdapter implements StatFilterMBean {

    private static final String IGNORE_SQL = "SELECT 1";

    private static final String INSERT= "insert";
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private BbsDruidSqlDao bbsDruidSqlDao;
    @Resource
    private SlowSqlConfig slowSqlConfig;

    @Override
    protected void statementExecuteBefore(StatementProxy statement, String sql) {
        super.statementExecuteBefore(statement, sql);
        //sql开始执行的时间
        statement.setLastExecuteStartNano();
    }

    @Override
    protected void statementExecuteBatchBefore(StatementProxy statement) {
        super.statementExecuteBatchBefore(statement);
        //sql开始执行的时间
        statement.setLastExecuteTimeNano();
    }

    @Override
    protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) {
        if (IGNORE_SQL.equals(sql) || sql.contains(INSERT)) {
            return;
        }
        if (slowSqlConfig == null) {
            slowSqlConfig = SpringUtil.getBean(SlowSqlConfig.class);
        }
        final long nonNano = System.nanoTime();
        final long lastTime = nonNano - statement.getLastExecuteStartNano();
        long millis = lastTime / (1000 * 1000);
        if (millis >= slowSqlConfig.getSlowSqlMillis()) {
            slowSqlToMysql(statement, sql,millis);
        }

    }


    @Override
    protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {
        super.statementExecuteUpdateBefore(statement, sql);
        statement.setLastExecuteTimeNano();
    }

    @Override
    protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {
        final long nonNano = System.nanoTime();
        final long lastTime = nonNano - statement.getLastExecuteStartNano();
        long millis = lastTime / (1000 * 1000);
        if (millis >= slowSqlConfig.getSlowSqlMillis()) {
            slowSqlToMysql(statement, sql,millis);
        }
    }

    @Override
    protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
        super.statementExecuteQueryBefore(statement, sql);
        statement.setLastExecuteStartNano();
    }

    @Override
    protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
        if (IGNORE_SQL.equals(sql)) {
            return;
        }
        final long nonNano = System.nanoTime();
        final long lastTime = nonNano - statement.getLastExecuteStartNano();
        long millis = lastTime / (1000 * 1000);
        if (millis >= slowSqlConfig.getSlowSqlMillis()) {
            slowSqlToMysql(statement, sql,millis);
        }
    }


    @Override
    protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) {
        super.statement_executeErrorAfter(statement, sql, error);
    }

    private void slowSqlToMysql(StatementProxy statement, String sql,Long millis) {
        if (bbsDruidSqlDao == null) {
            bbsDruidSqlDao = SpringUtil.getBean(BbsDruidSqlDao.class);
        }
        String slowParamters = buildSlowParameters(statement);
        logger.info("慢sql语句{},入参:{}", sql, slowParamters);
        BbsDruidSql bbsDruidSql = BbsDruidSql.builder().slowSql(sql).slowSqlParam(slowParamters)
                .createTime(new Date()).updateTime(new Date()).slowSqlTraceid(millis.toString()).build();
        bbsDruidSqlDao.insertSelective(bbsDruidSql);
    }

    protected String buildSlowParameters(StatementProxy statement) {
        JSONWriter out = new JSONWriter();

        out.writeArrayStart();
        for (int i = 0, parametersSize = statement.getParametersSize(); i < parametersSize; ++i) {
            JdbcParameter parameter = statement.getParameter(i);
            if (i != 0) {
                out.writeComma();
            }
            if (parameter == null) {
                continue;
            }

            Object value = parameter.getValue();
            if (value == null) {
                out.writeNull();
            } else if (value instanceof String) {
                String text = (String) value;
                if (text.length() > 100) {
                    out.writeString(text.substring(0, 97) + "...");
                } else {
                    out.writeString(text);
                }
            } else if (value instanceof Number) {
                out.writeObject(value);
            } else if (value instanceof java.util.Date) {
                out.writeObject(value);
            } else if (value instanceof Boolean) {
                out.writeObject(value);
            } else if (value instanceof InputStream) {
                out.writeString("<InputStream>");
            } else if (value instanceof NClob) {
                out.writeString("<NClob>");
            } else if (value instanceof Clob) {
                out.writeString("<Clob>");
            } else if (value instanceof Blob) {
                out.writeString("<Blob>");
            } else {
                out.writeString('<' + value.getClass().getName() + '>');
            }
        }
        out.writeArrayEnd();

        return out.toString();
    }

    @Override
    public boolean isMergeSql() {
        return false;
    }

    @Override
    public void setMergeSql(boolean mergeSql) {

    }

    @Override
    public boolean isLogSlowSql() {
        return false;
    }

    @Override
    public void setLogSlowSql(boolean logSlowSql) {

    }

    @Override
    public String mergeSql(String sql, String dbType) {
        return null;
    }

    @Override
    public long getSlowSqlMillis() {
        return 0;
    }

    @Override
    public void setSlowSqlMillis(long slowSqlMillis) {

    }
}

第二步:把自定义的拦截器放入druid的datasource中

@ConfigurationProperties(prefix = "spring.datasource")
@Bean(initMethod = "init",destroyMethod = "close")
public DruidDataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    //使用自定义拦截器 注意 不能new
    dataSource.setProxyFilters(Collections.singletonList(new SlowSqlTestFilter()));
    //dataSource.setProxyFilters(Collections.singletonList(statGwmFilter()));
    //设置druid的重置间隔
    dataSource.setTimeBetweenLogStatsMillis(60000);
    return dataSource;
}