java web开发中的日志的配置与原理
1. 在web.xml中需要配置一个日志配置监听类Log4jConfigListener,这样在服务器启动时就是读取和初始化的日志文件:
?
<!--日志--><context-param> <param-name>log4jConfigLocation</param-name> <param-value>WEB-INF/log4j.xml</param-value></context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener>
?
? 2.? 在类中通过一个工厂方法得到一个Log对象:
?? 比如:
? private static final Log LOGGER = LogFactory.getLog("system");// 日志
? 3. 在上面配置的log4j.xml中配置:
?
<logger name="system" > <level value="${logginglevel}"/> <appender-ref ref="system"/> </logger> <appender name="system" value="${loggingRoot}/system.log"/><param name="append" value="false"/><param name="encoding" value="GB2312"/><layout value="%d [%X{requestURIWithQueryString}] %-5p %c{2} - %m%n"/></layout> </appender> ????? 其中的配置变量在antx.properties中配置和获取。
?
原理:其实就是通过在jboss或comcat的服务器启动的时候,会执行监听类Log4jConfigListener中的初始化方法(??),这个监听类在web.xml中要在ContextLoaderListener之前配置:
?
/** * Bootstrap listener for custom log4j initialization in a web environment. * Delegates to {@link Log4jWebConfigurer} (see its javadoc for configuration details). * * <b>WARNING: Assumes an expanded WAR file</b>, both for loading the configuration * file and for writing the log files. If you want to keep your WAR unexpanded or * don't need application-specific log files within the WAR directory, don't use * log4j setup within the application (thus, don't use Log4jConfigListener or * Log4jConfigServlet). Instead, use a global, VM-wide log4j setup (for example, * in JBoss) or JDK 1.4's <code>java.util.logging</code> (which is global too). * * <p>This listener should be registered before ContextLoaderListener in <code>web.xml</code> * when using custom log4j initialization. * * @author Juergen Hoeller * @since 13.03.2003 * @see Log4jWebConfigurer * @see org.springframework.web.context.ContextLoaderListener * @see WebAppRootListener */public class Log4jConfigListener implements ServletContextListener {public void contextInitialized(ServletContextEvent event) {Log4jWebConfigurer.initLogging(event.getServletContext());}。。}??然后调用Log4jWebConfigurer的initLogging(。。)方法:
?
/** Parameter specifying the location of the log4j config file */public static final String CONFIG_LOCATION_PARAM = "log4jConfigLocation";/** Parameter specifying the refresh interval for checking the log4j config file */public static final String REFRESH_INTERVAL_PARAM = "log4jRefreshInterval";/** Parameter specifying whether to expose the web app root system property */public static final String EXPOSE_WEB_APP_ROOT_PARAM = "log4jExposeWebAppRoot";/** * Initialize log4j, including setting the web app root system property. * @param servletContext the current ServletContext * @see WebUtils#setWebAppRootSystemProperty */public static void initLogging(ServletContext servletContext) {// Expose the web app root system property.if (exposeWebAppRoot(servletContext)) {WebUtils.setWebAppRootSystemProperty(servletContext);}// Only perform custom log4j initialization in case of a config file.String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);if (location != null) {// Perform actual log4j initialization; else rely on log4j's default initialization.try {// Return a URL (e.g. "classpath:" or "file:") as-is;// consider a plain file path as relative to the web application root directory.if (!ResourceUtils.isUrl(location)) {// Resolve system property placeholders before resolving real path.location = SystemPropertyUtils.resolvePlaceholders(location);location = WebUtils.getRealPath(servletContext, location);}// Write log message to server log.servletContext.log("Initializing log4j from [" + location + "]");// Check whether refresh interval was specified.String intervalString = servletContext.getInitParameter(REFRESH_INTERVAL_PARAM);if (intervalString != null) {// Initialize with refresh interval, i.e. with log4j's watchdog thread,// checking the file in the background.try {long refreshInterval = Long.parseLong(intervalString);Log4jConfigurer.initLogging(location, refreshInterval);}catch (NumberFormatException ex) {throw new IllegalArgumentException("Invalid 'log4jRefreshInterval' parameter: " + ex.getMessage());}}else {// Initialize without refresh check, i.e. without log4j's watchdog thread.Log4jConfigurer.initLogging(location);}}catch (FileNotFoundException ex) {throw new IllegalArgumentException("Invalid 'log4jConfigLocation' parameter: " + ex.getMessage());}}}? 通过它打印出的日志,去查看服务器启动时打印出的日志server.log的最后一行日志是:
?
2012-09-14 09:30:08,609 INFO [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/]] Set web app root system property: 'webapp.root' = [D:\all_project\riskm8.3\riskm-web\target\exploded\riskm-web.war\]2012-09-14 09:30:08,609 INFO [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/]] Initializing log4j from [D:\all_project\riskm8.3\riskm-web\target\exploded\riskm-web.war\WEB-INF\log4j.xml]
?可见是服务器启动后的加载sprng bean容器的日志是通过log4j.xml的配置打印到了应用的具体路径下的日志文件里的,
? 然后调用:Log4jConfigurer.initLogging()
/** Pseudo URL prefix for loading from the class path: "classpath:" */public static final String CLASSPATH_URL_PREFIX = "classpath:";/** Extension that indicates a log4j XML config file: ".xml" */public static final String XML_FILE_EXTENSION = ".xml";/** * Initialize log4j from the given location, with the given refresh interval * for the config file. Assumes an XML file in case of a ".xml" file extension, * and a properties file otherwise. * <p>Log4j's watchdog thread will asynchronously check whether the timestamp * of the config file has changed, using the given interval between checks. * A refresh interval of 1000 milliseconds (one second), which allows to * do on-demand log level changes with immediate effect, is not unfeasible. * <p><b>WARNING:</b> Log4j's watchdog thread does not terminate until VM shutdown; * in particular, it does not terminate on LogManager shutdown. Therefore, it is * recommended to <i>not</i> use config file refreshing in a production J2EE * environment; the watchdog thread would not stop on application shutdown there. * @param location the location of the config file: either a "classpath:" location * (e.g. "classpath:myLog4j.properties"), an absolute file URL * (e.g. "file:C:/log4j.properties), or a plain absolute path in the file system * (e.g. "C:/log4j.properties") * @param refreshInterval interval between config file refresh checks, in milliseconds * @throws FileNotFoundException if the location specifies an invalid file path */public static void initLogging(String location, long refreshInterval) throws FileNotFoundException {String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);File file = ResourceUtils.getFile(resolvedLocation);if (!file.exists()) {throw new FileNotFoundException("Log4j config file [" + resolvedLocation + "] not found");}if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);}else {PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);}}??? 这样就读取了log4j.xml的工程中用到的日志的配置,然后相当于生成了一个日志容器,然后通过工厂方法就可以获取和生成配置文件配置的具体的日志对象,然后把日志打印到相应的文件中。
?
?