Proper method for registering custom LoggerFactory for Log4j 1.2?
我正在使用一个使用Log4j(1.2.16)注销的Web应用程序。为了避免不得不编辑大量文件,我尝试挂钩一个自定义的LoggerFactory实现,以防止日志伪造。
似乎可以设置
检查更多Log4j源代码,它似乎是实现我想要的唯一方法,我必须创建Log4j类的自定义子类。这是唯一的方法吗?
以下内容代表我在Web应用程序上下文侦听器中初始化Log4j所必须执行的操作,因此将使用我的自定义记录器工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | package com.example.myapp.log4j; import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent; import javax.servlet.*; public class MyLog4jInitContextListener implements ServletContextListener { public void contextInitialized( ServletContextEvent event ) { this.context = event.getServletContext(); String file = context.getInitParameter("log4jConfiguration"); if (file != null) { String prefix = context.getRealPath("/"); String pathname = prefix+file; event.getServletContext().log("Initializing log4j with"+pathname); org.apache.log4j.LogManager.setRepositorySelector( new org.apache.log4j.spi.DefaultRepositorySelector( new MyHierarchy( new org.apache.log4j.spi.RootLogger( (org.apache.log4j.Level)org.apache.log4j.Level.INFO))), this); new MyPropertyConfigurator().doConfigure( pathname, org.apache.log4j.LogManager.getLoggerRepository()); } else { event.getServletContext().log( "No log4jConfiguration parameter specified"); } } public void contextDestroyed( ServletContextEvent event ) { this.context = null; } private ServletContext context = null; } |
我必须创建一个自定义
MyHierarchy.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.example.myapp.log4j; import org.apache.log4j.Hierarchy; import org.apache.log4j.Logger; import org.apache.log4j.spi.LoggerFactory; public class MyHierarchy extends Hierarchy { public MyHierarchy(Logger root) { super(root); } @Override public Logger getLogger(String name) { return getLogger(name, defaultFactory); } private LoggerFactory defaultFactory = new MyLoggerFactory(); } |
不确定我是否需要自定义PropertyConfigurator,但是如果确实有一些执行路径实际使用它保留引用的记录器工厂实例,我会做。
MyPropertyConfigurator.java
1 2 3 4 5 6 7 8 9 10 11 12 | package com.example.myapp.log4j; import org.apache.log4j.PropertyConfigurator; public class MyPropertyConfigurator extends PropertyConfigurator { public MyPropertyConfigurator() { loggerFactory = new MyLoggerFactory(); } @Override protected void configureLoggerFactory(java.util.Properties props) { } } |
以下是我的记录器工厂实现。 MyEscapedLogger实现是Log4j的Logger类的子类,但是在调用方法的超级版本之前,它重写了protectedLog()受保护的方法来转义消息中的字符。
MyLoggerFactory.java
1 2 3 4 5 6 7 8 9 | package com.example.myapp.log4j; import org.apache.log4j.spi.LoggerFactory; public class MyLoggerFactory implements LoggerFactory { public Logger makeNewLoggerInstance(String name) { return new MyEscapedLogger(name); } } |
搜索了一段时间后,我发现了这个非常好的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | final LoggerFactory loggerFactory = new LoggerFactory() { @Override public Logger makeNewLoggerInstance(String name) { return new MyCustomLogger(name); // or (if you don't need a custom Logger implementation): // Logger logger = new Logger(name); // logger.setSTUFF(...); // return logger; } }; LoggerRepository rep = new Hierarchy(new RootLogger(Level.DEBUG)) { @Override public Logger getLogger(String name) { return super.getLogger(name, loggerFactory); } }; LogManager.setRepositorySelector(new DefaultRepositorySelector(rep), null); |
我正在使用:log4j 1.2.17