Mac下Log4j配置文件使用环境变量时Jetty启动报java.io.FileNotFoundException Permission denied
苹果Mac电脑,Java web项目用Eclipse Jetty插件启动时报log4j:ERROR setFile(null,true) call failed,java.io.FileNotFoundException Permission denied错误,具体如下:
log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /error_ (Permission denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:133)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:290)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:164)
at org.apache.log4j.DailyRollingFileAppender.activateOptions(DailyRollingFileAppender.java:216)
at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:257)
at org.apache.log4j.config.PropertySetter.setProperties(PropertySetter.java:133)
at org.apache.log4j.config.PropertySetter.setProperties(PropertySetter.java:97)
at org.apache.log4j.PropertyConfigurator.parseAppender(PropertyConfigurator.java:689)
at org.apache.log4j.PropertyConfigurator.parseCategory(PropertyConfigurator.java:647)
at org.apache.log4j.PropertyConfigurator.parseCatsAndRenderers(PropertyConfigurator.java:568)
at org.apache.log4j.PropertyConfigurator.doConfigure(PropertyConfigurator.java:442)
at org.apache.log4j.PropertyConfigurator.doConfigure(PropertyConfigurator.java:476)
at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:471)
at org.apache.log4j.LogManager.<clinit>(LogManager.java:125)
at org.apache.log4j.Logger.getLogger(Logger.java:105)
at org.apache.commons.logging.impl.Log4JLogger.getLogger(Log4JLogger.java:289)
at org.apache.commons.logging.impl.Log4JLogger.<init>(Log4JLogger.java:109)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.apache.commons.logging.impl.LogFactoryImpl.createLogFromClass(LogFactoryImpl.java:1116)
at org.apache.commons.logging.impl.LogFactoryImpl.discoverLogImplementation(LogFactoryImpl.java:914)
at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:604)
at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:336)
at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:310)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:685)
at com.leeyue.common.listener.SqlMapConfigListener.<init>(SqlMapConfigListener.java:21)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at java.lang.Class.newInstance(Class.java:442)
at org.eclipse.jetty.server.handler.ContextHandler$Context.createInstance(ContextHandler.java:2481)
at org.eclipse.jetty.webapp.StandardDescriptorProcessor.newListenerInstance(StandardDescriptorProcessor.java:1943)
at org.eclipse.jetty.webapp.StandardDescriptorProcessor.visitListener(StandardDescriptorProcessor.java:1898)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.eclipse.jetty.webapp.IterativeDescriptorProcessor.visit(IterativeDescriptorProcessor.java:83)
at org.eclipse.jetty.webapp.IterativeDescriptorProcessor.process(IterativeDescriptorProcessor.java:70)
at org.eclipse.jetty.webapp.MetaData.resolve(MetaData.java:403)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1364)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:778)
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:262)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:520)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
at org.eclipse.jetty.server.Server.start(Server.java:411)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
at org.eclipse.jetty.server.Server.doStart(Server.java:378)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at net.sourceforge.eclipsejetty.starter.jetty9.Jetty9Adapter.start(Jetty9Adapter.java:68)
at net.sourceforge.eclipsejetty.starter.common.AbstractJettyLauncherMain.launch(AbstractJettyLauncherMain.java:84)
at net.sourceforge.eclipsejetty.starter.jetty9.Jetty9LauncherMain.main(Jetty9LauncherMain.java:42)
log4j:ERROR Either File or DatePattern options are not set for appender [error].二、项目关键文件
1、web.xml 片段
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<listener>
<listener-class>com.leeyue.common.listener.ApplicationInitListener</listener-class>
</listener>
<listener>
<listener-class>com.leeyue.common.listener.SessionMonitorListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>com.leeyue.common.listener.SqlMapConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>2、ApplicationInitListener.java
@Override
public void contextInitialized(ServletContextEvent event) {
// 略去其它代码
String key = "ly_jxsywy.log_dir"; //实际代码为读取配置文件
String value = "Users/maben/logs/ly_jxsywy" //实际代码为读取配置文件
System.setProperty(key, value);
System.out.println("ApplicationInitListener contextInitialized!");
}3、SqlMapConfigListener.java
public class SqlMapConfigListener implements ServletContextListener {
@SuppressWarnings("unused")
private Log log = LogFactory.getLog(SqlMapConfigListener.class);
public SqlMapConfigListener() {
System.out.println("SqlMapConfigListener constrcuted.");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
}4、log4j.properties,文件指向使用了环境变量:${ly_jxsywy.log_dir}
#log4j.logger.org.logicalcobwebs.proxool=debug,stdout
log4j.rootLogger=warn,stdout
log4j.logger.com.leeyue.jpa=info,sql
log4j.logger.cc.leeyue.service=info,service
log4j.logger.cc.leeyue.error=error,error
#
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%t \: %d %p [%c] - %m%n
#
#sqlProcess config
log4j.appender.sql=org.apache.log4j.DailyRollingFileAppender
log4j.additivity.sql=false
log4j.appender.sql.File=${ly_jxsywy.log_dir}/sql_
log4j.appender.sql.DatePattern=yyyy-MM-dd'.log'
log4j.appender.sql.layout=org.apache.log4j.PatternLayout
log4j.appender.sql.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] - %m%n
log4j.appender.service=org.apache.log4j.DailyRollingFileAppender
#log4j.additivity.service=false
log4j.appender.service.File=${ly_jxsywy.log_dir}/service_
log4j.appender.service.DatePattern=yyyy-MM-dd'.log'
log4j.appender.service.layout=org.apache.log4j.PatternLayout
log4j.appender.service.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] - %m%n
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
#log4j.additivity.service=false
log4j.appender.error.File=${ly_jxsywy.log_dir}/error_
log4j.appender.error.DatePattern=yyyy-MM-dd'.log'
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] - %m%n三、项目启动顺序说明
根据web规范 ,web.xml中配置的listener,filter,serlet启动顺为:先读取context-para节点参数,然后Listener > Filter > Servlet,相同元素如listener则按web.xml文件中的出现顺序执行。
所以,项目原本设想是在ApplicationListener中设置环境变量ly_jxsywy.logdir, Log目录,然后Log4jConfigListener执行加载log4j配置文件时,引用${ly_jxsywy.logdir}环境变量。
该项目在win7下用jetty启动没报错,在linux下以root用户启动tomcat也没报错;但是在Mac下,却报文中开始处错误提示。通过分析,应用启动没报错是巧合,启动报错才是正常,见下文原因分析。
四、报错原因分析
诚然根据web规范,Listener执行顺序是web.xml文件中出现的顺序,但是Listener执行前,Listener已经实例化,即先创建Listener对象,放在容器里,然后从容器里安个获取Listener并执行。上文提到的SqlmapConfigListener,构建该listener实例时,会初始化Log,而这时ApplicationListener还没有执行,看jetty控制台输出,我们就一目了然。因为ApplicationListener还没执行,所以环境变量ly_jxsywy.logdir为空,所以根据log4j配置文件,日志文件为/error_,mac下非root用户没有该文件的访问权限,所以就报启动错误。而win7下,jetty插件启动时,没有文件访问权限限制,所以没报错;linux下,tomcat是root用户启动的,所以也没权限问题。
SqlMapConfigListener constrcuted.
2018-07-03 14:12:03.224:INFO:/ly-jxsywy:main: No Spring WebApplicationInitializer types detected on classpath
2018-07-03 14:12:03.235:WARN:oejs.SecurityHandler:main: ServletContext@o.e.j.w.WebAppContext@311bf055...
ApplicationInitListener contextInitialized!简单解决方案,SqlmapConfigListener里把log去掉,或移到contextInitlized方法里。
虽然启动报错,但不影响应用访问,而且日志设置也没问题,后续的Log4jConfigListener会重新初始化Log。
更多推荐
所有评论(0)