- 浏览: 555877 次
- 性别:
- 来自: 长沙
文章分类
- 全部博客 (145)
- apache-struts (3)
- apache-shiro (4)
- apache-wicket (1)
- spring (34)
- spring-data-jpa (2)
- spring-mvc (20)
- spring-security (1)
- spring-webflow (1)
- hibernate (2)
- mongodb (1)
- ibatis (5)
- mysql (4)
- 开源组件 (18)
- java (3)
- maven (7)
- jBPM (1)
- EJB (1)
- JMS (2)
- servlet / jsp (9)
- javascript / jquery (10)
- 工作技巧 (12)
- ubuntu (6)
- bootstrap (10)
- javaee (1)
- 他山石 (7)
- jetbrick (1)
最新评论
-
yubao2008:
[size=x-small]为什么我也这样试了, 就是没有生效 ...
javax.servlet.http.HttpServletResponse 得到 status_code -
chenrl:
...
SpringMVC杂记(十五) spring-mvc controller 的切面 -
LONGTENGLONG:
你好,这样配置的,得到的集合为空,是什么原因?
apache-shiro杂记(一) 统计在线用户数目 -
xiafengfeiwu:
[flash=200,200][url]引用[/url][/f ...
apache-shiro 学习笔记 -
3108493554:
你好 ,有些问题想请教下,加下我qq310849354,你这上 ...
SpringMVC杂记(十二) 自定义Interceptor从Active Directory得到域信息
一) logback已经提供了一个DBAppender(ch.qos.logback.classic.db.DBAppender),为何还需自己发明一个轮子?
1.1
ch.qos.logback.classic.db.DBAppender默认只能保存4个参数到数据库里,如下
(slf4j代码)
参数5不能保存在DB中的单独一个字段,这样并不方便。扩展为可以保存32个参数。
1.2
logback默认的DBAppender不方便配置,不能自由指定表名
1.3
logback默认的DBAppender中保存的时间戳为long,阅读时不方便。
二) 代码片段 (仅新的DBAppender类,其他工具类等为节省篇幅不贴出)
三) 配置 (logback.xml片段)
四) 下载安装
这是一个maven项目,源代码已经发布到GitHub
https://github.com/yingzhuo/logback-ext
1.1
ch.qos.logback.classic.db.DBAppender默认只能保存4个参数到数据库里,如下
(slf4j代码)
LOGGER.info("{}{}{}{}{}", 1,2,3,4,5);
参数5不能保存在DB中的单独一个字段,这样并不方便。扩展为可以保存32个参数。
1.2
logback默认的DBAppender不方便配置,不能自由指定表名
1.3
logback默认的DBAppender中保存的时间戳为long,阅读时不方便。
二) 代码片段 (仅新的DBAppender类,其他工具类等为节省篇幅不贴出)
package com.github.yingzhuo.logbackext.db; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import ch.qos.logback.classic.db.DBHelper; import ch.qos.logback.classic.spi.CallerData; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.StackTraceElementProxy; import ch.qos.logback.classic.spi.ThrowableProxyUtil; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.db.DBAppenderBase; import ch.qos.logback.core.db.dialect.SQLDialectCode; import com.github.yingzhuo.logbackext.names.DefaultTableAndColumnNameResolver; import com.github.yingzhuo.logbackext.names.TableAndColumnNameResolver; /** * 参考ch.qos.logback.classic.db.DBAppender * * @author yingzhuo * */ @SuppressWarnings("rawtypes") public class DBAppender extends DBAppenderBase<ILoggingEvent> { private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); private boolean printStackTrace = true; protected String insertPropertiesSQL; protected String insertExceptionSQL; protected String insertSQL; protected static final Method GET_GENERATED_KEYS_METHOD; private TableAndColumnNameResolver nameResolver = new DefaultTableAndColumnNameResolver(); static final int TIMESTMP_INDEX = 1; static final int FORMATTED_MESSAGE_INDEX = 2; static final int LOGGER_NAME_INDEX = 3; static final int LEVEL_STRING_INDEX = 4; static final int THREAD_NAME_INDEX = 5; static final int REFERENCE_FLAG_INDEX = 6; static final int ARG0_INDEX = 7; static final int ARG1_INDEX = 8; static final int ARG2_INDEX = 9; static final int ARG3_INDEX = 10; static final int ARG4_INDEX = 11; static final int ARG5_INDEX = 12; static final int ARG6_INDEX = 13; static final int ARG7_INDEX = 14; static final int ARG8_INDEX = 15; static final int ARG9_INDEX = 16; static final int ARG10_INDEX = 17; static final int ARG11_INDEX = 18; static final int ARG12_INDEX = 19; static final int ARG13_INDEX = 20; static final int ARG14_INDEX = 21; static final int ARG15_INDEX = 22; static final int ARG16_INDEX = 23; static final int ARG17_INDEX = 24; static final int ARG18_INDEX = 25; static final int ARG19_INDEX = 26; static final int ARG20_INDEX = 27; static final int ARG21_INDEX = 28; static final int ARG22_INDEX = 29; static final int ARG23_INDEX = 30; static final int ARG24_INDEX = 31; static final int ARG25_INDEX = 32; static final int ARG26_INDEX = 33; static final int ARG27_INDEX = 34; static final int ARG28_INDEX = 35; static final int ARG29_INDEX = 36; static final int ARG30_INDEX = 37; static final int ARG31_INDEX = 38; static final int CALLER_FILENAME_INDEX = 39; static final int CALLER_CLASS_INDEX = 40; static final int CALLER_METHOD_INDEX = 41; static final int CALLER_LINE_INDEX = 42; static final int EVENT_ID_INDEX = 43; static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance(); static { Method getGeneratedKeysMethod; try { getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null); } catch (Exception ex) { getGeneratedKeysMethod = null; } GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod; } @Override public void start() { insertExceptionSQL = SQLBuilder.buildInsertExceptionSQL(nameResolver); insertPropertiesSQL = SQLBuilder.buildInsertPropertiesSQL(nameResolver); insertSQL = SQLBuilder.buildInsertSQL(nameResolver); System.out.println(insertSQL); super.start(); } @Override protected void subAppend(ILoggingEvent event, Connection connection, PreparedStatement insertStatement) throws Throwable { bindLoggingEventWithInsertStatement(insertStatement, event); bindLoggingEventArgumentsWithPreparedStatement(insertStatement, event.getArgumentArray()); bindCallerDataWithPreparedStatement(insertStatement, event.getCallerData()); int updateCount = 0; try { updateCount = insertStatement.executeUpdate(); } catch (Exception e) { if (this.printStackTrace) { e.printStackTrace(); } throw e; } if (updateCount != 1) { addWarn("Failed to insert loggingEvent"); } } protected void secondarySubAppend(ILoggingEvent event, Connection connection, long eventId) throws Throwable { Map<String, String> mergedMap = mergePropertyMaps(event); insertProperties(mergedMap, connection, eventId); if (event.getThrowableProxy() != null) { insertThrowable(event.getThrowableProxy(), connection, eventId); } } void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException { stmt.setString(TIMESTMP_INDEX, DATE_FORMAT.format(new Date(event.getTimeStamp()))); stmt.setString(FORMATTED_MESSAGE_INDEX, event.getFormattedMessage()); stmt.setString(LOGGER_NAME_INDEX, event.getLoggerName()); stmt.setString(LEVEL_STRING_INDEX, event.getLevel().toString()); stmt.setString(THREAD_NAME_INDEX, event.getThreadName()); stmt.setShort(REFERENCE_FLAG_INDEX, DBHelper.computeReferenceMask(event)); } void bindLoggingEventArgumentsWithPreparedStatement(PreparedStatement stmt, Object[] argArray) throws SQLException { int arrayLen = argArray != null ? argArray.length : 0; for (int i = 0; i < arrayLen && i < 32; i++) { stmt.setString(ARG0_INDEX + i, asStringTruncatedTo254(argArray[i])); } if (arrayLen < 32) { for (int i = arrayLen; i < 32; i++) { stmt.setString(ARG0_INDEX + i, null); } } } String asStringTruncatedTo254(Object o) { String s = null; if (o != null) { s = o.toString(); } if (s == null) { return null; } if (s.length() <= 254) { return s; } else { return s.substring(0, 254); } } void bindCallerDataWithPreparedStatement(PreparedStatement stmt, StackTraceElement[] callerDataArray) throws SQLException { StackTraceElement caller = extractFirstCaller(callerDataArray); stmt.setString(CALLER_FILENAME_INDEX, caller.getFileName()); stmt.setString(CALLER_CLASS_INDEX, caller.getClassName()); stmt.setString(CALLER_METHOD_INDEX, caller.getMethodName()); stmt.setString(CALLER_LINE_INDEX, Integer.toString(caller.getLineNumber())); } private StackTraceElement extractFirstCaller(StackTraceElement[] callerDataArray) { StackTraceElement caller = EMPTY_CALLER_DATA; if (hasAtLeastOneNonNullElement(callerDataArray)) caller = callerDataArray[0]; return caller; } private boolean hasAtLeastOneNonNullElement(StackTraceElement[] callerDataArray) { return callerDataArray != null && callerDataArray.length > 0 && callerDataArray[0] != null; } Map<String, String> mergePropertyMaps(ILoggingEvent event) { Map<String, String> mergedMap = new HashMap<String, String>(); Map<String, String> loggerContextMap = event.getLoggerContextVO().getPropertyMap(); Map<String, String> mdcMap = event.getMDCPropertyMap(); if (loggerContextMap != null) { mergedMap.putAll(loggerContextMap); } if (mdcMap != null) { mergedMap.putAll(mdcMap); } return mergedMap; } @Override protected Method getGeneratedKeysMethod() { return GET_GENERATED_KEYS_METHOD; } @Override protected String getInsertSQL() { return insertSQL; } protected void insertProperties(Map<String, String> mergedMap, Connection connection, long eventId) throws SQLException { Set propertiesKeys = mergedMap.keySet(); if (propertiesKeys.size() > 0) { PreparedStatement insertPropertiesStatement = connection.prepareStatement(insertPropertiesSQL); for (Iterator i = propertiesKeys.iterator(); i.hasNext();) { String key = (String) i.next(); String value = (String) mergedMap.get(key); insertPropertiesStatement.setLong(1, eventId); insertPropertiesStatement.setString(2, key); insertPropertiesStatement.setString(3, value); if (cnxSupportsBatchUpdates) { insertPropertiesStatement.addBatch(); } else { insertPropertiesStatement.execute(); } } if (cnxSupportsBatchUpdates) { insertPropertiesStatement.executeBatch(); } insertPropertiesStatement.close(); } } void updateExceptionStatement(PreparedStatement exceptionStatement, String txt, short i, long eventId) throws SQLException { exceptionStatement.setLong(1, eventId); exceptionStatement.setShort(2, i); exceptionStatement.setString(3, txt); if (cnxSupportsBatchUpdates) { exceptionStatement.addBatch(); } else { exceptionStatement.execute(); } } short buildExceptionStatement(IThrowableProxy tp, short baseIndex, PreparedStatement insertExceptionStatement, long eventId) throws SQLException { StringBuilder buf = new StringBuilder(); ThrowableProxyUtil.subjoinFirstLine(buf, tp); updateExceptionStatement(insertExceptionStatement, buf.toString(), baseIndex++, eventId); int commonFrames = tp.getCommonFrames(); StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray(); for (int i = 0; i < stepArray.length - commonFrames; i++) { StringBuilder sb = new StringBuilder(); sb.append(CoreConstants.TAB); ThrowableProxyUtil.subjoinSTEP(sb, stepArray[i]); updateExceptionStatement(insertExceptionStatement, sb.toString(), baseIndex++, eventId); } if (commonFrames > 0) { StringBuilder sb = new StringBuilder(); sb.append(CoreConstants.TAB).append("... ").append(commonFrames) .append(" common frames omitted"); updateExceptionStatement(insertExceptionStatement, sb.toString(), baseIndex++, eventId); } return baseIndex; } protected void insertThrowable(IThrowableProxy tp, Connection connection, long eventId) throws SQLException { PreparedStatement exceptionStatement = connection.prepareStatement(insertExceptionSQL); short baseIndex = 0; while (tp != null) { baseIndex = buildExceptionStatement(tp, baseIndex, exceptionStatement, eventId); tp = tp.getCause(); } if (cnxSupportsBatchUpdates) { exceptionStatement.executeBatch(); } exceptionStatement.close(); } public boolean isPrintStackTrace() { return printStackTrace; } public void setPrintStackTrace(boolean printStackTrace) { this.printStackTrace = printStackTrace; } public TableAndColumnNameResolver getNameResolver() { return nameResolver; } public void setNameResolver(TableAndColumnNameResolver nameResolver) { this.nameResolver = nameResolver; } @Override public void append(ILoggingEvent eventObject) { Connection connection = null; try { connection = connectionSource.getConnection(); connection.setAutoCommit(false); PreparedStatement insertStatement; if (cnxSupportsGetGeneratedKeys) { String EVENT_ID_COL_NAME = "EVENT_ID"; if (connectionSource.getSQLDialectCode() == SQLDialectCode.POSTGRES_DIALECT) { EVENT_ID_COL_NAME = EVENT_ID_COL_NAME.toLowerCase(); } insertStatement = connection.prepareStatement(getInsertSQL(), new String[] { EVENT_ID_COL_NAME }); } else { insertStatement = connection.prepareStatement(getInsertSQL()); } long eventId; synchronized (this) { subAppend(eventObject, connection, insertStatement); eventId = selectEventId(insertStatement, connection); } secondarySubAppend(eventObject, connection, eventId); insertStatement.close(); connection.commit(); } catch (Throwable sqle) { if (this.printStackTrace) { sqle.printStackTrace(); } addError("problem appending event", sqle); } finally { try { connection.close();} catch (SQLException e) {} } } }
三) 配置 (logback.xml片段)
<appender name="DB" class="com.github.yingzhuo.logbackext.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource"> <driverClass>com.mysql.jdbc.Driver</driverClass> <url>jdbc:mysql://127.0.0.1:3306/logback</url> <user>root</user> <password>root</password> </dataSource> </connectionSource> <nameResolver class="com.github.yingzhuo.logbackext.names.DefaultTableAndColumnNameResolver"> <loggingEventTableName>last</loggingEventTableName> <loggingEventExceptionTableName>last_exception</loggingEventExceptionTableName> <loggingEventPropertyTableName>last_property</loggingEventPropertyTableName> </nameResolver> <printStackTrace>true</printStackTrace> </appender>
四) 下载安装
这是一个maven项目,源代码已经发布到GitHub
https://github.com/yingzhuo/logback-ext
发表评论
-
Java生成缩略图之Thumbnailator(转载)
2013-07-15 21:19 2726Java生成缩略图之Thumbnailator(转载) 原文 ... -
pinyin4j 的应用
2013-05-12 08:59 1241<!-- pinyin4j --> < ... -
二维条形码的生成与解析
2013-05-02 11:58 2608二维条形码的生成与解 ... -
memcached学习笔记(二) 使用memcached java客户端
2012-07-11 11:51 13951) 了解了一下 memcached 客户端常见的有两种 sp ... -
memcached学习笔记(一) instanll memcached on windows machine
2012-07-11 10:44 15721) 下载 http://code.jellycan.com/ ... -
Zip 压缩和解压缩
2011-12-31 14:17 1666要依赖 ant.1.7.0.jar <depend ... -
Log4j RollingFileAppender和DailyRollingFileAppender杂交
2011-12-16 15:13 3881package org.apache.log4j; ... -
BoneCP
2011-11-07 10:39 27011) BoneCP加入工程 <dependency& ... -
Quartz 任务调度器
2011-05-04 15:33 1813字段允许值允许的特殊 ... -
commons-email笔记
2011-04-15 11:59 1636使用Apache Commons-email发送电子邮件 所 ... -
commons-digest笔记
2011-04-12 11:09 1390本文为转载且为截取的片段,如有需要请访问原帖 待解析的xml ... -
json-taglib
2011-03-29 14:53 1747JSON-taglib是一套JSP标签库用于在JSP代码中输出 ... -
JSR-303
2011-03-21 15:45 12009JSR-303 是JAVA EE 6 中的一项子规范,叫做Be ... -
JUnit如何使用
2011-02-17 13:34 4765一,Junit4是Junit框架有 ... -
Apache-dom4j的使用(二)
2011-02-11 15:57 2016本小节讲如何使用dom4j解析一个xml文件 以读取book ... -
Apache-dom4j的使用(一)
2011-02-11 14:15 1314本节主要介绍如何用dom4j生成一个xml文档 <? ... -
log4j的xml配置方式
2011-01-15 07:33 1583一,原来一贯用的properties配置文件 log4j.pr ...
相关推荐
扩展logback将日志输出到Kafka实例扩展源码,详情参见博文:http://blog.csdn.net/l1028386804/article/details/79136841
扩展logback将日志输出到Kafka实例源码,详情请参见博文:http://blog.csdn.net/l1028386804/article/details/79135948
登录扩展 Logback日志库的扩展主要适用于针对Amazon Web Services的附加程序,包括CloudWatch Logs,DynamoDB,Kinesis,SNS和SQS附加程序。 还包含基于LMAX Disrupotr的高性能异步附加器和某些实用程序,例如...
几乎是网上 能找到的 日志脱敏的所有实现 1、基于正则表达式的 日志脱敏实现 ,扩展logback 、log4j 2、springmvc 返回报文脱敏。 3、基于注解方式的脱敏。 大家选择使用。
spring使用logback的扩展,使用起来非常方便。在web.xml中配置: <param-name>logbackConfigLocation <param-value>/WEB-INF/conf/logback.xml <listener-class>ch.qos.logback.ext.spring.web....
该压缩包包含 logback类库所包含的jar包以及logback.xml配置文件(放到 src 目录),用于开发学习使用。
内置三个jar包 一个配置文件 logback.txt logback-classic-1.2.3.jar logback-core-1.2.3.jar slf4j-api-1.7.26.jar
Slf4j+logback实现logback测试,Slf4j+logback实现logback测试
此zip包含logback-access-1.2.3和logback-classic-1.2.3和logback-core-1.2.3
赠送jar包:logback-core-1.2.10.jar; 赠送原API文档:logback-core-1.2.10-javadoc.jar; 赠送源代码:logback-core-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.10.pom; 包含翻译后的API文档...
slf4j-api-1.7.26.jar logback-core-1.2.3.jar logback-classic-1.2.3.jar logback.xml
日志组件logback jar包,logback-access-1.1.3.jar logback-classic-1.1.3.jar logback-core-1.1.3.jar slf4j-api-1.7.12.jar
logback与spring集成的文件,从官网上找的。上传的文件包括源文件和jar包,以下是连接: https://github.com/qos-ch/logback-extensions/wiki/Spring ...
包含logback所需:logback-classic-1.1.7.jar、logback-classic-1.1.7-sources.jar、logback-core-1.1.7.jar、logback-core-1.1.7-sources.jar、slf4j-api-1.7.21.jar、slf4j-api-1.7.21-sources.jar
logback日志的jar包和配置介绍:logback-classic-1.1.2.jar、logback-core-1.1.2.jar、slf4j-api-1.7.7.jar、logback.xml、rsframework.properties
logback当前分成三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便...
Logback 中文手册,清晰版. 简单地说,Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。 Logback 主要由三个模块组成: logback-core logback-classic logback-access
LogBack配置文件,主要包括LOGBack的配置文件内容
用于logback框架通用xml配置文件
免费获取Logback所需的jar包 打包合集 让你少走弯路 一.logback简介 1.logback: Logback是由log4j创始人设计的另一个开源日志组件。(好的日志记录方式可以提供我们足够多的定位错误的依据)。 2.主要有三个模块...