log4j2 不使用配置文件,动态生成logger对象
大家平时使用Log4j一般都是在classpath下放置一个log4j的配置文件,比如log4j.xml,里面配置好Appenders和Loggers,但是前一阵想做某需求的时候,想要的效果是每一个任务都要有一个单独的日志文件记录下来,比如job.001.log,job.002.log这种,这种完全不能使用配置文件来设置。
整体架构:

Log4j的组成:
Log4j由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。
1.日志记录器(Loggers):控制要输出哪些日志记录语句,对日志信息进行级别限制。
2.输出端(Appenders):指定了日志将打印到控制台还是文件中。
3.日志格式化器(Layout):控制日志信息的显示格式。
于是点开Log4j的源码,研究了一番,发现使用Log4j的底层代码完全可以动态生成新的Logger,比较关键的类有
org.apache.logging.log4j.core.Layout负责格式
org.apache.logging.log4j.core.Appender就是配置文件里的Appender,我们使用FileAppender,也可以使用RollingFileAppender,
org.apache.logging.log4j.core.config.Configuration和org.apache.logging.log4j.core.LoggerContext是负责Log4j的配置的。
LoggerContext
在日志系统中,LoggerContext扮演者重要的角色。然而,根据实际情况,一个应用中可能存在多个有效的LoggerContext。
Configuration
每一个LoggerContext都有一个有效的Configuaration,它包含了所有的Appenders、context-wide Filters、LoggerConfigs以及对StrSubstitutor的引用。在重新配置期间,两个Configuaration会同时存在;一旦日志器被重新赋予新的Configuaration,旧的Configuaration就会停止工作并丢弃。
LoggerConfig
LoggerConfig将会在Loggers在logging configuration中被声明的时候创建。在LoggerConfig 拥有一列类的过滤器(Filter),这些过滤器将会过来所有的记录日志的事件,只有符合要求的日志才会被传递到Appenders。因为LoggerConfig需要将事件传递给Appenders,所以它拥有一系列Appenders的引用。
Appender
根据logger请求选择去接受或者拒绝该只是他们的一个能力。Log4j允许日志打印服务打印到多个目的地上。在Log4j的说法是一个输出的目的地对应着一个Appdender。现在的Appender允许是console, files, remote socket servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various database APIs。
是在Log4j2.3下测试通过的。注意在不使用Logger的时候一定要调用stop方法将Logger移除,不然我自己测试生成7000多个Logger后便会报错open too many file。
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
*/
public class JobLogFactory {
private JobLogFactory() {
}
public static void start(int jobId) {
//为false时,返回多个LoggerContext对象, true:返回唯一的单例LoggerContext
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
//创建一个展示的样式:PatternLayout, 还有其他的日志打印样式。
Layout layout = PatternLayout.createLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN,
config, null, null, true, false, null, null);
//TriggeringPolicy tp = SizeBasedTriggeringPolicy.createPolicy("10MB");
//Appender appender = RollingFileAppender.createAppender(String.format("
// logs/test/syncshows-job-%s.log", jobID),
// "/logs/test/" + jobID + "/syncshows-job-" + jobID + ".log.gz",
// "true", jobID, null, null, null, tp, null, layout, null,
// null, null, null, config);
// 日志打印方式——输出为文件
Appender appender = FileAppender.createAppender(
String.format("logs/test/syncshows-job-%s.log", jobId), "true", "false",
"" + jobId, null, "true", "true", null, layout, null, null, null, config);
appender.start();
config.addAppender(appender);
AppenderRef ref = AppenderRef.createAppenderRef("" + jobId, null, null);
AppenderRef[] refs = new AppenderRef[]{ref};
LoggerConfig loggerConfig = LoggerConfig.createLogger("false", Level.ALL, "" + jobId,
"true", refs, null, config, null);
loggerConfig.addAppender(appender, null, null);
config.addLogger("" + jobId, loggerConfig);
ctx.updateLoggers();
}
public static void stop(int jobId) {
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
config.getAppender("" + jobId).stop();
config.getLoggerConfig("" + jobId).removeAppender("" + jobId);
config.removeLogger("" + jobId);
ctx.updateLoggers();
}
/**
* 获取Logger
*
* 如果不想使用slf4j,那这里改成直接返回Log4j的Logger即可
* @param jobId
* @return
*/
public static Logger createLogger(int jobId) {
start(jobId);
return LoggerFactory.getLogger("" + jobId);
}
}
测试类:
import org.slf4j.Logger;
/**
*
simple test
*/
public class LoggerTest {
public static void main(String[] args) {
for(int i=0;i<50000;i++) {
Logger logger = JobLogFactory.createLogger(i);
logger.info("Testing testing testing 111");
logger.debug("Testing testing testing 222");
logger.error("Testing testing testing 333");
JobLogFactory.stop(i);
}
}
}
致谢,感谢您的阅读!
log4j2 不使用配置文件,动态生成logger对象的更多相关文章
- 利用StringList对象来管理这些动态生成的对象
如果程序需要动态创建大量的对象,那么我们可以利用StringList对象来管理这些动态生成的对象.1.创建StringList对象:OBJ := TStringList.Create; 2.保存动态生 ...
- JS 动态生成JSON对象
JS 动态生成JSON对象,一般用到JSON传递参数的时候,会用到. function onGeneratedRow(columnsResult) { var jsonData = {}; colum ...
- Python PageFactory-使用配置文件动态生成页面PageObject
需求 在Python Selenium 的 PageObject模式中,一般每个页面需要写一个类, 一种PageObject的写法如下: class BaiduPageObject(object): ...
- mybatis-generator 动态生成实体对象、dao 以及相关的xml映射文件
.新建maven空项目 2.修改pom.xml文件 <?xml version="1.0" encoding="UTF-8"?> <proje ...
- Jquery给动态生成的对象绑定事件
$(document).on("blur", ".Text1", function () { var index = this.id.replace('txtS ...
- Log4j2 - 动态生成Appender
功能需求 项目里将User分成了各个区域(domain),这些domain有个标志domainId,现在要求在打印日志的时候,不仅将所有User的日志都打印到日志文件logs/CNTCore.log中 ...
- Emit动态生成代理类用于监控对象的字段修改
利用Emit动态生成代理对象监控对象哪些字段被修改,被修改为什么值 被Register的对象要监控的值必须是Virtual虚类型 必须使用CreateInstance创建对象 必须使用DynamicP ...
- Vuforia图像追踪,动态创建的对象隐藏显示的坑
刚做的一个项目,使用Unity3D的Vuforia插件进行图像识别,其中有动态生成的游戏对象模型,地形模型放在ImageTarget下,作为ImageTarget的子物体. 动态生成的敌人则有Pref ...
- log4cplus 直接创建logger 对象
#include <log4cplus/loggingmacros.h> #include <log4cplus/fileappender.h> #include <lo ...
随机推荐
- Windows Phone 如何振动手机?
1. 导入命名空间. using Windows.Phone.Devices.Notification; 2. 通过调用对 VibrationDevice 类的静态 GetDefault 方法获取对振 ...
- 工作流引擎Oozie(二):coordinator
1. 简介 coordinator是workflow的定时提交器,基于时间条件与数据生成触发(based on time and data triggers).简单点说,coordinator按所定义 ...
- Hibernate —— 映射关联关系(附录)
一.单向的多对一 1.建表语句 CREATE TABLE customer ( customer_id ) NOT NULL AUTO_INCREMENT PRIMARY KEY , ) CREATE ...
- 多步骤多分步的组件StepJump
最近的工作在做一个多步骤多分步的表单页面,这个多步骤多分步的意思是说这个页面的业务是分多个步骤完成的,每个步骤可能又分多个小步骤来处理,大步骤之间,以及小步骤之间都是一种顺序发生的业务关系.起初以为这 ...
- Python_Day_05 计数器(counter),有序字典(OrderDict),默认字典(defaultdict),可命名元祖(namedtuple),双向队列(deque),单项队列(deuqe.Queue)
Counter(计数器) 是一个字典的子类,存储形式同样为字典,其中存储的键为字典的元素,值为元素出现的次数,在使用之前我们需要先导入文件 import collections 初始化一个计数器 im ...
- [译] Paxos算法详解
1. 概述 Paxos算法被用来实现一个容错的分布式系统,一直以来以晦涩难懂著称.这可能是因为该算法最开始使用希腊文表述的.事实上,它是所有分布式算法中最简单易懂的.Paxos算法的本质其实就是一个共 ...
- Nancy之区域和分部视图的使用
一.前言 在MVC中,区域(Area)和分部视图(PartialView)应该是我们用的十分频繁的两个东西 今天我们就在Nancy中,把这两个东西简单的用起来! 二.简单使用之区域 区域,无论是对 ...
- 【C#公共帮助类】FTPClientHelper帮助类,实现文件上传,目录操作,下载等动作
关于本文档的说明 本文档使用Socket通信方式来实现ftp文件的上传下载等命令的执行 欢迎传播分享,必须保持原作者的信息,但禁止将该文档直接用于商业盈利. 本人自从几年前走上编程之路,一直致力于收集 ...
- Struts,spring,hibernate三大框架的面试
Struts,spring,hibernate三大框架的面试 1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3 ...
- iOS下Audio自动播放(Autoplay)音乐
前几天做了一个H5活动页面,产品要求初始化播放音乐,因晓得H5 Audio标签支持Autoplay就没在意. 完了在手机上测试,发现手机上打开页面死活就是不会自动播放,点击播放按钮才可以播放,很是纠结 ...