java 使用redis記錄logback日誌,由自定義Appender與Jedis的使用實現。

需求

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連接池配置

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章