- 背景介绍
- sql语句打印
- filter配置
- log4j2 配置
- druid的监控功能
- 参考
背景介绍
前一段时间看了一篇打印sql语句的分享,如下:Jfinal中使用日志框架输出完整sql语句信息
该文章中使用额外的jar包进行sql语句打印,
<dependency>
<groupId>com.googlecode.log4jdbc</groupId>
<artifactId>log4jdbc</artifactId>
<version>1.2</version>
</dependency>
但是因为日志框架的问题无法使用,谁知柳暗花明又一村,让我发现了druid
,druid
能做的事情更多,除了打印sql外还能监控,统计.druid常见问题
本文整理了druid的sql语句打印,监控统计功能的配置
sql语句打印
filter配置
druid使用了拦截过滤器模式,只要配置相应Filter的即可,代码如下
/**
* @return 配置完善的DruidPlugin
*/
public static DruidPlugin createDruidPlugin() {
// 从配置文件中读取数据库url,username,password
String name = Const.devProfile.getName();
String url = prop.get(name + ".db.url");
String username = prop.get(name + ".db.username");
String password = prop.get(name + ".db.password").trim();
DruidPlugin dp = new DruidPlugin(url, username, password);
// 添加数据库插件
// 1.统计信息插件
StatFilter statFilter = new StatFilter();
statFilter.setMergeSql(true);
statFilter.setLogSlowSql(true);
// 慢查询目前设置为1s,随着优化一步步进行慢慢更改
statFilter.setSlowSqlMillis(Duration.ofMillis(1000).toMillis());
dp.addFilter(statFilter);
// 2.日志插件
// 保存DruidDataSource的监控记录,设置打印日志周期,默认使用DruidDataSourceStatLoggerImpl
// DruidPlugin未暴露setTimeBetweenLogStatsMillis(),只能使用properties方法设置
dp.setConnectionProperties("druid.timeBetweenLogStatsMillis="
+ Duration.ofHours(24).toMillis());
Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
slf4jLogFilter.setDataSourceLogEnabled(false);
slf4jLogFilter.setConnectionLogEnabled(false);
slf4jLogFilter.setConnectionLogErrorEnabled(true);
slf4jLogFilter.setStatementLogEnabled(false);
slf4jLogFilter.setStatementLogErrorEnabled(true);
slf4jLogFilter.setResultSetLogEnabled(false);
slf4jLogFilter.setResultSetLogErrorEnabled(true);
slf4jLogFilter.setConnectionConnectBeforeLogEnabled(false);
slf4jLogFilter.setConnectionConnectAfterLogEnabled(false);
slf4jLogFilter.setConnectionCommitAfterLogEnabled(false);
slf4jLogFilter.setConnectionRollbackAfterLogEnabled(true);
slf4jLogFilter.setConnectionCloseAfterLogEnabled(false);
slf4jLogFilter.setStatementCreateAfterLogEnabled(false);
slf4jLogFilter.setStatementPrepareAfterLogEnabled(false);
slf4jLogFilter.setStatementPrepareCallAfterLogEnabled(false);
slf4jLogFilter.setStatementExecuteAfterLogEnabled(false);
slf4jLogFilter.setStatementExecuteQueryAfterLogEnabled(false);
slf4jLogFilter.setStatementExecuteUpdateAfterLogEnabled(false);
slf4jLogFilter.setStatementExecuteBatchAfterLogEnabled(false);
slf4jLogFilter.setStatementCloseAfterLogEnabled(false);
slf4jLogFilter.setStatementParameterSetLogEnabled(false);
slf4jLogFilter.setResultSetNextAfterLogEnabled(false);
slf4jLogFilter.setResultSetOpenAfterLogEnabled(false);
slf4jLogFilter.setResultSetCloseAfterLogEnabled(false);
if (Const.devProfile == Const.DevProfile.LOCAL_DEV
|| Const.devProfile == Const.DevProfile.LOCAL_TEST) {
slf4jLogFilter.setStatementExecutableSqlLogEnable(true);
}
dp.addFilter(slf4jLogFilter);
// 3.防注入插件
WallFilter wall = new WallFilter();
wall.setDbType("mysql");
dp.addFilter(wall);
return dp;
}
配置了3个Filter,就是配置Slf4jLogFilter时需要注意哪些需要打印,哪些不需要
log4j2 配置
此外,还要在log4j2中配置日志过滤,我的Logger配置如下
<Loggers>
<!--打印无用日志较多的设置level为info-->
<!--<Logger name="net.sf.ehcache" level="WARN"/>-->
<Logger name="org.apache.shiro.web.servlet.SimpleCookie" level="info"/>
<Logger name="org.apache.shiro" level="info"/>
<!--设置druid日志level为debug-->
<Logger name="druid" level="debug" additivity="false">
<AppenderRef ref="sql"/>
<AppenderRef ref="Console"/>
</Logger>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="debug"/>
<AppenderRef ref="info"/>
<AppenderRef ref="warn"/>
<AppenderRef ref="error"/>
</Root>
</Loggers>
druid的监控功能
druid的监控功能是通过配置servlet和filter实现的,配置如下:
<!--配置Druid的WebStatFilter-->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.app.vocalist.filter.druid.MyWebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
<init-param>
<!--开启session监控-->
<param-name>sessionStatEnable</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!--最大监控session数-->
<param-name>sessionStatMaxCount</param-name>
<param-value>2000</param-value>
</init-param>
<init-param>
<!--principal在session中的属性名-->
<param-name>principalSessionName</param-name>
<param-value>user</param-value>
</init-param>
<init-param>
<!--单条url分析-->
<param-name>profileEnable</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!--Druid内置监控配置-->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<init-param>
<!-- 用户名 -->
<param-name>loginUsername</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<!-- 密码 -->
<param-name>loginPassword</param-name>
<param-value>root</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
注意:
- com.app.vocalist.filter.druid.MyWebStatFilter是我写的继承com.alibaba.druid.support.http.WebStatFilter的一个类,重写了getPrincipal(httpRequest)
- jfinal框架是一个Filter,处理request后不会将其交给后续的servlet,而是直接返回(其实是使用了boolean[] isHandled = {false}作为标志,但是在ActionHandler中会将其设置为true,doFilter()中判断为true就直接返回了)
- 可以在jfinal中设置com.jfinal.plugin.druid.DruidStatViewHandler进行处理,我所有的url格式为/api/*,所以将配置
<filter-mapping>
即可
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>