package com.example.demo.config; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.rolling.RollingFileAppender; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.util.concurrent.ConcurrentHashMap; @Component public class LoggerBuilder { private ConcurrentHashMap<String, Logger> container = new ConcurrentHashMap<>(); public Logger getLogger(String name,Class<?> clazz) { Logger logger = container.get(name); if (logger != null) { return logger; } synchronized (LoggerBuilder.class) { logger = container.get(name); if (logger != null) { return logger; } logger = build(name,clazz); container.put(name, logger); } return logger; } private Logger build(String name,Class<?> clazz) { RollingFileAppender errorAppender = new AppenderFactory().createRollingFileAppender(name, Level.ERROR); RollingFileAppender infoAppender = new AppenderFactory().createRollingFileAppender(name, Level.INFO); ConsoleAppender consoleAppender = new AppenderFactory().createConsoleAppender(); LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); Logger logger = context.getLogger(clazz + " [" + name + "]"); //設置不向上級打印信息 logger.setAdditive(false); logger.addAppender(errorAppender); logger.addAppender(infoAppender); logger.addAppender(consoleAppender); return logger; } }
package com.example.demo.config; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.filter.LevelFilter; import ch.qos.logback.core.ConsoleAppender; import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy; import ch.qos.logback.core.util.FileSize; import ch.qos.logback.core.util.OptionHelper; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import static ch.qos.logback.core.spi.FilterReply.ACCEPT; import static ch.qos.logback.core.spi.FilterReply.DENY; public class AppenderFactory { public RollingFileAppender createRollingFileAppender(String name, Level level) { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); RollingFileAppender appender = new RollingFileAppender(); //這裏設置級別過濾器 appender.addFilter(createLevelFilter(level)); //設置上下文,每一個logger都關聯到logger上下文,默認上下文名稱爲default。 // 但可使用<contextName>設置成其餘名字,用於區分不一樣應用程序的記錄。一旦設置,不能修改。 appender.setContext(context); //appender的name屬性 appender.setName("file-" + level.levelStr.toLowerCase()); //設置文件名 appender.setFile(OptionHelper.substVars("${LOG_HOME}/" + name + "/" + level.levelStr.toLowerCase() + ".log", context)); appender.setAppend(true); appender.setPrudent(false); //加入下面兩個節點 appender.setRollingPolicy(createSizeAndTimeBasedRollingPolicy(name,level,context,appender)); appender.setEncoder(createEncoder(context)); appender.start(); return appender; } public ConsoleAppender createConsoleAppender(){ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); ConsoleAppender appender = new ConsoleAppender(); appender.setContext(context); appender.setName("file-console"); appender.addFilter(createLevelFilter(Level.DEBUG)); appender.setEncoder(createEncoder(context)); appender.start(); return appender; } private SizeAndTimeBasedRollingPolicy createSizeAndTimeBasedRollingPolicy(String name, Level level, LoggerContext context, FileAppender appender) { //設置文件建立時間及大小的類 SizeAndTimeBasedRollingPolicy policy = new SizeAndTimeBasedRollingPolicy(); //文件名格式 String fp = OptionHelper.substVars("${LOG_HOME}/" + name + "/backup/" + level.levelStr.toLowerCase() + "-%d{yyyy-MM-dd}.log.%i", context); //最大日誌文件大小 policy.setMaxFileSize(FileSize.valueOf("5MB")); //設置文件名模式 policy.setFileNamePattern(fp); //設置最大歷史記錄爲30條 policy.setMaxHistory(30); //總大小限制 policy.setTotalSizeCap(FileSize.valueOf("32GB")); //設置父節點是appender policy.setParent(appender); //設置上下文,每一個logger都關聯到logger上下文,默認上下文名稱爲default。 // 但可使用<contextName>設置成其餘名字,用於區分不一樣應用程序的記錄。一旦設置,不能修改。 policy.setContext(context); policy.start(); return policy; } private PatternLayoutEncoder createEncoder(LoggerContext context) { PatternLayoutEncoder encoder = new PatternLayoutEncoder(); //設置上下文,每一個logger都關聯到logger上下文,默認上下文名稱爲default。 // 但可使用<contextName>設置成其餘名字,用於區分不一樣應用程序的記錄。一旦設置,不能修改。 encoder.setContext(context); //設置格式 encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %msg%n"); encoder.start(); return encoder; } private LevelFilter createLevelFilter(Level level) { LevelFilter levelFilter = new LevelFilter(); levelFilter.setLevel(level); levelFilter.setOnMatch(ACCEPT); levelFilter.setOnMismatch(DENY); levelFilter.start(); return levelFilter; } }
${LOG_HOME} 是 logback-spring.xml中的變量 ,以下
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml"/> <!--spring.application.name 是 application.yml 中設置--> <springProperty scope="context" name="app_name" source="spring.application.name"/> <property scope="context" name="LOG_HOME" value="logs/${app_name}"/> </configuration>
測試代碼以下,使用了swaggerjava
@RestController @RequestMapping("/test") @Api(tags = "Test", description = "測試接口") public class controller { @Autowired private LoggerBuilder loggerBuilder; @ApiOperation("測試") @PostMapping("/test") public ResultVO test(String name) { Logger logger = loggerBuilder.getLogger(name,controller.class); logger.info("測試...我係{}",name); return ResultVO.success(); } }
以上代碼運行在 springboot(2.2.2.RELEASE) + logback、springboot(1.5.8.RELEASE) + logback 均有效spring