- 浏览: 565131 次
- 性别:
- 来自: 长沙
-
文章分类
- 全部博客 (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 2775Java生成缩略图之Thumbnailator(转载) 原文 ... -
pinyin4j 的应用
2013-05-12 08:59 1289<!-- pinyin4j --> < ... -
二维条形码的生成与解析
2013-05-02 11:58 2664二维条形码的生成与解 ... -
memcached学习笔记(二) 使用memcached java客户端
2012-07-11 11:51 14511) 了解了一下 memcached 客户端常见的有两种 sp ... -
memcached学习笔记(一) instanll memcached on windows machine
2012-07-11 10:44 16231) 下载 http://code.jellycan.com/ ... -
Zip 压缩和解压缩
2011-12-31 14:17 1705要依赖 ant.1.7.0.jar <depend ... -
Log4j RollingFileAppender和DailyRollingFileAppender杂交
2011-12-16 15:13 3920package org.apache.log4j; ... -
BoneCP
2011-11-07 10:39 27401) BoneCP加入工程 <dependency& ... -
Quartz 任务调度器
2011-05-04 15:33 1868字段允许值允许的特殊 ... -
commons-email笔记
2011-04-15 11:59 1681使用Apache Commons-email发送电子邮件 所 ... -
commons-digest笔记
2011-04-12 11:09 1441本文为转载且为截取的片段,如有需要请访问原帖 待解析的xml ... -
json-taglib
2011-03-29 14:53 1807JSON-taglib是一套JSP标签库用于在JSP代码中输出 ... -
JSR-303
2011-03-21 15:45 12071JSR-303 是JAVA EE 6 中的一项子规范,叫做Be ... -
JUnit如何使用
2011-02-17 13:34 4817一,Junit4是Junit框架有 ... -
Apache-dom4j的使用(二)
2011-02-11 15:57 2064本小节讲如何使用dom4j解析一个xml文件 以读取book ... -
Apache-dom4j的使用(一)
2011-02-11 14:15 1373本节主要介绍如何用dom4j生成一个xml文档 <? ... -
log4j的xml配置方式
2011-01-15 07:33 1625一,原来一贯用的properties配置文件 log4j.pr ...
相关推荐
标题"扩展logback将日志输出到Kafka实例源码"涉及的技术点主要集中在如何将Logback与Kafka集成,使得日志可以被有效地发送到Kafka集群。这个过程通常涉及到以下几个步骤: 1. **添加依赖**:首先,你需要在项目的...
标题中的“扩展logback将日志输出到Kafka实例扩展源码”指的是在Java应用程序中,使用logback作为日志框架,并通过自定义appender(输出模块)将日志信息发送到Apache Kafka的消息队列中。Logback是SLF4J(Simple ...
我们可以使用Logback的DBAppender来实现日志记录到数据库。下面是一个示例代码: ```java import ch.qos.logback.classic.db.DBAppender; import ch.qos.logback.classic.db.DBHelper; public class ...
登录扩展 Logback日志库的扩展主要适用于针对Amazon Web Services的附加程序,包括CloudWatch Logs,DynamoDB,Kinesis,SNS和SQS附加程序。 还包含基于LMAX Disrupotr的高性能异步附加器和某些实用程序,例如...
Logback 是为了提供更高效、更灵活的日志记录解决方案而设计的,它不仅继承了 Log4j 的优点,还解决了一些性能和可扩展性问题。在Java应用程序中,日志系统扮演着至关重要的角色,它帮助开发者调试代码,记录错误,...
Logback 是一个在Java应用程序中广泛使用的日志记录框架,它是对早期的log4j框架的一个升级和扩展。Logback 提供了高效、灵活的日志记录解决方案,支持多种日志级别,如DEBUG、INFO、WARN、ERROR等,帮助开发者调试...
`logback-classic-1.2.3.jar`是Logback的经典实现,它扩展了`logback-core`,实现了SLF4J接口,从而使得Logback可以作为SLF4J的日志实现。这个库还引入了`ch.qos.logback.classic.Logger`,它是`org.slf4j.Logger`的...
这是 Logback 的经典实现,扩展了核心库的功能,并且兼容 SLF4J(Simple Logging Facade for Java)。SLF4J 提供了一个抽象层,允许开发者在不同的日志框架之间切换,如 Log4j 或 Logback。`ch.qos.logback.classic...
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 是一个用于日志记录的开源框架,由 Ceki Gülcü(也是 Log4j 的创始人)设计并开发。它作为 Log4j 的升级版,提供了更高的性能和更丰富的功能。Logback 分为三个主要组件:...
**日志框架Logback** 日志是任何软件系统中至关重要的组成部分,它为开发者提供了运行时的调试信息、错误报告以及性能分析数据。在Java世界里,Logback是一款高效、可配置的日志记录框架,由Ceki Gülcü(也是log4...
本主题将详细介绍如何利用Logback和SLF4J来将日志记录到Kafka队列中,以及支持日志解析和过滤等扩展功能。 首先,我们需要理解SLF4J的工作原理。SLF4J提供了一组API,允许我们在应用程序中插入日志语句,而具体的...
10. **可扩展性**: Logback设计时考虑了扩展性,可以通过自定义Appender和Layout来满足特定的日志记录需求。 通过这个压缩包,用户可以获得Logback框架的核心组件和经典实现,以及用于处理HTTP访问日志的模块,从而...
**logback-1.1.2源码包详解** **一、logback介绍** Logback 是一个用于日志记录的开源框架,由 Ceki Gülcü(也创建了广泛使用的 log4j)开发。它是对 log4j 的升级,旨在提供更高的性能、更灵活的配置以及更好的...
免费获取Logback所需的jar包 打包合集 让你少走弯路 一.logback简介 1.logback: Logback是由log4j创始人设计的另一个开源日志组件。(好的日志记录方式可以提供我们足够多的定位错误的依据)。 2.主要有三个模块...
`logback-classic-1.2.3.jar`是logback-classic的库文件,它扩展了logback的功能,如MDC(Mapped Diagnostic Context)、自定义布局和过滤器等。 3. **SLF4J API**: SLF4J作为一个抽象层,允许开发者选择不同的日志...
在日常工程开发中,日志是非常重要的一部分,通过...本资源基于maven,使用logback搭建日志结构,实现多种级别日志的输出控制,并封装各个级别的日志输出方法,可以作为日志管理基础进行扩展以满足其他场景的日志管理。
标题“logback1.2.3”和描述中的文件名暗示了这是一个关于Logback日志框架的版本1.2.3的资源包,其中包含了Logback的经典实现(logback-classic)和核心库(logback-core),以及Simple Logging Facade for Java ...
Logback 是一个专门为Java应用程序设计的日志框架,由log4j的创始人Ceki Gülcü设计,旨在提高日志处理的效率和灵活性。它在性能和资源消耗方面优于log4j和其他日志系统,提供了许多独特的特性,如Marker、参数化...
spring使用logback的扩展,使用起来非常方便。在web.xml中配置: <param-name>logbackConfigLocation <param-value>/WEB-INF/conf/logback.xml <listener-class>ch.qos.logback.ext.spring.web....