2511-Druid监控功能的深入使用与配置-如何记录监控数据(基于logback)
Druid的监控很强大,但可惜的是监控数据是存在内存中的,需求就是定时把监控数据记录下来,以日志文件的形式或者数据库入库。
记录两种方式:
- 数据库入库
- logback形式记录
原理(重点)
- 如果仅仅想记录sql的监控,可以自己重写DruidDataSourceStatLogger的log方法,这个方式是Druid记录日志的默认接口,在此略过。
- 使用内部接口,直接获取元数据。

Druid包中有个DruidStatService类,这个是监控的业务类。
其中有个service方法, public String service(String url) ,参数是形如/sql.json的字符串,service方法根据不同的参数,获取不同的监控数据,返回的字符串即已经序列化后的监控数据JSON字符串。
例如,"/basic.json" 就可以获取基础数据,"/weburi.json" 就可以获取URI页面的数据。
利用这个业务接口,即可获取我们想要的监控数据。
使用springboot的定时任务,可以方便的定时执行日志记录。直接上代码。
说明:SyslogService是自定义的业务类,用于持久化日志,可注释掉。
package com.company.project.timetask;
import com.alibaba.druid.stat.DruidStatService;
import com.alibaba.fastjson.JSONObject;
import com.company.project.model.Syslog;
import com.company.project.service.SyslogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 记录Druid的监控信息
*/
@Component
public class DruidLogTask {
private static Logger myLogger = LoggerFactory.getLogger(DruidLogTask.class);
// 获取DruidStatService
private DruidStatService druidStatService = DruidStatService.getInstance();
// 是否是重启后的第一次记录
private boolean isFirstflag = true;
// @Autowired
// private SyslogService syslogService;
// 启动后延迟5秒调用 每5*60*1000即5分钟记录一次
// @Scheduled(initialDelay = 5000, fixedDelay = 300000)
@Scheduled(initialDelay = 5000, fixedDelay = 20000)
@Async// 定时任务异步化 还需在启动类上加@EnableAsync
public void log() throws InterruptedException {
// 首次启动标志
if (isFirstflag) {
myLogger.info("===============已重启,重启时间是{},开始新的记录===============", LocalDateTime.now().toString());
isFirstflag = !isFirstflag;
// Syslog newLog = new Syslog();
// newLog.setLogType("druidLog");
// newLog.setLogBody("检测到重启");
// newLog.setCreatTime(new Date());
// syslogService.save(newLog);
}
JSONObject allResult = new JSONObject(16, true);
// 首页信息
String basicJson = druidStatService.service("/basic.json");
// 数据源
String datasourceJson = druidStatService.service("/datasource.json");
// SQL监控
String sqlJson = druidStatService.service("/sql.json?orderBy=SQL&orderType=desc&page=1&perPageCount=1000000&");
// SQL防火墙
String wallJson = druidStatService.service("/wall.json");
// web应用
String webappJson = druidStatService.service("/webapp.json");
// URI监控
String weburiJson = druidStatService.service("/weburi.json?orderBy=URI&orderType=desc&page=1&perPageCount=1000000&");
// session监控
String websessionJson = druidStatService.service("/websession.json");
// spring监控
String springJson = druidStatService.service("/spring.json");
allResult.put("/basic.json", JSONObject.parseObject(basicJson));
allResult.put("/datasource.json", JSONObject.parseObject(datasourceJson));
allResult.put("/sql.json", JSONObject.parseObject(sqlJson));
allResult.put("/wall.json", JSONObject.parseObject(wallJson));
allResult.put("/webapp.json", JSONObject.parseObject(webappJson));
allResult.put("/weburi.json", JSONObject.parseObject(weburiJson));
allResult.put("/websession.json", JSONObject.parseObject(websessionJson));
allResult.put("/spring.json", JSONObject.parseObject(springJson));
String allResultJsonString = allResult.toJSONString();
myLogger.info("Druid监控定时记录,allResult==={}", allResultJsonString);
// Syslog newLog = new Syslog();
// newLog.setLogType("druidLog");
// newLog.setLogBody(allResultJsonString);
// newLog.setCreatTime(new Date());
// syslogService.save(newLog);
}
}
使用logback记录数据到日志
主要是使用了内置的RollingFileAppender和自定义logger指定类进行记录
核心配置
<!--配置变量-->
<!--文件路径前缀-->
<property name="LOG_HOME_PATH" value="file_logs"/>
<property name="encoder_pattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%thread] [%c{0}:%L] : %msg%n"/>
<property name="maxHistory" value="60"/>
<property name="maxFileSize" value="10MB"/>
<appender name="druidSqlRollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/druid-sql.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--配置druid的SQL日志输出-->
<logger name="druid.sql.Statement" level="DEBUG" additivity="false">
<appender-ref ref="druidSqlRollingFile" />
</logger>
如果文件的写压力比较大,还可以再引用一层异步队列appender,这个AsyncAppender也是logback提供好的。
完整的logback配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--配置变量-->
<!--文件路径前缀-->
<property name="LOG_HOME_PATH" value="file_logs"/>
<property name="encoder_pattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%thread] [%c{0}:%L] : %msg%n"/>
<property name="maxHistory" value="60"/>
<property name="maxFileSize" value="10MB"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE_All" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/level_all.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/level_info.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/level_debug.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/level_error.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="FILE_CONTROLLER_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/controller_log.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="druidSqlRollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/druid-sql.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="druidMonitorRollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME_PATH}/druid-monitor.%d.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${encoder_pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--自定义logback的扩展appender-->
<!-- <appender name="FILE_SELF" class="com.company.project.core.log.MyAppender">
<encoder>
<pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%thread] [%c{0}:%L] : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>-->
<!-- 异步INFO输出 -->
<appender name ="ASYNC_INFO" class= "ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref ="FILE_INFO"/>
</appender>
<!-- 异步输出 -->
<appender name ="ASYNC_CONTROLLER_LOG" class= "ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref ="FILE_CONTROLLER_LOG"/>
</appender>
<!-- 控制台输出日志级别 -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE_All"/>
<appender-ref ref="FILE_DEBUG"/>
<appender-ref ref="ASYNC_INFO"/>
<appender-ref ref="FILE_ERROR"/>
<!--<appender-ref ref="FILE_SELF"/>-->
</root>
<!--配置druid的SQL日志输出-->
<logger name="druid.sql.Statement" level="DEBUG" additivity="false">
<appender-ref ref="druidSqlRollingFile" />
</logger>
<!--配置druid的监控日志输出-->
<!--<logger name="com.company.project.support.druid.MyDruidDataSourceStatLoggerAdapter" level="DEBUG" additivity="false">-->
<!--<appender-ref ref="druidMonitorRollingFile" />-->
<!--</logger>-->
<!--配置定时任务DruidLogTask的监控日志输出-->
<logger name="com.company.project.timetask.DruidLogTask" level="DEBUG" additivity="false">
<appender-ref ref="druidMonitorRollingFile" />
</logger>
<!--配置aop对controller参数日志的监控-->
<logger name="com.company.project.support.aop.ControllerLogAop" level="INFO" additivity="false">
<appender-ref ref="ASYNC_CONTROLLER_LOG" />
</logger>
<!-- <logger name="com.mchange" level="ERROR" /> -->
<logger name="org.springframework" level="ERROR" />
<logger name="org.mybatis" level="ERROR" />
<!-- <logger name="org.apache.activemq" level="ERROR" /> -->
<logger name="java.sql.Connection" level="DEBUG" />
<logger name="java.sql.Statement" level="DEBUG" />
<logger name="java.sql.PreparedStatement" level="DEBUG" />
<logger name="org.springframework.scheduling" level="INFO"/>
<logger name="org.springframework.session" level="INFO"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
<logger name="org.crsh.plugin" level="WARN"/>
<logger name="org.crsh.ssh" level="WARN"/>
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN"/>
<!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
</configuration>
2511-Druid监控功能的深入使用与配置-如何记录监控数据(基于logback)的更多相关文章
- 2509-Druid监控功能的深入使用与配置-基于SpringBoot-完全使用 .properties配置文件
java实现的数据库连接池有很多,c3p0,dbcp等,还有号称速度最快的HikariCP,并且springboot2.0.2版本默认使用的就是HikariCP. 为什么选用Druid呢? - 性能够 ...
- 2510-Druid监控功能的深入使用与配置-基于SpringBoot-完全使用java config的形式
环境 springboot 1.5.9.RELEASE + JDK1.8 配置步骤 分两步,1 配置数据源 2 配置监控 直接上代码 1 配置数据源 package com.company.proje ...
- 【spring boot】15.spring boot项目 采用Druid数据库连接池,并启用druid监控功能
在http://www.cnblogs.com/sxdcgaq8080/p/9039442.html的基础上,来看看spring boot项目中采用Druid连接池. GitHub地址:示例代码 == ...
- 技术杂记-改造具有监控功能的数据库连接池阿里Druid,支持simple-jndi,kettle
kettle内置的jndi管理是simple-jndi,功能确实比较简单,我需要监控kettle性能,druid确实是很不错的选择,但没有提供对应的支持,我改进了druid源码,实现了simple-j ...
- Spring Boot开启Druid数据库监控功能
Druid是一个关系型数据库连接池,它是阿里巴巴的一个开源项目.Druid支持所有JDBC兼容的数据库,包括Oracle.MySQL.Derby.PostgreSQL.SQL Server.H2等.D ...
- spring boot 开启Druid监控功能
1.配置yml spring: datasource: # 数据源基本配置 username: song password: 123456 driver-class-name: com.mysql.j ...
- Druid使用起步—在javaWeb项目中配置监控 连接池
当我们在javaWEB项目中使用到druid来作为我们的连接池的时候,一定不会忘了添加监控功能.下面我们就来看一下,在一个简单的web项目中(尚未使用任何框架)我们是如果来配置我们的web.xml来完 ...
- 手把手教你搭建LyncServer2013之部署及配置监控功能(十八)
自弃用监控服务器角色以来,已对 Microsoft Lync Server 2013 监控基础结构进行了重大更改.不再采用不同的监控服务器角色(通常需要组织设置专用计算机来充当监控服务器),现在监控服 ...
- spring boot集成websocket实现聊天功能和监控功能
本文参考了这位兄台的文章: https://blog.csdn.net/ffj0721/article/details/82630134 项目源码url: https://github.com/zhz ...
随机推荐
- DOM 事件与事件委托
DOM 事件与事件委托 本文写于 2020 年 5 月 28 日 先思考一个问题:我们如何给一百个 button 添加点击事件? 遍历? 那岂不是要添加一百个监听器? 这就需要事件委托了. 其实这根本 ...
- 聊一聊 HBase 是如何写入数据的?
hi,大家好,我是大D.今天继续了解下 HBase 是如何写入数据的,然后再讲解一下一个比较经典的面试题. Region Server 寻址 HBase Client 访问 ZooKeeper: 获取 ...
- ID为XXXX的进程当前未运行
项目文件夹下,有个.vs的文件夹,删除掉,然后重新打开项目就ok了. 或者: 在启动项目根目录下用文本编辑器打开Web项目下的{X}.csproj文件,然后查找 <WebProjectPrope ...
- consul系列文章02---替换掉.netcore的配置文件
如果是开发微服务的项目,多个服务的配置管理起来比较麻烦,需要集中管理,也就是需要有配置中心: consul集成配置中心的思路:读取配置文件时不在从本地的应用中读取,而是从consul的KEY/valu ...
- 学学dotnet core中的身份验证和授权-1-概念
前言 身份验证: Authentication 授权: Authorization net core 中的身份验证和授权这两个部分,是相辅相成的.当初我在学在部分的时候,是看的 net core 官网 ...
- GraphX 图计算实践之模式匹配抽取特定子图
本文首发于 Nebula Graph Community 公众号 前言 Nebula Graph 本身提供了高性能的 OLTP 查询可以较好地实现各种实时的查询场景,同时它也提供了基于 Spark G ...
- PostgreSQL Array 数组类型与 FreeSql 打出一套【组合拳】
前言 PostgreSQL 是世界公认的功能最强大的开源数据库,除了基础数据类型 int4/int8/varchar/numeric/timestamp 等数据类型,还支持 int4[]/int8[] ...
- Dev C++编写C/C++程序 出现[Error] ld returned 1 exit status报错分析及解决
debug系列第一弹,不知道大家写程序的时候是不是都遇到过如题的报错. 我本人是经常遇到这行熟悉的令人不知所措的报错,可能是我太笨了 有时候百度无果也差不到原因,那就汇总一下目前我遇到的情况吧--持续 ...
- MySQL-常用数据库操作SQL汇总
更新记录 2022年6月15日 发布. 2022年6月11日 将笔记迁移到博客中. 连接与字符设置 设置连接字符类型 SET CHARACTER SET 'utf8'; 或者 SET NAMES ut ...
- 【Azure 应用服务】App Service 开启了私有终结点(Private Endpoint)模式后,如何来实现公网Git部署呢?
问题描述 因为中国区的App Service对外(公网访问)需要进行ICP备案,所以很多情况下,Web应用部署到App Service后,都是通过Application Gateway(应用程序网关) ...