需求
1、獲取日誌的產生的線程名稱,記錄器名稱,上下文產生時間,日誌發生時間,自定義日誌的信息
2、將獲取的信息以json的形式保存到redis中
思路
1、配置logback使用自定義Appender實現,來獲取對應的日誌信息
2、配置一個單列的redis工具類(不影響其他業務),將獲取的日誌信息保存起來
依賴
1、logback
<!-- 日誌:slf4j是接口,log4j是具體實現 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 實現slf4j接口並整合 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.1</version>
</dependency>
2、redis
<!--redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.3</version>
</dependency>
配置
1、logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--自定義日誌-->
<appender name="MyAppender" class="log.RedisAppender" />
<root level="info">
<appender-ref ref="MyAppender" />
</root>
</configuration>
2、redis.properties
maxIdle=100
maxWait=3000
testOnBorrow=true
host=127.0.0.1
port=6379
timeout=3000
pass=你的密碼
工具類
1、json轉換類
package tool;
import com.fasterxml.jackson.databind.ObjectMapper;
import exception.DobeoneException;
/**
* Created by yuyu on 2018/3/15.
* json相關的函數
*/
public class JsonBuilder {
/**
* 將一個實體類轉換成json字符串
* @param object
* @return
*/
public static String getString(Object object){
//安全判斷
if (object==null){
return null;
}
ObjectMapper mapper = new ObjectMapper();
String back;
try{
back=mapper.writeValueAsString(object);
}catch (Exception e){
//拋出一個自定義異常
throw new DobeoneException("json字符轉換失敗!-object-"+object,e);
}
return back;
}
}
2、配置文件獲取
package tool;
import exception.DobeoneException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Created by yuyu on 2018/3/12.
* 用於參數配置文件中的數據獲取
*/
public class PropertiesGetter {
/**
* 獲取配置文件的配置信息
* @param name
* @return
*/
public synchronized static Properties get(String name){
String file="/properties/"+name+".properties";
Properties prop = new Properties();
InputStream in = PropertiesGetter.class.getResourceAsStream(file);
try {
prop.load(in);
} catch (IOException e) {
throw new DobeoneException("獲取配置文件異常!-file-"+file,e);
}
return prop;
}
}
3、日期轉換
package tool;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by yuyu on 2018/3/15.
* 用於日期處理相關函數
*/
public class DataFormatBuilder {
/**
* 根據傳進來的時間戳 獲取對應的時間格式
* @param format 時間格式
* @param stamp 時間戳
* @return
*/
public static String getTimeStampFormat(String format,Long stamp){
if (stamp==null){
return null;
}
if (format==null){
format="yyyy-MM-dd HH:mm:ss/SSS";
}
SimpleDateFormat df = new SimpleDateFormat(format);//設置日期格式
return df.format(stamp);//傳進來的時間戳爲獲取當前系統時間
}
}
4、redis相關的操作
package tool;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Properties;
/**
* Created by yuyu on 2018/3/15.
* redis相關的操作,獲取一個單例的連接池
*/
public class RedisBuilder {
private static JedisPool jedisPool;
private static RedisBuilder singleRedisBuilder=new RedisBuilder();
//單利模式
private RedisBuilder(){
//獲取配置信息
Properties properties=PropertiesGetter.get("redis");
//設置連接池參數
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(Integer.parseInt(properties.getProperty("maxIdle")));//最大的jedis實例
config.setMaxWaitMillis(Integer.parseInt(properties.getProperty("maxWait")));//最大等待時間(毫秒)
config.setTestOnBorrow(Boolean.parseBoolean(properties.getProperty("testOnBorrow")));//借用時測試
//redis鏈接
jedisPool=new JedisPool(config, properties.getProperty("host")
, Integer.parseInt(properties.getProperty("port"))
, Integer.parseInt(properties.getProperty("timeout"))
, properties.getProperty("pass"));
}
/**
* 從連接池中獲取一個Jedis對象
* @param db 數據庫[0,15]
* @return
*/
public static Jedis getSingleJedis(Integer db) {
if (db==null||(db<0&&db>15)){
return null;
}
Jedis back=jedisPool.getResource();
back.select(db);
return back;
}
/**
*傳入名稱獲取保存在redis中的Index號碼
* @param name
* @return
*/
public static Integer getRedisIndexByName(String name){
if (name==null){
return null;
}
Jedis jedis=RedisBuilder.getSingleJedis(15);
Integer index;
String value=jedis.get(name);
//獲取保存的index數據,沒有的時候取0
if (null==value){
index=0;
}else{
index =Integer.parseInt(value)+1;
}
//將index保存
jedis.set(name,index.toString());
jedis.close();
return index;
}
}
實現
1、數據保存dto
package dto.log;
import ch.qos.logback.classic.spi.LoggingEvent;
import tool.DataFormatBuilder;
/**
* Created by yuyu on 2018/3/15.
* 用於保存日誌數據
*/
public class LogData {
private String message;//日誌的信息
private String loggerTime;//上下文產生時間
private String loggerName;//記錄器名稱
private String threadName;//線程名稱
private String happenStamp;//日誌發生時間
public LogData() {
}
public LogData(LoggingEvent loggingEvent) {
this.message=loggingEvent.toString();
this.loggerTime=DataFormatBuilder.getTimeStampFormat(null,
loggingEvent.getContextBirthTime());
this.loggerName=loggingEvent.getLoggerName();
this.threadName=loggingEvent.getThreadName();
this.happenStamp=DataFormatBuilder.getTimeStampFormat(null,
loggingEvent.getTimeStamp());
}
//getter,setter略
}
2、自定義Appender
package log;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.AppenderBase;
import dto.log.LogData;
import redis.clients.jedis.Jedis;
import tool.JsonBuilder;
import tool.RedisBuilder;
/**
* Created by yuyu on 2018/3/15.
* 自定義日誌處理
*/
public class RedisAppender extends AppenderBase<LoggingEvent> {
@Override
protected void append(LoggingEvent loggingEvent) {
//獲取日誌數據
LogData logData=new LogData(loggingEvent);
//設置日誌保存數據庫
Jedis jedis=RedisBuilder.getSingleJedis(2);
//設置日誌的key
String key="logData";
//獲取日誌條數
Integer index=RedisBuilder.getRedisIndexByName(key);
//保存日誌
jedis.set(key+index, JsonBuilder.getString(logData));
//關閉鏈接
jedis.close();
}
}
測試
1、測試代碼
package tool;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by yuyu on 2018/3/15.
* 測試日誌到redis
*/
public class TestLogger {
private Logger logger= LoggerFactory.getLogger(this.getClass());
@Test
public void testLogger(){
logger.info("hahha");
}
}
2、redis數據截圖
3、json數據結構
{
"message":"[INFO] hahha",
"loggerTime":"2018-03-15 20:00:55/694",
"loggerName":"tool.TestLogger",
"threadName":"main",
"happenStamp":"2018-03-15 20:00:56/087"
}
總結
1、代碼中出現使用的工具類都已經給出
2、每一次日誌都提交記錄的情況可能會消耗大量資源,可以設置緩存,然後到達一定條數再將記錄寫入redis中
3、想要具體獲取再多的日誌信息詳情請查看,ch.qos.logback.classic.spi.LoggingEvent 提供的方法
4、更多請查看參考文章
參考文章
1、Log4j2、Log4j、Logback自定義Appender實現
2、logback-Appender 自定義詳解
3、單例模式
4、jedis連接池配置