logback运行时动态创建日志文件
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>
测试代码如下,使用了swagger
@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 均有效
logback运行时动态创建日志文件的更多相关文章
- C# 在运行时动态创建类型
C# 在运行时动态的创建类型,这里是通过动态生成C#源代码,然后通过编译器编译成程序集的方式实现动态创建类型 public static Assembly NewAssembly() { //创建编译 ...
- [C#] 将NLog输出到RichTextBox,并在运行时动态修改日志级别过滤
作者: zyl910 一.缘由 NLog是一个很好用的日志类库.利用它,可以很方便的将日志输出到 调试器.文件 等目标,还支持输出到窗体界面中的RichTextBox等目标. 而且它还支持在运行时修改 ...
- [转] Java运行时动态生成class的方法
[From] http://www.liaoxuefeng.com/article/0014617596492474eea2227bf04477e83e6d094683e0536000 廖雪峰 / 编 ...
- Java 运行时动态生成class
转载 http://www.liaoxuefeng.com/article/0014617596492474eea2227bf04477e83e6d094683e0536000 Java是一门静态语言 ...
- 利用log4net创建日志文件时过滤日志,这是坑还是?
前言 网上貌似没有太多关于log4net过滤日志的资料,在研究过程中发现一点小问题,这里做下记录,希望对后续有用到的童鞋起到一丢丢帮助作用. log4net日志过滤 由于是在.NET Core中使用, ...
- LINQ to SQL 运行时动态构建查询条件
在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...
- 使用javassist运行时动态重新加载java类及其他替换选择
在不少的情况下,我们需要对生产中的系统进行问题排查,但是又不能重启应用,java应用不同于数据库的存储过程,至少到目前为止,还不能原生的支持随时进行编译替换,从这种角度来说,数据库比java的动态性要 ...
- 解决 Retrofit 多 BaseUrl 及运行时动态改变 BaseUrl ?
原文地址: juejin.im/post/597856- 解决Retrofit多BaseUrl及运行时动态改变BaseUrl(一) 解决Retrofit多BaseUrl及运行时动态改变BaseUrl( ...
- .NET6运行时动态更新限流阈值
昨天博客园撑不住流量又崩溃了,很巧正在编写这篇文章,于是产生一个假想:如果博客园用上我这个限流组件会怎么样呢? 用户会收到几个429错误,并且多刷新几次就看到了内容,不会出现完全不可用. 还可以降低查 ...
随机推荐
- linux scp 命令使用
1.scp命令使用 linux 把文件复制到另一台服务器上 复制文件 scp file_name user_name@remote_ip:file_path 复制文件夹 scp -r file_nam ...
- PyQt开发样例: 利用QToolBox开发的桌面工具箱Demo
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 toolBox工具箱是一个容器部件,对应类为QToolBox,在其内有一列从上到下顺序排列 ...
- PyQt(Python+Qt)实现的GUI图形界面应用程序的事件捕获方法大全及对比分析
一. 概述 PyQt的图形界面应用中,事件处理类似于Windows系统的消息处理.一个带图形界面的应用程序启动后,事件处理就是应用的主循环,事件处理负责接收事件.分发事件.接收应用处理事件的返回结果, ...
- ADF 第一篇:Azure Data Factory介绍
Azure Data Factory(简写 ADF)是Azure的云ETL服务,简单的说,就是云上的SSIS.ADF是基于云的ETL,用于数据集成和数据转换,不需要代码,直接通过UI(code-fre ...
- 常见SQL注入点判断
sql注入手工检测 SQL注入手工检测 1基本检测 数字型 字符型 搜索型 POST注入 布尔盲注 报错注入 堆叠注入 判断是什么数据库 2绕过技巧 大小写 替换关键字 使用编码 注释和符号 等价函数 ...
- 第 7篇 Scrum 冲刺博客
一.站立式会议 1.站立式会议照片 2.昨天已完成的工作 对职工的查询 3.今天计划完成的工作 继续与同学对接,争取早日完成项目的整个流程 初步对数据库筛选 4.工作中遇到的困难 ①有同学不知道如何远 ...
- AT2688 [ARC080C] Young Maids
一道挺有意思的题目,在这里记录一下. 题目大意 给你一个长度为 \(n\) 的排列,每一次你可以取出相邻的两个数将其放在答案序列的开头,最后问你字典序最小的答案序列是什么. 题解 由于最后是求字典序最 ...
- 操作系统精髓与设计原理(九)——I/O管理和磁盘调度
文章目录 I/O设备 I/O功能组织 直接存储器访问 操作系统设计问题 设计目标 IO功能的逻辑结构 I/O缓冲 单缓冲 双缓冲 循环缓冲 缓冲的作用 磁盘调度 磁盘性能参数 磁盘调度策略 先进先出 ...
- nginx学习之——CentOS6.0下安装nginx
1.下载对应nginx版本 #注:下载地址:http://nginx.org/download/ wget -c http://nginx.org/download/nginx-1.10.3.tar. ...
- JavaScript:记录一些字符串和数组常用的方法
字符串: 字符串的方法:注意:都不会改变原来的字符串,返回值为新的字符串.如果(1,2),一般是包含小标1,不包含下标2 str.charAt(i): 取str的第i+1个字符,类似数组的arr[i] ...