目录
前言
业务需求:Java通过自定义logback实现日志文件按业务独立生成日志文件到指定路径。当用户创建一个任务后,该任务生成日志文件,点击页面有任务详细信息,包含错误信息。
设计方案:在创建任务时,任务的日志生成是动态生成只包含当前任务日志内容且输出到固定目录下,所以不能依赖于logbak的xml方式,要自定义logback的appender。至于页面查看,可对日志文件进行按行读取再分页查询即可。
本文内容会详细讨论如何基于logback生成任务独立的日志文件到某一文件夹下的功能。下面是详细步骤:
一、自定义logback appender对象
类似通常使用的logback.xml配置方式一样,需要先定义一个appender,appender这里选择的是RollingFileAppender,这个appender会将日志打印到文件里。在appender里设置文件生成路径、日志输出格式、滚动策略、编码等操作。下面是代码:
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.nio.charset.Charset;
public class LogAppender {
/**
* 通过传入的任务名字,动态设置appender
* @param taskName
* @return
*/
public RollingFileAppender getAppender(String oldLogPath,String taskName) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
RollingFileAppender appender = new RollingFileAppender();
//appender的name属性
appender.setName( taskName);
appender.setContext(context);
//设置文件名
appender.setFile(new File(oldLogPath, taskName+".log").getAbsolutePath());
//设置日志文件输出格式
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(context);
encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
encoder.setCharset(Charset.forName("UTF-8"));
encoder.start();
//设置日志记录器的滚动策略
TimeBasedRollingPolicy policy = new TimeBasedRollingPolicy();
policy.setFileNamePattern(oldLogPath+taskName+".%d{yyyy-MM-dd}.log");
policy.setParent(appender); //设置父节点是appender
policy.setContext(context);
policy.start();
//加入下面两个节点
appender.setRollingPolicy(policy);
appender.setEncoder(encoder);
appender.start();
return appender;
}
}
二、给Logger对象指定appender
同样类比logback.xml配置方式,需要给自定义logger或者root logger指定一个appender,appender,在配置文件中用appender-ref。这里实现逻辑是:封装TaskLoggerService对象,该对象build方法实现给Logger对象指定appender,用户使用公有方法getLogger获取Logger对象来实现日志打印。代码如下:
package com.jd.upload.utils;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.rolling.RollingFileAppender;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class TaskLoggerService {
String logPath;//日志存储路径
public TaskLoggerService(String logPath) {
this.logPath = logPath;
}
//对外暴露日志对象:每次拿的对象从内存里拿,没有再构建
private static Map<String,Logger> container = new HashMap<>();
public Logger getLogger(String taskName) {
Logger logger = container.get(taskName);
if(logger != null) {
return logger;
}
logger = build(taskName);
container.put(taskName,logger);
return logger;
}
//构建Logger对象,给Logger指定appender,该方法不对外暴露
private Logger build(String taskName) {
RollingFileAppender runTaskAppender =new com.jd.upload.utils.LogAppender().getAppender(this.logPath,taskName);
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = context.getLogger(taskName);
logger.addAppender(runTaskAppender);
return logger;
}
}
三、测试
下面代码是测试类,可打印出相应级别的日志,生成任务名命名的日志文件并存储到相应路径下。
扫描二维码关注公众号,回复:
15601214 查看本文章
package com.test.example.log;
import org.slf4j.Logger;
//测试类
public class CustomerLog {
String logPath;//日志路径
public CustomerLog(String logPath) {
this.logPath = logPath;
}
TaskLoggerServiceloggerBuilder =new TaskLoggerService(this.logPath);
Logger logger;
public void getLog(String taskName) throws Exception {
logger = loggerBuilder.getLogger(taskName);
logger.debug("shuai1 +++++++++++++++++++++++++++++++++++++debug");
logger.warn("shuai2 +++++++++++++++++++++++++++++++++++++warn");
logger.info("shuai3 +++++++++++++++++++++++++++++++++++++info");
try{
int i = 1/0;
}catch (Exception e){
logger.error("shuai4 +++++++++++++++++++++++++++++++++++++error");
throw new Exception(e);
}
}
}