logback、log4j、log4j2 全是以同一个人为首的团伙搞出来的(日志专业户!),这几个各有所长,log4j性能相对最差,log4j2性能不错,但是目前跟mybatis有些犯冲(log4j2的当前版本,已经将AbstractLoggerWrapper更名成ExtendedLoggerWrapper,但是mybatis 2.3.7依赖的仍然是旧版本的log4j2,所以mybatis使用log4j2会报错),说到日志,还要注意另一外项目SLF4J( java的世界里,记日志的组件真是多!),SLF4J只一个接口标准,并不提供实现(就好象JSF/JPA 与 RichFaces/Hibernate的关系类似),而LogBack是SLF4J的一个实现,下面介绍logback的基本用法
一、基本用法
1.1 maven依赖项
1 <!-- log --> 2 <dependency> 3 <groupId>org.slf4j</groupId> 4 <artifactId>slf4j-api</artifactId> 5 <version>1.7.7</version> 6 </dependency> 7 8 <dependency> 9 <groupId>ch.qos.logback</groupId> 10 <artifactId>logback-core</artifactId> 11 <version>1.1.2</version> 12 </dependency> 13 14 <dependency> 15 <groupId>ch.qos.logback</groupId> 16 <artifactId>logback-classic</artifactId> 17 <version>1.1.2</version> 18 </dependency>
1.2 配置文件logback.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <configuration scan="true" scanPeriod="1800 seconds" 3 debug="false"> 4 5 <property name="USER_HOME" value="logs" /> 6 <property scope="context" name="FILE_NAME" value="mylog-logback" /> 7 8 <timestamp key="byDay" datePattern="yyyy-MM-dd" /> 9 10 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 11 <encoder> 12 <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 13 </pattern> 14 </encoder> 15 </appender> 16 17 <appender name="file" 18 class="ch.qos.logback.core.rolling.RollingFileAppender"> 19 <file>${USER_HOME}/${FILE_NAME}.log</file> 20 21 <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> 22 <fileNamePattern>${USER_HOME}/${byDay}/${FILE_NAME}-${byDay}-%i.log.zip 23 </fileNamePattern> 24 <minIndex>1</minIndex> 25 <maxIndex>10</maxIndex> 26 </rollingPolicy> 27 28 <triggeringPolicy 29 class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> 30 <maxFileSize>5MB</maxFileSize> 31 </triggeringPolicy> 32 <encoder> 33 <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n 34 </pattern> 35 </encoder> 36 37 </appender> 38 39 <logger name="com.cnblogs.yjmyzz.App2" level="debug" additivity="true"> 40 <appender-ref ref="file" /> 41 <!-- <appender-ref ref="STDOUT" /> --> 42 </logger> 43 44 <root level="info"> 45 <appender-ref ref="STDOUT" /> 46 </root> 47 </configuration>
1.3 示例程序
跟前面log4j2的示例程序几乎完全一样:
1 package com.cnblogs.yjmyzz; 2 3 import org.slf4j.*; 4 5 public class App2 { 6 7 static Logger logger = LoggerFactory.getLogger(App2.class); 8 9 10 public static void main(String[] args) { 11 for (int i = 0; i < 100000; i++) { 12 logger.trace("trace message " + i); 13 logger.debug("debug message " + i); 14 logger.info("info message " + i); 15 logger.warn("warn message " + i); 16 logger.error("error message " + i); 17 } 18 System.out.println("Hello World! 2"); 19 } 20 }
运行后,会在当前目录下创建logs目录,生成名为mylog-logback.log的日志文件,该文件体积>5M后,会自动创建 yyyy-mm-dd的目录,将历史日志打包生成类似:mylog-logback-2014-09-24-1.log.zip 的压缩包,每天最多保留10个
二、与spring -mvc的集成
2.1 maven依赖项
注:${springframework.version},我用的是3.2.8.RELEASE 版本
1 <!-- Spring --> 2 <dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-core</artifactId> 5 <version>${springframework.version}</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework</groupId> 9 <artifactId>spring-beans</artifactId> 10 <version>${springframework.version}</version> 11 </dependency> 12 <dependency> 13 <groupId>org.springframework</groupId> 14 <artifactId>spring-context</artifactId> 15 <version>${springframework.version}</version> 16 </dependency> 17 <dependency> 18 <groupId>org.springframework</groupId> 19 <artifactId>spring-web</artifactId> 20 <version>${springframework.version}</version> 21 </dependency> 22 <dependency> 23 <groupId>org.springframework</groupId> 24 <artifactId>spring-webmvc</artifactId> 25 <version>${springframework.version}</version> 26 </dependency> 27 <dependency> 28 <groupId>org.springframework</groupId> 29 <artifactId>spring-expression</artifactId> 30 <version>${springframework.version}</version> 31 </dependency> 32 33 <!-- logback --> 34 <dependency> 35 <groupId>org.slf4j</groupId> 36 <artifactId>slf4j-api</artifactId> 37 <version>1.7.7</version> 38 </dependency> 39 40 <dependency> 41 <groupId>ch.qos.logback</groupId> 42 <artifactId>logback-core</artifactId> 43 <version>1.1.2</version> 44 </dependency> 45 46 <dependency> 47 <groupId>ch.qos.logback</groupId> 48 <artifactId>logback-classic</artifactId> 49 <version>1.1.2</version> 50 </dependency> 51 52 <!-- Servlet --> 53 <dependency> 54 <groupId>javax.servlet</groupId> 55 <artifactId>servlet-api</artifactId> 56 <version>2.5</version> 57 <scope>provided</scope> 58 </dependency>
2.2 web.xml里增加下面的内容
1 <!-- logback-begin --> 2 <context-param> 3 <param-name>logbackConfigLocation</param-name> 4 <param-value>classpath:logback.xml</param-value> 5 </context-param> 6 <listener> 7 <listener-class>com.cnblogs.yjmyzz.util.LogbackConfigListener</listener-class> 8 </listener> 9 <!-- logback-end -->
其中com.cnblogs.yjmyzz.util.LogbackConfigListener 是自己开发的类,代码如下:(从网上掏来的)
注:该处理方式同样适用于struts 2.x
1 package com.cnblogs.yjmyzz.util; 2 3 import javax.servlet.ServletContextEvent; 4 import javax.servlet.ServletContextListener; 5 6 public class LogbackConfigListener implements ServletContextListener { 7 8 public void contextInitialized(ServletContextEvent event) { 9 LogbackWebConfigurer.initLogging(event.getServletContext()); 10 } 11 12 public void contextDestroyed(ServletContextEvent event) { 13 LogbackWebConfigurer.shutdownLogging(event.getServletContext()); 14 } 15 }
1 package com.cnblogs.yjmyzz.util; 2 3 import java.io.FileNotFoundException; 4 5 import javax.servlet.ServletContext; 6 7 import org.springframework.util.ResourceUtils; 8 import org.springframework.util.SystemPropertyUtils; 9 import org.springframework.web.util.WebUtils; 10 11 public abstract class LogbackWebConfigurer { 12 13 /** Parameter specifying the location of the logback config file */ 14 public static final String CONFIG_LOCATION_PARAM = "logbackConfigLocation"; 15 16 /** 17 * Parameter specifying the refresh interval for checking the logback config 18 * file 19 */ 20 public static final String REFRESH_INTERVAL_PARAM = "logbackRefreshInterval"; 21 22 /** Parameter specifying whether to expose the web app root system property */ 23 public static final String EXPOSE_WEB_APP_ROOT_PARAM = "logbackExposeWebAppRoot"; 24 25 /** 26 * Initialize logback, including setting the web app root system property. 27 * 28 * @param servletContext 29 * the current ServletContext 30 * @see WebUtils#setWebAppRootSystemProperty 31 */ 32 public static void initLogging(ServletContext servletContext) { 33 // Expose the web app root system property. 34 if (exposeWebAppRoot(servletContext)) { 35 WebUtils.setWebAppRootSystemProperty(servletContext); 36 } 37 38 // Only perform custom logback initialization in case of a config file. 39 String location = servletContext 40 .getInitParameter(CONFIG_LOCATION_PARAM); 41 if (location != null) { 42 // Perform actual logback initialization; else rely on logback's 43 // default initialization. 44 try { 45 // Return a URL (e.g. "classpath:" or "file:") as-is; 46 // consider a plain file path as relative to the web application 47 // root directory. 48 if (!ResourceUtils.isUrl(location)) { 49 // Resolve system property placeholders before resolving 50 // real path. 51 location = SystemPropertyUtils 52 .resolvePlaceholders(location); 53 location = WebUtils.getRealPath(servletContext, location); 54 } 55 56 // Write log message to server log. 57 servletContext.log("Initializing logback from [" + location 58 + "]"); 59 60 // Initialize without refresh check, i.e. without logback's 61 // watchdog thread. 62 LogbackConfigurer.initLogging(location); 63 64 } catch (FileNotFoundException ex) { 65 throw new IllegalArgumentException( 66 "Invalid 'logbackConfigLocation' parameter: " 67 + ex.getMessage()); 68 } 69 } 70 } 71 72 /** 73 * Shut down logback, properly releasing all file locks and resetting the 74 * web app root system property. 75 * 76 * @param servletContext 77 * the current ServletContext 78 * @see WebUtils#removeWebAppRootSystemProperty 79 */ 80 public static void shutdownLogging(ServletContext servletContext) { 81 servletContext.log("Shutting down logback"); 82 try { 83 LogbackConfigurer.shutdownLogging(); 84 } finally { 85 // Remove the web app root system property. 86 if (exposeWebAppRoot(servletContext)) { 87 WebUtils.removeWebAppRootSystemProperty(servletContext); 88 } 89 } 90 } 91 92 /** 93 * Return whether to expose the web app root system property, checking the 94 * corresponding ServletContext init parameter. 95 * 96 * @see #EXPOSE_WEB_APP_ROOT_PARAM 97 */ 98 private static boolean exposeWebAppRoot(ServletContext servletContext) { 99 String exposeWebAppRootParam = servletContext 100 .getInitParameter(EXPOSE_WEB_APP_ROOT_PARAM); 101 return (exposeWebAppRootParam == null || Boolean 102 .valueOf(exposeWebAppRootParam)); 103 } 104 105 }
1 package com.cnblogs.yjmyzz.util; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.net.URL; 6 7 import org.slf4j.LoggerFactory; 8 import org.springframework.util.ResourceUtils; 9 import org.springframework.util.SystemPropertyUtils; 10 11 import ch.qos.logback.classic.LoggerContext; 12 import ch.qos.logback.classic.joran.JoranConfigurator; 13 import ch.qos.logback.core.joran.spi.JoranException; 14 15 public abstract class LogbackConfigurer { 16 17 /** Pseudo URL prefix for loading from the class path: "classpath:" */ 18 public static final String CLASSPATH_URL_PREFIX = "classpath:"; 19 20 /** Extension that indicates a logback XML config file: ".xml" */ 21 public static final String XML_FILE_EXTENSION = ".xml"; 22 23 private static LoggerContext lc = (LoggerContext) LoggerFactory 24 .getILoggerFactory(); 25 private static JoranConfigurator configurator = new JoranConfigurator(); 26 27 /** 28 * Initialize logback from the given file location, with no config file 29 * refreshing. Assumes an XML file in case of a ".xml" file extension, and a 30 * properties file otherwise. 31 * 32 * @param location 33 * the location of the config file: either a "classpath:" 34 * location (e.g. "classpath:mylogback.properties"), an absolute 35 * file URL (e.g. 36 * "file:C:/logback.properties), or a plain absolute path in the file system (e.g. " 37 * C:/logback.properties") 38 * @throws FileNotFoundException 39 * if the location specifies an invalid file path 40 */ 41 public static void initLogging(String location) 42 throws FileNotFoundException { 43 String resolvedLocation = SystemPropertyUtils 44 .resolvePlaceholders(location); 45 URL url = ResourceUtils.getURL(resolvedLocation); 46 if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) { 47 // DOMConfigurator.configure(url); 48 configurator.setContext(lc); 49 lc.reset(); 50 try { 51 configurator.doConfigure(url); 52 } catch (JoranException ex) { 53 throw new FileNotFoundException(url.getPath()); 54 } 55 lc.start(); 56 } 57 // else { 58 // PropertyConfigurator.configure(url); 59 // } 60 } 61 62 /** 63 * Shut down logback, properly releasing all file locks. 64 * <p> 65 * This isn't strictly necessary, but recommended for shutting down logback 66 * in a scenario where the host VM stays alive (for example, when shutting 67 * down an application in a J2EE environment). 68 */ 69 public static void shutdownLogging() { 70 lc.stop(); 71 } 72 73 /** 74 * Set the specified system property to the current working directory. 75 * <p> 76 * This can be used e.g. for test environments, for applications that 77 * leverage logbackWebConfigurer's "webAppRootKey" support in a web 78 * environment. 79 * 80 * @param key 81 * system property key to use, as expected in logback 82 * configuration (for example: "demo.root", used as 83 * "${demo.root}/WEB-INF/demo.log") 84 * @see org.springframework.web.util.logbackWebConfigurer 85 */ 86 public static void setWorkingDirSystemProperty(String key) { 87 System.setProperty(key, new File("").getAbsolutePath()); 88 } 89 90 }
2.3 JBOSS EAP 6+ 的特殊处理
jboss 默认已经集成了sf4j模块,会与上面新加的3个类有冲突,app启动时会报错:
java.lang.ClassCastException: org.slf4j.impl.Slf4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
所以,需要手动排除掉jboss默认的slf4j模块,在web-inf下创建名为jboss-deployment-structure.xml的文件,内容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <jboss-deployment-structure> 3 <deployment> 4 <exclusions> 5 <module name="org.slf4j" /> 6 <module name="org.slf4j.impl" /> 7 <module name="org.slf4j.jcl-over-slf4j" /> 8 <module name="org.slf4j.ext" /> 9 </exclusions> 10 </deployment> 11 </jboss-deployment-structure>
2.4 最后将logback.xml放到resouces目录下即可(打包后,会自动复制到classpath目录下)