logback如何自定義日志存儲(chǔ)
logback自定義日志存儲(chǔ)
1、配置lockback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_HOME" value="/wzwsq-log" />
<property name="APP_NAME" value="wzwsq" />
<!-- 控制臺(tái)輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級(jí)別從左顯示5個(gè)字符寬度%msg:日志消息,%n是換行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %X{address} %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件輸出的文件名 -->
<FileNamePattern>${LOG_HOME}/${APP_NAME}.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天數(shù) -->
<MaxHistory>10</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級(jí)別從左顯示5個(gè)字符寬度%msg:日志消息,%n是換行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %X{address} %-5level %logger{50} - %msg%n</pattern>
<!--<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> -->
</encoder>
</appender>
<!--連接數(shù)據(jù)庫(kù)配置 class:日志保存操作類 -->
<appender name="db_classic_mysql_pool" class="wzwsq.config.LogDBAppender">
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="org.apache.commons.dbcp.BasicDataSource">
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<url>jdbc:mysql://localhost:3306/wzwsq?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf8</url>
<username>root</username>
<password>123456</password>
</dataSource>
</connectionSource>
</appender>
<!-- 日志輸出級(jí)別 -->
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<!--添加自定義操作配置-->
<appender-ref ref="db_classic_mysql_pool" />
</root>
</configuration>
2、配置自定義日志操作類
import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;
import com.alibaba.fastjson.JSONObject;
import wzwsq.model.IpInfo; //自定義IP對(duì)象
import wzwsq.model.UsersModel; //自定義用戶對(duì)象
import wzwsq.util.Constant; //自定義常量對(duì)象
import wzwsq.util.WebUtils; //自定義Web工具對(duì)象
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
/**
* @ClassName LogDBAppender
* @Description: 自定義日志保存至數(shù)據(jù)庫(kù)
* @Author wzwsq
* @Date 2020/12/10
* @Version V1.0
**/
@Configuration
public class LogDBAppender extends DBAppenderBase<ILoggingEvent> {
protected static final Method GET_GENERATED_KEYS_METHOD;
//插入sql
protected String insertSQL;
//自定義存儲(chǔ)字段
/**
* menu_type:操作類型,指的是菜單ID
* record_id:相關(guān)操作對(duì)象的ID
* operation_content:操作內(nèi)容,自定義編輯
* add_id:操作人ID
* add_time:操作時(shí)間
* ip:根據(jù)IP對(duì)應(yīng)城市
* city:ip所屬城市
* ua:瀏覽器信息
* */
static final int MENU_TYPE = 1;
static final int RECORD_ID = 2;
static final int OPERATION_CONTENT = 3;
static final int ADD_ID = 4;
static final int ADD_TIME = 5;
static final int IP = 6;
static final int CITY = 7;
static final int UA = 8;
static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();
static {
// PreparedStatement.getGeneratedKeys() method was added in JDK 1.4
Method getGeneratedKeysMethod;
try {
// the
getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);
} catch (Exception ex) {
getGeneratedKeysMethod = null;
}
GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
}
@Override
public void start() {
// 將寫(xiě)好的sql語(yǔ)句賦值給insertSQL
insertSQL = buildInsertSQL();
super.start();
}
// 自己寫(xiě)新增sql語(yǔ)句
private static String buildInsertSQL() {
return "INSERT INTO `operation_log`" +
"(" +
"`menu_type`,`record_id`," +
"`operation_content`,`add_id`," +
"`add_time`,`ip`," +
"`city`,`ua`" +
")" +
"VALUES (?,?,?,?,?,?,?,?)";
}
@Override
protected Method getGeneratedKeysMethod() {
return GET_GENERATED_KEYS_METHOD;
}
@Override
protected String getInsertSQL() {
return insertSQL;
}
/**
* 主要修改的方法
*
* @param stmt
* @param event
* @throws SQLException
*/
private void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException {
// event.getFormattedMessage() 日志打印內(nèi)容
String message = event.getFormattedMessage();
// 如果只想存儲(chǔ)自己打印的日志,可以這樣寫(xiě)日志:
// logger.info("'MENU_TYPE': '{}','RECORD_ID': '{}','OPERATION_CONTENT': '{}'",XXX,XXX,XXX)
//判斷當(dāng)前日志信息是否屬于自定義類型
int MENU_TYPE_FLAG=message.indexOf("MENU_TYPE");
int RECORD_ID_FLAG=message.indexOf("RECORD_ID");
int OPERATION_CONTENT_FLAG=message.indexOf("OPERATION_CONTENT");
if(MENU_TYPE_FLAG>0&&RECORD_ID_FLAG>0&&OPERATION_CONTENT_FLAG>0){
//截取用戶自定義的日志信息
JSONObject jsonObject =JSONObject.parseObject(message);
String menuType=jsonObject.get("MENU_TYPE").toString();
String recordId=jsonObject.get("RECORD_ID").toString();
String operationContent=jsonObject.get("OPERATION_CONTENT").toString();
//獲取當(dāng)前使用系統(tǒng)的用戶對(duì)象、IP、CITY、UA
UsersModel usersModel=WebUtils.getUser();//用戶登錄對(duì)象
IpInfo ipInfo=(IpInfo)WebUtils.getSession().getAttribute(Constant.IP_INFO);//用戶登錄IP信息
String ip=ipInfo.getIp();
String city=ipInfo.getCity();
String ua=ipInfo.getUa();
stmt.setString(MENU_TYPE, menuType);
stmt.setString(RECORD_ID, recordId);
stmt.setString(OPERATION_CONTENT, operationContent);
stmt.setString(ADD_ID,usersModel.getId().toString());
stmt.setTimestamp(ADD_TIME, new Timestamp(event.getTimeStamp()));
stmt.setString(IP, ip);
stmt.setString(CITY,city==null?"":city.toString());
stmt.setString(UA, ua==null?"":ua.toString());
}
}
@Override
protected void subAppend(ILoggingEvent eventObject, Connection connection, PreparedStatement statement) throws Throwable {
bindLoggingEventWithInsertStatement(statement, eventObject);
// This is expensive... should we do it every time?
int updateCount = statement.executeUpdate();
if (updateCount != 1) {
addWarn("Failed to insert loggingEvent");
}
}
@Override
protected void secondarySubAppend(ILoggingEvent eventObject, Connection connection, long eventId) throws Throwable {
}
}
3、調(diào)用方法
private static Logger logger = LoggerFactory.getLogger(UsersController.class);
logger.info("'MENU_TYPE': '{}','RECORD_ID': '{}','OPERATION_CONTENT': '{}'",XXX,XXX,XXX);
注意事項(xiàng):在logback.xml中appender標(biāo)簽一定的寫(xiě)在root標(biāo)簽之前
使用logback進(jìn)行系統(tǒng)日志記錄
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.11</version>
</dependency>
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.base" value="/data1/logs/applogs/dt-mapping-api" />
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date %.-5level %class{100} ----------->> %msg%n</pattern>
</encoder>
</appender>
<appender name="logfile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.base}/default.log</file>
<!-- 配置日志所生成的目錄以及生成文件名的規(guī)則 在logs/mylog-2017-06-31.0.log.zip -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.base}.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<!-- 如果按天來(lái)回滾,則最大保存時(shí)間為30天,30天之前的都將被清理掉 -->
<maxHistory>30</maxHistory>
<!-- 日志總保存量為10GB -->
<totalSizeCap>10 GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!--文件達(dá)到 最大128MB時(shí)會(huì)被壓縮和切割 -->
<maxFileSize>128 MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %.-5level %class{25} - %msg%n</pattern>
</encoder>
</appender>
<appender name="errorfile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.base}/error.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 配置日志所生成的目錄以及生成文件名的規(guī)則 在logs/mylog-2017-06-31.0.log.zip -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.base}/error.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<!-- 如果按天來(lái)回滾,則最大保存時(shí)間為30天,30天之前的都將被清理掉 -->
<maxHistory>30</maxHistory>
<!-- 日志總保存量為10GB -->
<totalSizeCap>10 GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!--文件達(dá)到 最大128MB時(shí)會(huì)被壓縮和切割 -->
<maxFileSize>128 MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %.-5level %class{25} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.netflix.curator" level="OFF" />
<root level = "DEBUG">
<appender-ref ref="errorfile" />
<appender-ref ref="logfile" />
<appender-ref ref="stdout" />
</root>
</configuration>
private final static Logger logger = LoggerFactory.getLogger(Application.class);
logger.info("批次號(hào): {}",111111111111);
logger.error("xxx失敗: {}",e);
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot+Redis實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)的示例
本文將結(jié)合實(shí)例代碼,介紹SpringBoot+Redis實(shí)現(xiàn)后端接口防重復(fù)提交校驗(yàn)的示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
java web手寫(xiě)實(shí)現(xiàn)分頁(yè)功能
這篇文章主要為大家詳細(xì)介紹了java web手寫(xiě)實(shí)現(xiàn)分頁(yè)功能的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean
這篇文章主要介紹了Spring Bean Scope 有狀態(tài)的Bean與無(wú)狀態(tài)的Bean,每個(gè)用戶有自己特有的一個(gè)實(shí)例,在用戶的生存期內(nèi),bean保持了用戶的信息,下面來(lái)了解有狀態(tài)和無(wú)狀態(tài)的區(qū)別吧2022-01-01
Springboot配置Swagger的實(shí)現(xiàn)示例
Swagger 是一種提高 API 開(kāi)發(fā)和維護(hù)效率的工具,它使開(kāi)發(fā)者能夠更輕松地構(gòu)建、測(cè)試和文檔化 API,本文主要介紹了Springboot配置Swagger的實(shí)現(xiàn)示例,感興趣的可以了解一下2023-10-10
編譯大型Java項(xiàng)目class沖突導(dǎo)致報(bào)錯(cuò)的解決方案
這篇文章給大家盤(pán)點(diǎn)編譯大型項(xiàng)目class沖突導(dǎo)致報(bào)錯(cuò)的解決方案,文中通過(guò)代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2023-10-10
Springboot Thymeleaf模板文件調(diào)用Java類靜態(tài)方法
這篇文章主要介紹了Springboot Thymeleaf模板文件調(diào)用Java類靜態(tài)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2007-09-09
Spring加載屬性文件方式(自動(dòng)加載優(yōu)先級(jí)問(wèn)題)
這篇文章主要介紹了Spring加載屬性文件方式(自動(dòng)加載優(yōu)先級(jí)問(wèn)題),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

