笑话/slf4j的简单用法以及与log4j的区别
之前在项目中用的日志记录器都是log4j的日志记录器lZ5lQ3bqfpw7n7,KgSXL可是到了新公司发现都是slf4jyOXCJUo1GFcDBv,6F6PW6YCQtDcK于是想着研究一下slf4j的用法hM4lYQo1Qk8。pjQ8E   注意:每次引入Logger的时候注意引入的jar包wIr2P7,CbvP2REAfh因为有Logger的包太多了9Yj6C3。52F4MB6LM8HBZ。qeNc08jutceRYkr837。4m5x33HsTZ6750nf2z7。05TC0i87Q3aoy389。446D211wBvj99Y73NVflB。mVaPfs7     Logger必须作为类的静态变量使用8JjbJwg3Dac。7Qp5e8u43qn原因如下: 1 使用static修饰的属性是归这个类使用的 2 也就是说不论这个类实例化多少个b9ni4425TJtB,xg24F5Duy9ozZ7大家用的都是同一个static属性 3 log4j记录的是当前类的日志XpIMv3r5o,21z04O不是每个实例的日志 4 所以只要有一个记录就可以了 创建日志记录器方法:(最好声明加final关键字) //private static final Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日志记录器RI4kxjc1Lq2 A4GmvKI36F6f private static final Logger logger = LoggerFactory.getLogger(Slf4jTest.class.getName());// slf4j日志记录器 简要记录一下日志级别: 每个Logger都被了一个日志级别(log level)7V9DA9,3vVZ2w99As0lA9用来控制日志信息的输出pr8Oi4bxu。68e1q日志级别从高到低分为Gyhnl4wiGpRI:E1L0PFomV1R0YgOJlt4 G2pJGZaA5B1Xu:V8A7x95OEroff         最高等级qazNnm22,IZJLkk0nFIRe用于关闭所有日志记录jinedB7。Y2l7smtL363w1wxP9Y0S4XgOWmMI QQwQfEB4MYx9sFW:DXLk9414L8mDfatal       指出每个严重的错误事件将会导致应用程序的退出u71nG16790。fBgMMExf5ovwG03K644k6 ECr39K742BC4Pa7GdRZJ:vVAm7uqerror      指出虽然发生错误事件m3s6L7gcd1q,WGwRpz但仍然不影响系统的继续运行1Bni3e18。W1G944i56cyZrJXWhNoN4DYy eQ68kmenqzGAVDQI6XdWoh9dzRN:S88a44KYwarm     表明会出现潜在的错误情形0RK40UoM。463QX75yfp65OLo T7y7zTT3xngEI4Td0k3ay9:LB4latinfo         一般和在粗粒度级别上bGnd25iT,rlxi9HaQRK强调应用程序的运行全程5XJHvaMjS0S2。3zzQhyI1CaPHv5R4 kLnL1c45ZTl08WF70rWb663E37:p4Y979rUk4LZJdebug     一般用于细粒度级别上9S2h8,5dFpx9JM对调试应用程序非常有帮助9NGx31iMZ。xR7im9h3uyp85ULCC42x yLU9YUSGI39Gqe92SVLb:qZqWujzall           最低等级I338xp,n9saOf48用于打开所有日志记录5jEMJ。CU7gMGW 其实对于不同的版本有不同的级别5Z9K2U3p,sww7CXfw8S1M12不过最常用的就是debug\info\warn\error.下面是摘自log4j-1.2.17.jar中的级别: 可以看出:all\TRACE\debug同级别O750P5zHPGt35。NN97R6vW0Lwoff与fatal同级别fFNsvQM803Eib8。QH1h4Q2N1 package org.apache.log4j;d4x87IsXW4 oCf3NUf4Zi0import java.io.IOException;bNd7j4ln0w2yQ V1odx6rYimport java.io.ObjectInputStream;5q7tl9592 IF3I2B4bnd7OIimport java.io.ObjectOutputStream;fBU5Eu UNs40mrimport java.io.ObjectStreamException;27Hdi250w3buj pQmd3ELoimport java.io.Serializable;GCqx6lOOMz6b Tmp1T9vP9FOk0qk7w 6TY6o50i3BdcGYN76KW55T8wQfM sjsmqN3CmM7public class Level extends Priority implements Serializable {jZaxv 813P4kO0dvAhSmxL26LNFTPjQe Z91He653V8   /**edy7Q X3R96xKtq    * TRACE level integer value.WKJ8Ih48x3 eD9nf35A0Ni    * @since 1.2.12vRHO5fGA ZEy6PR4    */A8xjL2lPx3X 6EZUs6E2KcsH3 public static final int TRACE_INT = 5000; IY1d3n7kZut eRt4XNN0hsPKZ final static public Level OFF = new Level(OFF_INTdUI3P338oA7cqR,926mxfH "OFF"Fte0bj6VS4Rj,r7hWwZy 0);C0M74A38dBg H0J1kAYZjzz78R0YxYZQ rOMCt8UPyH6d final static public Level FATAL = new Level(FATAL_INTT8ShCGUsm,m7v703q89e513 "FATAL"F88I0V3sw,6IMArux 0);1SpF02hz0Rpih4 uzBrBfie3N5BYBjPJE5w2T x6S2A8cqE21vB final static public Level ERROR = new Level(ERROR_INT8PJX7,fo3o8 "ERROR"J0f1ec68J5Tq8,A2FPoB1YZ1G8 3);5H8nx0f5tgQ j0beFp9tw7021fo3H R74b74z6lF final static public Level WARN = new Level(WARN_INTY6hl7wB9,54UhA555I "WARN"8dE9F2d2gznm,ol3WSDYm32 4);pQ41UL88k QUcNPBZC2x0WX78M JYrcv2nx final static public Level INFO = new Level(INFO_INTByV3h,p24ghRDTN0t26 "INFO"4Cyhfy0B2UeH,oR62eWd0qu2wY 6);M5gtuSj1Pnwz Vi694Um022GJr7 ODCg8QxhNJMLL final static public Level DEBUG = new Level(DEBUG_INTD5Qb88LUcth,47rdBTDYAVEua "DEBUG"DXdYbYH0g,U20P0qXNC 7);Dn51npjNO 0pAg53g4I8V 5rrRV99E49Jglu public static final Level TRACE = new Level(TRACE_INTpTZFp,mD6d0O81Qj59aq "TRACE"62p61j,gvv1FWH92o540 7);Vkg4r54B30 23Vz4ASBae5AnQ7 uBYQcnuJTrawg final static public Level ALL = new Level(ALL_INTNbMjdk,TC62D88VDIol "ALL"aYtQ2Q,p2xms4QAF 7);w14378Q4v2J me6f593A85dkp57KL4c 2CD8RI static final long serialVersionUID = 3491141966387921974L;F3K9yvrc8h qUjdK1atY9jCuAy848i04 XE11S protectedbZusU8AMd26R8T 82jGyn974  Level(int level59rZVIRUSg1K,IbuQVY46cHU String levelStrm7J8h9,I5bm6dRL87jl int syslogEquivalent) {taU352417t1a 66VZ9Ct6    super(levelD85ojl9e,9eYbb2S55I levelStrSWz5z9MX6,1tMV9XI19L syslogEquivalent);98qyMzpa93v bNB8V69ZyV9N  }5ANUC4y 8Q27kGnXOBtTSxyCv0 yo6qh7zZPgb58003 Qpmp9546mT  DzguQ BJ2o03ZE1nVm22 public8kyjox0S5f7T9J GxT443au static1Cz2D wcC5rp7N0aJeA  Level toLevel(int valD51uWnO1zVHkic,uWZayer4nh Level defaultLevel) {jqys2x18 6r46z5GU8    switch(val) {1k7OQ T0SkKA    case ALL_INT: return ALL;UMe8274lO3 Qm76ECxG5    case DEBUG_INT: return Level.DEBUG;1xY04IgS 4UjV21Dg2rZ    case INFO_INT: return Level.INFO;0wri8Jf s5L1W55    case WARN_INT: return Level.WARN;9Bkpu0sO4d3JT 1tnjM    case ERROR_INT: return Level.ERROR;y7Jki5vL92 6DgMfu    case FATAL_INT: return Level.FATAL;1gu67j6sS 0T4zT8T    case OFF_INT: return OFF;z302xt NS39Q98f    case TRACE_INT: return Level.TRACE;KUNyg55Fwfs lLVytV5    default: return defaultLevel;7R8t4I FO3FxTDU76j3    }ius12R23 GCydTAaA  }nU7351 ZNO4DoiHmNb。uiyDG8Dc68BiAWvG。gGK31404luJbvLSaKjce。68pu4F83N7zT1bbb。88G5aaGz1YH4N8P791uz。147U7F8fY 0.依赖的Jar包 HrpYg eQk9U 8WKUDY1cscDiHf 94luJl71 org.slf4jKD2W8f bmEW1DBAl slf4j-apie2L3JXso m18R2 1.7.256yrhFab2FQ h377Y1w0 6JbPH6x2Y 5kWN6 VULij204x u7I8x7mG3F org.slf4j40QdB2z9g4T RQ50u8C slf4j-log4j128FI8z69H7 6GvRnFWT1hV 1.7.5fNBAm P3p19 C1R66 s9i80l wSHke45jVG05 R161Njmc org.apache.logging.log4j47gSHsD UG2505UZ1 log4j-api3g6oz9 271pNhP 2.0-rc182vt7J5nd2B qels8ZnAjGj68F b59241T3P8V q179X E6Ww8VvwPNZ 1OCWlfW8f13 org.apache.logging.log4jvK5l8 axuExZhrHbw86p log4j-coreFbwt2szX04 0N44xux3W9YnvM 2.0-rc106qW10TDbV1 6xDza 或者手动导入下面的包: 介绍:slf4j-api提供接口YMHQn5u,j5giyy10HJslf4j-log4j提供具体的实现4X7V4DG17T。oPsQl也就是 slf4j只是一个日志标准76aZ9Bh35Y8,T449x并不是日志系统的具体实现S4s7VM1,QvSYYonm0cck5如果项目只有slf4j的包是没有办法实现日志功能的6Gs5JPZ。NsH0oVKqj 1 基本介绍   SLF4J不同于其他日志类库396h7af4OWT2,65C0clKR与其它日志类库有很大的不同9SU6jjH。LA32pSLF4J(Simple logging Facade for Java)不是一个真正的日志实现64h0aqXbeqoN,8X4r83C而是一个抽象层( abstraction layer)sY89sn9l36V,MklF5G7LK它允许你在后台使用任意一个日志类库ZK1BR8A4IYR15Q。NUNyW如果是在编写供内外部都可以使用的API或者通用类库cz7RUs5hUmz,TJ7hGuDL95e4那么你真不会希望使用你类库的客户端必须使用你选择的日志类库FKH3C。izUz18   如果一个项目已经使用了log4j6X7Ar72N,Uhc585Pb5GpL而你加载了一个类库l0q76v0s1eM9a,oK0Y96比方说 Apache Active MQ——它依赖于于另外一个日志类库logbackTMmGK,lzUNpEb2AHMw那么你就需要把它也加载进去rZh9u。0N60B但如果Apache Active MQ使用了SLF4J40jXZYS,56N25你可以继续使用你的日志类库而无需忍受加载和维护一个新的日志框架的痛苦prLOUWa30qDp。1iE79L1   总的来说VI729bR6d,C2xg8t9GdCSLF4J使你的代码独立于任意一个特定的日志APIz61ez5v7Fi09,D9CIrQr这是对于API开发者的很好的思想64h11r6z7APx5。kke1Ui9fKs虽然抽象日志类库的思想已经不是新鲜的事物V5PPC9ng,M2507N而且Apache commons logging也已经在使用这种思想了D10dZq8As8,942ekGIj但SLF4J正迅速成为Java世界的日志标准IJrr69OuC。7fsdQWQ42735D让我们再看几个使用SLF4J而不是log4jt53N0qmv1p0JSA、5BcC56QV5vLF2logback或者java.util.logging的理由n4983hf87OUm。3rePLGBI 2 SLF4J对比Log4JaTFIZr,b87NSHstpQ0logback和java.util.Logging的优势 正如我之前说的Yad70QD16b,Ve9w4FcNYwfKI在你的代码中使用SLF4J写日志语句的主要出发点是使得你的程序独立于任何特定的日志类库R1lx8261L8Q,9rX119A依赖于特定类库可能需要使用不同于你已有的配置Ymr2dtG6g,j50o2wErCGC并且导致更多维护的麻烦0z45X65ArTHsM。DfZKbQ除此之外nb1qtqD7KD,rmtvvi还有一个SLF4J API的特性是使得我坚持使用SLF4J而抛弃我长期间钟爱的Log4j的理由FPYlIr4GH,9Uj5k3824sHG是被称为占位符(place holder)pEV01PWaUeNzD2,dcD1GA62FpI在代码中表示为“{}”的特性HyAWB。ifuHvlw4t11tR占位符是一个非常类似于在String的format()方法中的%shc8PLMi35Qz8,osP3a4mGW16dy因为它会在运行时被某个提供的实际字符串所替换0w4gmfMPx7c。05T0y这不仅降低了你代码中字符串连接次数4gQgVvA9rOI0,M06ZAji82L9iQ而且还节省了新建的String对象BOyLmJEa1o3。RKGnheVcVEB通过使用SLF4Jd7F7EB6ikU,NrqkKu66S7tk你可以在运行时延迟字符串的建立7U8y9M5ZpM,0T7Z4vqz1这意味着只有需要的String对象才被建立yN5RY。umhYte而如果你已经使用log4jJucBE,4396pp2zyD那么你已经对于在if条件中使用debug语句这种变通方案十分熟悉了943Z3y,5k9MS46f但SLF4J的占位符就比这个好用得多08he3q2。k1nw3 3.slf4j的简单用法 1.简单使用 1.配置文件(log4j.properties) log4j.rootLogger=debugCz6JDyY3fu,fiax50hN CJEu7VL73zmO0B iwCP53pcoAc989xQVNW 8621nlGlog4j.appender.A=org.apache.log4j.ConsoleAppender4KucioH JW2o39log4j.appender.A.layout=org.apache.log4j.PatternLayoutZ5jgB5V6m5C aqPHZg9nlog4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%ndk1A64 322Hj5TX1NsnCxNCjDLd623 VM56ndRIF4log4j.appender.B=org.apache.log4j.FileAppenderyg65v7C EXt1QoKlog4j.appender.B.File=E:\\log.logiqqwgJz2 pQegVM99355P67log4j.appender.B.layout=org.apache.log4j.SimpleLayout681084M3B 565X2YDIvSgV2521RkLi5v3 2ge3439Lalog4j.appender.C=org.apache.log4j.RollingFileAppendericsf4MG3CQiOm0 JS362u5e8xklog4j.appender.C.File=E:\\log.htmlvdku4zYa6 xRyTu8fktjlog4j.appender.C.MaxFileSize=1000KBjaLWZkuwd918D KmeRFVpqW2rlog4j.appender.C.MaxBackupIndex=10ULQR0MWNn6i727 tLxk132b75zlog4j.appender.C.layout=org.apache.log4j.HTMLLayout4kDs6rgY410 1GcSwalog4j.appender.C.encoding=gbk2NS7367BEH 0GIc0uYFgtY4FI2F25 P6FFshdwj5u1log4j.appender.D=org.apache.log4j.DailyRollingFileAppenderwqDX5Aub 0vBKouc42YV4log4j.appender.D.File=E:\\log.loghQ11IOcN 34NKcqy8hlog4j.appender.D.layout=org.apache.log4j.TTCCLayout 注意:     1.如果需要输出到多个位置的时候可以逗号隔开1m97O,AlkLj3比如: log4j.rootLogger=infor73nPvn75fN,3kE0MmC AvW2Z7bIqcP1RpZ,Rjqm9Sgp B   2. log4j.appender.C.encoding=gbk 的配置是为了解决中文乱码j2Ytodefz,o05IFxBq有时候也可以设置为UTF-8试试 关于pattern的设置如下: %p: 输出日志信息优先级cBuo8c8,SGI6rCL94xrtY7即DEBUGK7N3X24lrbC59,8pz618INFOgdkA4,1iy7hk3WARNVrAxD,9ywVeKI8VERROR1e5bsNHGx,M15hj7892FATALnPSs5IynIq,LQAYNIDG4g%d: 输出日志时间点的日期或时间43E4yaq1,Ul5s4I4qC默认格式为ISO86015sEak,3M95fyffq6IZ也可以在其后指定格式9DgW56eI53G,9r7U22比如11UZN:9DS52sjc0Hu6P%d{yyyy-MM-dd HH:mm:ss3DKZ6kD,4WGeB130FSSSS}M7aVp60Xajx2zY,3P4M5输出类似7iqkNIfaYp:Dhu2QAJA6dsuBw2011-10-18 22:10:283vf7pRm3D96,y9nV48Io921 41sds53Z lDhDbyKT%r: 输出自应用启动到输出该log信息耗费的毫秒数 JJsPuZo20C 0lrysxMvdt0%c: 输出日志信息所属的类目WOAUNBiW,ihU49通常就是所在类的全名 PV2YPCwcn Rx292CW%t: 输出产生该日志事件的线程名 nM125a9 OtrVmYr26u1Za5%l: 输出日志事件的发生位置w81rta1821,o7m32jtnE51MUo相当于%C.%M(%F:%L)的组合xOHM3BU3o7eIQ,5k27m9MB包括类目名5fev05oj2z0、GA099FKCJJorJ发生的线程Jt41Zb3L0bI,4lVSHCr5VHvX以及在代码中的行数9ZC3f6O。Fj9hMJpI0Cz ZGUE23 N3da4%x: 输出和当前线程相关联的NDC(嵌套诊断环境)TpYnGAS57tMM,RBVPf3Cm5LH尤其用到像java servlets这样的多客户多线程的应用中ZhnqV。WXks6oZc6WC4l zxM227AhawRR u1w4msG69C6%%: 输出一个"%"字符 1lPahC3B9m36 Mlr5j4%F: 输出日志消息产生时所在的文件名称 8k0BjgA hf836m9Ktx%L: 输出代码中的行号 H668BC8VnE0rk RYBUEyl4095%m: 输出代码中指定的消息1mDQ4m5Xc,ZI2GXf1BL1Nt1产生的日志具体信息 429999BISoP1d6 fEVL34bQOFDz4S%n: 输出一个回车换行符5mx4Ebi,oRm56FiNWindows平台为"\r\n"G1pBej91n1i,6K6Zgt5Unix平台为"\n"输出日志信息换行 2.测试代码: package cn.xm.exam.test;6423OZ0V1C6 L6a58l42LZbI4lsqn043jN 1U1lsVKXimport org.slf4j.Logger;BCX7a j5yLf1rm08eimport org.slf4j.LoggerFactory;RPXEi1GR7F7t M24o31915gm33eTjGs5e45 0Sm7tIJXYQ4l8public class Slf4jTest {pyO5bKY3X06c 1F27SxL7    private static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日志记录器d5q73nf54 11Pf1EOk991rklwTU1 2jSjH33pIRMk public static void main(String[] args) {03o7t37k NO6y4Sf5F7aKILozXK b6cZ8ekn2        // 普通的日志记录DN8QQ 6Oxx7 logger.debug("普通的日志记录");mWG0F090oD FQNvOz4coeRtX4tLzx4l GDM1qEwj        // {}占位符记录日志QRCj4T7 RdPvbs54ql7NTP for (int i = 0; i < 3; i++) {7zy1G67ABm 6aAeT17F            logger.debug("这是第{}条记录"uB4rue6a1,02Ww2 i);pDP53n0gw1 d96RJXPQW        }s24YMUiMpSHk57 JJwrn5jLtaFfIau170 P0lZjJ0rti1        // 用\转义{}zDOzC8306B38K1 IaC482ckbOn95 logger.debug("Set \\{} differs from {}"F32vy1H7f6,vZ68r "3"); // output:Set {} differsV02842t3 r913Zyo                                                        // from 33HGJRCxzV0 9ibK1AAtxe5qVb82Ou0KZ9 838An3Jk        // 两个参数26ZqC I3WGhC logger.debug("两个占位符09T1Y,7T8glDrJj可以传两个参数{}----{}"llJB964s8z0,qIhd7S 16C009B03y7,o4aS05i 2);0C0DOH6Nj 0gmc98hoVB5FXwy5XJ5z9 7m4c56BDu26ns        // 多个参数(可变参数)4NCbswG 23dSuAotss4Byx logger.debug("debug:多个占位符gV92btmKvy,144s6{}zV1PSPmSvno58V,Izrbxv{}o6mj20dfA,350Gcw{}88jfi,cVb1nwj88qCB{}"4I1zkpT,q96jQQ0K 1hg47r,TvGT0eb 2e40Oxo,Vz1IK4eTyQff 3E4DQJ1L5EQG20,32xP5OYn 4);d7sWNx32e 9M4w6U1L718q3JZ8lV4 mKi7147tP6        // 多个参数(可变参数)7nsZRUE ehYuOq4xC logger.info("info:多个占位符2O1S18k,AnTfE{}R8035L8DhiM,71D9gXk9IO{}h40s2yD9,6t8u2aStw6H1T{}lWrd1Vj72,8l80xxpZ1vO7{}"u9Hvy7ML,8AH8ovge 1X8L783OyqcCZB4,1Z7Os2Pp4C7H 2C5161,ahb5guqSso2kBK 32NtaCvVcKh9br3,48mp9qtZbuN 4);2FC7y69Jii 3sGxlk6G5nj2m GO0a651g7hO3        // 多个参数(可变参数)giNaVq 6A7ZfIx0yEP logger.error("error:多个占位符IZ6YEbBEXY,HTDC13u0d4nBq{}9so6vX0,6d61S8NuO3Z{}uhxY5xrFKEQL9T,P0m38nh2r003W{}eH49A78wURL5,Jdn6f3{}"L4Qa9Pj,45KdH 1fKCk94Gv,cxC8YJbs7HuA0D 2cvxRFYX,Hzc1xZ 36Q709sx5fMM3o,hs2p26J9x 4);Nqun1TAQj qB4JTKBVRUjeWCgE7z xizXh    }76090ECs00M aYE4L1O05ian1pPq8964UyH Sxm7BQe0SSrXv} 结果: 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 普通的日志记录 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 这是第0条记录 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 这是第1条记录 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 这是第2条记录 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] Set {} differs from 3 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] 两个占位符07xB3qteRLUh,bp6i3KEdFcG可以传两个参数1----2 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[DEBUG] debug:多个占位符q0873QKJ,yc88WEve1Yk9M7h4Y54,37Z4N05qG62g7F3QZAdxKlA,knPEiC9E3W1l7SJ2so,Js83yms02D3Y4 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[INFO] info:多个占位符T55ms40x3D8B2,wAC731glo4GqqPJi7w7,Q36L4H2VzO2t,oQba8I052bi354j407,46NgQI5uBcRv6e4 2018-08-18 10:58:38 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:多个占位符iII3NuUdXWXD,JU1Ug4B1y5zjbvg5W439V,5risV1cRL2EFN5v4329,t90Ae2KUS5g3B93Ha884Fp0TJj,806Wj8VDAIgrP4 注意:debugi12dO1ry,ttXMry1PE1infon2mt5FeN9mJz,Ebmyq5sEqkl1erroru52Q5a,3p7vA4等各个级别的方法都可以传入多个可变参数: 至于详细的日志级别的介绍参考我的另一篇博客:http://www.cnblogs.com/qlqwjy/p/7192947.html 2.关于正式开发中的日记记录的方法:(重要)   项目中日志记录还是有很多说法的ZqHvV3sPQVU,9N5ItoSTAXr6G比如保存日志级别zoAc05,6hbmkL7g8日志应该打印的信息C2VR8jC3oz,dfD11日志参数的设置等: 1.一般是将捕捉到的Exception对象作为日志记录的最后一个参数(会显示具体的出错信息以及出错位置)270Rva61IoijuO,54Ddys5而且要放在{}可以格式化的参数之外g86s4F6DyS1c0z,0lskJ6qD6Gi防止被{}转为e.toString() 例如一个标准的日记记录的方法: package cn.xm.exam.test;EdbIk7AW dp83cKs4A5xz800MH69A v3V82Yimport java.io.File;sfhkE5989E 3xNf350Wimport java.io.FileInputStream;IqN89G0e0lL9O D5486U3tOfvC5import java.io.FileNotFoundException;90olhO60lky3pL 5pc4cUX8import java.io.InputStream;qsW8cRmc540 02y4wBU8V4kFdZ QLg80yAs4zimport org.slf4j.Logger;80RuVgXI zNWOmxff5Pqimport org.slf4j.LoggerFactory;kBvx4ru5799521 U63x0sL4bZ7fKFq6AMB2fcV44 13G0e337public class Slf4jTest {90hiDPME4 iHu4vYTOF67lOC2omJNbwoNL7 Gh7Wwm0Q5    private static Logger log = LoggerFactory.getLogger(Slf4jTest.class);hbx32MYa 72h0V3I33d7cZ18299NIw6tVR 6efSn4gs    public static void main(String[] args) {OGI9HllnS5lo9 i6d8M06        openFile("xxxxxx");3onb2tb6ba1hd 2Pv29RL88z    }Q74kCVs jAxcml1vWHkPXM57nQJ 2N9d2rr6iB7    public static void openFile(String filePath) {r995m T57kgqkvuf67        File file = new File(filePath);IGE7T1Sa o50FO        try {gdz7X 8UM41r3Q            InputStream in = new FileInputStream(file);7SMO6 cmfJf8        } catch (FileNotFoundException e) {yH31QJ689 ufb0v0            log.error("can found file [{}]"51QhQ2Y4,O44co0910Kf filePathy4LwNKCzW6S0L,V7Z4wFEWN43iR5 e);osaJ53o 1F9W1CkZ2        }56Pd3028yt 0wCgw    }J9jY5qNUbf 946cwaGnGg4d6j 14564Cy} 结果: 2018-08-18 10:50:03 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx]WDDUPT8 xTtaKUUS2CUmjava.io.FileNotFoundException: xxxxxx (系统找不到指定的文件n5SniLW。2EbZlv)7yiz9b96Ux J9F17    at java.io.FileInputStream.open(Native Method)GMCrtc30J 5u7CGb0t    at java.io.FileInputStream.(FileInputStream.java:146)yDOA6w6hQl FqLj2pPB7eOvD    at cn.xm.exam.test.Slf4jTest.openFile(Slf4jTest.java:22)5p576LJo01wsz 89SVH05jW    at cn.xm.exam.test.Slf4jTest.main(Slf4jTest.java:16) 注意: {}的作用是调用对应参数的toString()方法格式化日志01Zji1vJ,a4cOm1r0N7YQhr如果exception放在对应参数的位置上也会被格式化19y4WKhHqg3。nZN3q4m7CMc所以LM6px8PN5yI,8id47Z59A8X8D1e要放在{}参数之外5llJ9vNlChQ,TZ9825而且只能放在最后一个p52R0eqhBV1XW。ewNzQ1c4如果放在中间也不会被打印错误信息: 例如: 只要放到{}之外的最后一个参数可以打印错误信息(包括信息和位置) public static void openFile(String filePath) {EB32hAr1 89m51HO4AaCSXR        File file = new File(filePath);6N90GK Cf4a98P4        try {ghxl2TCMhlcKe 9hHE0k            InputStream in = new FileInputStream(file);01r3rCZ5GB6m74 DU4XTP        } catch (FileNotFoundException e) {5XzGwdFTBuco 9Y6chQHhM3y9            log.error("error:can found file [{}]"uAUm13,h2WCdgntc5E4LO filePath4tmPr,9wex75 3SuOHmwbk5ZjL,sVmdbEcUc e);XD81XS4z7 tuUQLAiQ        }i5Mb6 KQmZA    } 结果: 2018-08-18 11:11:18 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:can found file [xxxxxx]UPNG8RU6D80g 74229b1WV7M1ZLjava.io.FileNotFoundException: xxxxxx (系统找不到指定的文件wi4VnFqlhS。4501tmZRxl1)BVp9W k4223j5    at java.io.FileInputStream.open(Native Method)PQoMk6 e2ORb3Dfon    at java.io.FileInputStream.(FileInputStream.java:146)S7hAr gB0sW    at cn.xm.exam.test.Slf4jTest.openFile(Slf4jTest.java:22)vu3K8k7 Y1S15z85i4jb    at cn.xm.exam.test.Slf4jTest.main(Slf4jTest.java:16) 放到{}之外的非最后一个参数不会打印错误信息 public static void openFile(String filePath) {ah8DUPU219NNG7 7QTQOk        File file = new File(filePath);e8vh8Ui7slf ZJqgl5Hr        try {5E0r7gr327G6 I12X57Ij            InputStream in = new FileInputStream(file);N4UFNV 58nqhV        } catch (FileNotFoundException e) {ZNRL886z RpeLCC            log.error("error:can found file [{}]"zr15g15Y,7843m47 filePathUfZ1Km,2dHALk07465Jes9Jqe5091F16,eqV5p8oPJPYs3);270676R19 diD9o88G        }nDYKlF9fF6dpA bafDDob1H    } 结果: 2018-08-18 11:10:38 [cn.xm.exam.test.Slf4jTest]-[ERROR] error:can found file [xxxxxx] 2.尽量不使用e.getMessage()Oa2j3TvO,WPa83qS因为有的异常不一定有message9oKWvpMa,2O0W2fhzzY可以使用e.toString只会显示信息3BAklo,Z96kBAR1k06l不会显示出错的位置信息(不建议这种) 例如: package cn.xm.exam.test;69AXj3VEqaz Cc66YrnCCWKoMBSb7 Z1lM9y8lcfimport java.io.File;52jul R9G5f97t5i7bimport java.io.FileInputStream;3u5h2M3Dj0k5b 51Goocimport java.io.FileNotFoundException;dD3DQb 70h5Bimport java.io.InputStream;EYx6pq2VYZiI8a eAT8K2admm59wiU3IQs5J9w 289Y1fuB3NmwJimport org.slf4j.Logger;JoZJiZ5 1Gip20031J5Opimport org.slf4j.LoggerFactory;HP7xU3s7n seO18E9yChQ54n50sahVbgkfrm atBV61public class Slf4jTest {30z46fw1nlJjRD gYr3cFkf19h6RLT749NV5L4 oQw9zX8    private static Logger log = LoggerFactory.getLogger(Slf4jTest.class);3fV2oF5 Vc5b30ie6Q6o0zh263l 6loxj    public static void main(String[] args) {7XgQt 7D2pmfB67TY        openFile("xxxxxx");29Yk4AR5SNV gWrFR56ai    }ZrHoo3H2Tqk87 Grog6t20cuk7fxSzo0DGHNz 56xJG00y6    public static void openFile(String filePath) {gwbBispy G4RWi        File file = new File(filePath);1eML5 hfrfEBzvk8        try {tSf9uUR44LPBAD 6J5gzg2mri            InputStream in = new FileInputStream(file);gtzWX2s 0HC58xhw        } catch (FileNotFoundException e) {PO809W7S 38omynK9K2338            //下面两句的效果一样dCa9sbHVs04Eo m4dfWOBQ94w0 log.error("can found file [{}]VH3X8k5J5l7dl,L00Wi72P9cause:{}"amJclb,nY5r634 filePathY3KY2frVu,71e6yz68AJg e.toString());UnDH3xQsO977 ljZe6xMvXjKSM            log.error("can found file [{}]lC9v7In22,uNUEL9uwecause:{}"X41k2l99IL,50L23R359LI1CL filePathLFIoB11222YGM,jxAsEs0t6pX e);BTsiH4JVY7 5653BF        }6D9Y55P eR1cXPYI7258V8    }leGheDDB8Nqy0D KY3DG6I5QnfP8lQ VCePLiWFvh} 结果: 2018-08-18 10:53:31 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx]6Jgdx,M1Yx3M92cause:java.io.FileNotFoundException: xxxxxx (系统找不到指定的文件XoUfGHypMM。E1yj2U)4Ewlw5Pdl3z 32N1lYnsqOK22018-08-18 10:53:31 [cn.xm.exam.test.Slf4jTest]-[ERROR] can found file [xxxxxx]5sOq3U6L2,dfyotX2k2Mh01lcause:java.io.FileNotFoundException: xxxxxx (系统找不到指定的文件cd7oGT6cXk5Mx。OXI6a0X) 补充:一份上线系统使用的log4j.properties配置: log4j.rootLogger=info10rmmOz2oQB6,a8BDf7OBq1e174BspA6o YePS88Fg4347Vw 13gP3ZnDlog4j.appender.A=org.apache.log4j.ConsoleAppenderW5IkR cZcP4log4j.appender.A.layout=org.apache.log4j.PatternLayoutN308f1mu9zPXp X5c1zZEFrX9ylog4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%nvCixXG g460ItEnKWNle2T 3Lyq2Hlog4j.appender.B=org.apache.log4j.RollingFileAppenderoL479TOJEu wg99Xlog4j.appender.B.File=E:\\test.log6K8CFg3C4C Yh0pZ21I5r9log4j.appender.B.MaxFileSize=10MB2059E2E9o 67EuQg79xlog4j.appender.B.MaxBackupIndex=5zN877 o2eXJD9iYJlog4j.appender.B.layout=org.apache.log4j.PatternLayoutyNf6J w11DrXlf7dPilog4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n %d{yyyy-MM-dd HH:mm:ss} 也可以改为%d{yyyy-MM-dd HH:mm:ssL2pb8S9629yQR,DO331sLc1M4tSSS} SSS代表至少输出3位数字的毫秒1M6XD。6d0q1q152EopT如果4个S的话不足位补0ToC5On。t5GpQ6I6 解释:org.apache.log4j.RollingFileAppender是log4j的一个类8zv4NmLFWh,Zu1JGA下面的配置都是它的属性的配置:(其中还有好多属性来自其父类je294t6UEg42q,S995xfYv98U需要的时候我们可以去查阅) log4j.appender.B.File 指定输出的日志的文件名称以及路径 log4j.appender.B.MaxFileSize 指定每个文件的最大大小 log4j.appender.B.MaxBackupIndex  指定文件达到文件大小之后最多重命名的文件数量 log4j.appender.B.layout  指定采用的样式 log4j.appender.B.layout.ConversionPattern 指定样式的格式(值一般固定) 测试代码: package cn.qlq.slf4jTest;RU3by1c6ke1 7QOEb4V81EZdFVU8o1MdAgb8Ck 08oz4import org.slf4j.Logger;7Xa9qG 9ew2bbDJ0xE6Gimport org.slf4j.LoggerFactory;zj0R5SpUmO8JD 87Ug27hf89w1l33jnJq 37rw4CINTpublic class Slf4jTest {jx1P5Kw 08dh6F53tT5    private static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日志记录器83aaCrF3kZ UDuWgVjIAAz18eejrj4 6hpdi4SFm6M8Oa public static void main(String[] args) {1CQIy0X 2eP0NqgFB1tfM6IHAP5Om0fID UT5a9ecZ4O0D        while (true) {O3HCFM1 4rZ4nJx28G4RT40X1MDNvh Xt4bTM            // 普通的日志记录X7Vouta7nPgOU6 n35a6sX1ZQZI4m logger.error("普通的日志记录");cWADVnwF1T34 K5k0lc0v44GUJkrRvCFxkHo7O XwS8ItOqV17            // {}占位符记录日志aJW4L8So9E Idv1t71g4OqB5B for (int i = 0; i < 3; i++) {dc0f77w p83pc1UQ                logger.info("这是第{}条记录"7hUzR44Tm96,YQM9V7p7AGNH35 i);5DZ8eT1h4E QJf33J4U5bh            }LY43693LJ9z 13334AF8Z35t488TwhfyX74HQ Je6bjQW            // 用\转义{}sr94MHliIoPB6 ZyUtN1 logger.info("Set \\{} differs from {}"xkbEQ,eOK2e92Hc "3"); // output:Set {} differs from 3n50eq3JWv8x51 2a1x5pa91mtKMO038K04pv KCs2cO5K8            // 两个参数SznFcy4 28EJcO8Iwyu70 logger.info("两个占位符Yl4x047Cs6,V61US20q5YcD可以传两个参数{}----{}"7381P3AdSszi,IXr32003 147JG5BByh,7Qvc146BB2vx 2);v9X24zJrf0 8eGm6B6Hn14J6vI8i1l Xt4s6Vp7W5V        }A05L3lih9G8Z 6iAh7T2YSqAkcWET 1GOkb7    }oW9WfN7d 6huPWVluBs 2zX1xMlAl583} 结果:(会产生对应的文件J7N23B6hC7,tOaq5ivtest.log永远保存最新的日志1o9jwdE,fN1Ml4JRj达到10M后会重命名文件为test.log.14UHS9q5,4x5v9H0WN01L1并将原来test.log.1命名为test.log.2....) log内容如下: 补充:Threshold还可以指定输出的日志级别: (如果设置不起作用查看项目是不是用的log4j的包1jmMC2xEL3e8,g9AyE有可能有多个log4j包Oj9qw,pAPfKYLiOvK5造成冲突)   有时候我们需要把一些报错ERROR日志单独存到指定文件 w1nfD4,6s5s6kRo4F5这时候NOTlzLSIBpA,GfUMzjTLzZQ9SgThreshold属性就派上用场了259i8W05MNM,689uYlC比如: log4j.rootLogger=infoKJT2UI,Z66lDDEBP1L4s34V2IJF,8tkfZubCX1Hk1cWJwO12 7Ha2fbGqSft62l2400 3WKHH4DUbirblog4j.appender.B=org.apache.log4j.RollingFileAppender6qt060oM5 4A95Y4YWBk5Ilog4j.appender.B.Threshold=infoe3cyAsp5t5t DdybHP2p8Flog4j.appender.B.File=E:\\info.log710BVL aXmF6Yzlog4j.appender.B.MaxFileSize=10MB348409MjmX3 GXG77XWlog4j.appender.B.MaxBackupIndex=5xnhKNK Y1P6Pvj6c3oJm8log4j.appender.B.layout=org.apache.log4j.PatternLayoutO9SZG 0ZX0hqA457rwglog4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n268ud0dDSaD MiEDfm1gPInVBRhIhWwrKT 0e4Ka4L9log4j.appender.C=org.apache.log4j.RollingFileAppender31aKkxBS4 zEmdilog4j.appender.C.Threshold=error73Ir7L8E985R4 0U021416Iylog4j.appender.C.File=E:\\error.logNH84oJbxJ63pA 1c7yuXv61AihXlog4j.appender.C.MaxFileSize=10MBm93O7N3WVqZiC9 1tz1j0log4j.appender.C.MaxBackupIndex=58SPlx62z NO1mV8jM3log4j.appender.C.layout=org.apache.log4j.PatternLayoutbZUo62B9Jnh13 V4A6K0Jj3b4JQTlog4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n 上面B格式的就是info级别以上的日志93BZN2IeRe35,dG164mh包括error信息   C格式的就是error级别以上的信息930735jj。c8N1vtmuOtn8u   当然这里有个提前 rootLogger里配置的level必须小于Threshold等级g8rEeFX,LV7YAp15zdkfO1否则无效 还是按照总的rootLogger里的level来输出957h39lkD,qK5Y6ySBHU4Ls一般我们实际实用的话 rootLogger里配置DEBUGGqO0px,mjGQQz2然后某个文件专门存储ERRO日志9sc78d,jR152L997就配置下Threshold为ERROR 代码还是上面的测试代码: 结果: error.log内容:全是error级别以上的日志 info.log内容(info级别以上07MDjS9fRM0ih,TvPZEeR9T包括error) 补充:log4j也可以对不同的包进行不同的配置lrH8bssM9t,nRpboQ3Yc9lm6也就是针对不同的包采用不同的日志级别与日志控制器   有时候我们也希望对不同的包采用不通的日志记录级别以及不同的日志记录方式gsuK00pUHCt。B35JHTMn70qGa7log4j完全可以做到这点52jBdE9e5ddk,70htIIAz例如下面 默认包采用rootLogger的配置DPPSY4ssq,TzDaR9Ih4info级别e93jl0、p4hLL03U49在控制台与文件中进行显示;同时又修改了cn下面的aaz141v5JgNf、0akWC759pQcuHbZ9dmtcnp、KwY76u39X6c包的日志级别:   cn.a只降低了级别为debugkcO634q7Jn6RXB,3eT5Q8cI2a输出方式还是console与file两种GVp7Ll。NR8MiD65406O(一般我们采用这种方式修改级别即可8ns53tDvq1,18vjI1v20如果再设置输出方式会在原来的基础上增加方式)   cn.b级别设为infol0z2RhP1K9H4R,pZqZk5mYHD方式设为console12bbY0Ei44Qm,UI751mhUn547hf实际是加了第三种方式   cn.c级别设置为errorxofGD63Eao4K,iLelJws9kxVUO方式设为file7lPSAMf4QUT,1h41rF98Lw5实际也是在rootLogger基础上增加第三种方式   级别会以log4j.logger.XX级别为准jn3FU6oQf75uWt,W9JY06u不管rootLogger级别高于对具体包的设置还是低于具体包的设置;输出方式会在rootLogger的基础上增加新的方式58e3sYa,335P860m如果没有额外的方式采用rootLogger的方式m5FB289。b50p70H 例如:(注意标红地方) log4j.rootLogger=info43VwxUQ5KhnCq,xkn3dj736consoleK2v1TPQ43,yFXG00f67jgnOfilezihrf84wrF4pJy z0IpyKZHnUXqVWhAZgx9moO x2LY4Jm2log4j.logger.cn.a=debugcBB3IdseW6u 3QWv820kVOlog4j.logger.cn.b=infoLCbrz470bMpS0f,zvks4TiconsoleeWHP7nPEbw9 4kenxi0nlog4j.logger.cn.c=error856YHJ,34Ml4fileIeqfz0Ns4G O60For5Cb825fvw88FFb 3lZSDAIlog4j.appender.console=org.apache.log4j.ConsoleAppender9CiokeBf tisuI8PwZDDqlog4j.appender.console.layout=org.apache.log4j.PatternLayoutQLHXbmlf H9iRzi57log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%nHtAOMR p6zREUd8p0j0 c62re5R37log4j.appender.file=org.apache.log4j.RollingFileAppender50xwME5m ym1Nxlog4j.appender.file.File=E:\\test.log319ctk3G5Q a4qR4log4j.appender.file.MaxFileSize=10MBca772zsPKx0k 8RJ2qlog4j.appender.file.MaxBackupIndex=51xPoby S7a3Rn77g63DE5log4j.appender.file.layout=org.apache.log4j.PatternLayouthSYkL9RpE036 9Oe0XAZlog4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n 测试: 包结构: Root package cn;Aqn1fb4fSl byhW6KjiEynJkY48ZP 8Lh2ObTLTsimport org.slf4j.Logger;00aHXU0D4Z3M K7Uj3import org.slf4j.LoggerFactory;N290Zuq75nj4d6 g224593913BwxMT0 yBjeysSt2G6NRpublic class RootClass {kwytzNcWw NeHWr1a8k98k1    private static final Logger LOGGER = LoggerFactory.getLogger(RootClass.class);bYgDrEdPGP OKQaPwNip3cmu13e0ERIx6M3 E7ecL72BHC    public static void main(String[] args) {6z2o6Xdg aO8Srf6        LOGGER.debug("RootClass");sgvuEYZRQ24C 0s4FS4eWsDen        LOGGER.info("RootClass");37qo1YH A86GhIG2dEH22        LOGGER.error("RootClass");wyPIf4510r9 pN0dvNX8S    }uHT23TQyqV F5jXu78FD} 运行结果: 2018-10-23 19:38:04 [cn.RootClass]-[INFO] RootClass 2018-10-23 19:38:04 [cn.RootClass]-[ERROR] RootClass AC1 package cn.a;3j9FD EtwHE27iw3s RHP1gJ8oXimport org.slf4j.Logger;60Q31AuOe5sLWV 3V217rU3466LJvimport org.slf4j.LoggerFactory;1q6vnMaD0D2ujp klNoX0VfLXauhUKG eabsRpublic class AC1 {q2X1NN3Hs qT6zz    private static final Logger LOGGER = LoggerFactory.getLogger(AC1.class);W8wYK o3KK6h4DTw10554aMb71E2O90 u85lCr    public static void main(String[] args) {A0l8l5Qqy7 Gf2zL        LOGGER.debug("AC1");iTOU6M8nU7ot rMsjQv        LOGGER.info("AC1");nGAqDj v65Jb9        LOGGER.error("AC1");iTlMUwuj6pgj ZWJMSkYn    }bnZp529 bq6we7o9} 运行结果: 2018-10-23 19:38:31 [cn.a.AC1]-[DEBUG] AC1 2018-10-23 19:38:31 [cn.a.AC1]-[INFO] AC1 2018-10-23 19:38:31 [cn.a.AC1]-[ERROR] AC1 BC1: package cn.b;8M4883Hl X43g49jox94t86B91 qTHLjtimport org.slf4j.Logger;2q261 c82VlLBhfN0fUimport org.slf4j.LoggerFactory;78816 NZNj4QLRwz5M7 fArp20RbaiuE0public class BC1 {291rapiDoUA5 Z9j032eA    private static final Logger LOGGER = LoggerFactory.getLogger(BC1.class);wHLg96y5f 7rcS5Y3QA6SBbYR2jTb O2O9B9qRZtn7uI    public static void main(String[] args) {rG5cx3lO3LUi 0U83LOoM6X73K        LOGGER.debug("BC1");596h9LkA4tS9 396hv8q2        LOGGER.info("BC1");B7F27vF842r k6pBvAjG2UQch4        LOGGER.error("BC1");kAOoQpUSMy2S7A Hp5zu8    }405Hl95 2g2zl0nHLQXdZ3} 运行结果: 2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1 2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1 2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1 2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1 CC1: package cn.c;p60cP UKBPMY0GB562z 54FlGzRXCimport org.slf4j.Logger;tG0yqqL mQzp951xMaimport org.slf4j.LoggerFactory;G356MRKXD9qU z9Hjx4dgIC01H8AQe5 F4h25Cy91dpublic class CC1 {Q65l5j4 w4Z8e1DO18CN    private static final Logger LOGGER = LoggerFactory.getLogger(CC1.class);T3g5r1KPsiu K4MeOC9M0    public static void main(String[] args) {q2E1N3gs48 47p91lvXFuV        LOGGER.debug("CC1");27U7hHcDBS 8m54e8wy        LOGGER.info("CC1");71kj8qU8Vh5 04Ysnn        LOGGER.error("CC1");6tZ89Bx FnN1X5M8LtB    }9R22Q5UB X82xowJ} 运行结果: 2018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1 最后查看E:/test.log 2018-10-23 19:38:04 [cn.RootClass]-[INFO] RootClassGuGEu2c9DfD2Nc IdHaIQPw3fJ2018-10-23 19:38:04 [cn.RootClass]-[ERROR] RootClassU8DnC2 66nSV2018-10-23 19:38:31 [cn.a.AC1]-[DEBUG] AC1fTtUo7k934 8WAyP2018-10-23 19:38:31 [cn.a.AC1]-[INFO] AC1QDbXe 67BxBDrN0QuQ2018-10-23 19:38:31 [cn.a.AC1]-[ERROR] AC1dRgiJ05WX6pFzh SFO08F2018-10-23 19:39:04 [cn.b.BC1]-[INFO] BC1210630C AJB30K2018-10-23 19:39:04 [cn.b.BC1]-[ERROR] BC1j9K6ntr gL7R8qC82018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1NxZVF iWQ682018-10-23 19:39:28 [cn.c.CC1]-[ERROR] CC1 补充:对父包设置日志级别25x6tl,0dyO7NSHQ如果子包没有设置默认采用父包的设置w80HCMG8,K02sZiAvw5x如果子包设置了会采用单独的设置 配置修改cn包设置以及对b包单独进行设置: log4j.logger.cn=errorhbb5Uy8Td KU6NUlog4j.logger.cn.b=inforNyR2zWcs,VeZJjpbaV2HQknconsoleG1Z77t0m 6J09Xr831f 测试cn.d包默认采用cn包的error级别: package cn.d;bW8J1 1AWg49tmqE2MMbFP r43EPAA4t871vimport org.slf4j.Logger;PqWHq8TjX4 PJw940sH8KYcHimport org.slf4j.LoggerFactory;EX6gMr7EKc33h k0We1rx2uw2eXIyXx28UC LulfPdOELV8public class DC1 {6io3X0 4jkjNc2d0    private static final Logger LOGGER = LoggerFactory.getLogger(DC1.class);Al88U8AGgv ckdc7p9Yr9t88sT944z GcM5R4R3B    public static void main(String[] args) {6Z6O1X3XT0FH0 3BnYq        LOGGER.debug("D");1qA9z0CO51Ks 6yFFfDLg6        LOGGER.info("D");Uczhlj4hEQ jP66j9Z5H5PNeL        LOGGER.error("D");tQJ0k2z5jwtK5 G1UEaqC01sCB    }4E696 PW1K32uv58TPt} 结果gl26Vgw8Jvn7A:Xb2Y6hZ 2018-12-29 13:30:09 [cn.d.DC1]-[ERROR] D 测试cn.b采用单独对cn.b包的配置 package cn.b;QbfbMnW 2O02XybEE63gmzUn21Mug GT9127XCoimport org.slf4j.Logger;zILU8 r939RX84L3S4Jhimport org.slf4j.LoggerFactory;c8gCodrFBFS9 94qRhd33q7O6nVi1 pibE31public class BC1 {1KF8QUcJ0 VAA7L99Q    private static final Logger LOGGER = LoggerFactory.getLogger(BC1.class);9866W5dS yF1PVYryY3quzfb5xq 5eC5YG    public static void main(String[] args) {11eHb6W2m6 i1FM3TgmXo63        LOGGER.debug("BC1");3XuXzO Bel7O        LOGGER.info("BC1");6SnOK 18e1xNKsDwuhe4        LOGGER.error("BC1");3gS5pj POFU2z3    }3RIVb809JMF2G3 2tV54} 结果: 2018-12-29 13:31:27 [cn.b.BC1]-[INFO] BC1 2018-12-29 13:31:27 [cn.b.BC1]-[INFO] BC1 2018-12-29 13:31:27 [cn.b.BC1]-[ERROR] BC1 2018-12-29 13:31:27 [cn.b.BC1]-[ERROR] BC1 补充:上面的对包的具体设置日志级别虽然不受总的log4j.rootLogger的日志级别的限制g71C1,1kw31BP但是却受特殊的日志的Threshold属性的限制2KHe5xE6,8lth8t8IQ1cd也就是对具体包的设置必须高于其记录器的Threshold属性IAyt2KPmg38,2VLthW7dKrP否则以其记录器的Threshold属性为准 例如:修改上面的日志配置(每个日志记录器增加Threshold属性) log4j.rootLogger=infoEh37Ye3,8h7530LconsoleV1vCy86vk80,4oV8e3ZfileHQd5fiI7udO42 ecGVdG4P82YC2Cl7hfV vt5kYwMlog4j.logger.cn.a=debugoBufKwlV bfp93AqOlog4j.logger.cn.b=infoy8x1Mm3U89f1T,eOe1Anvx8eVy9consolea13y31366F4 xwN0UD3log4j.logger.cn.c=errorw866kRHRelQTcC,2ck5YHY2041CtfileP1gM5aN14HzZ a1tB6YJkPYEVi6YzI8b o135qvt7ByBplog4j.appender.console=org.apache.log4j.ConsoleAppenderIozSe814AXz8n H4akc4log4j.appender.console.Threshold=infoEA0dQJ6X04Ox7 Ecvs9log4j.appender.console.layout=org.apache.log4j.PatternLayoutc966hhtN 749D8gssrlog4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n9c1sV5uwZyeo8Y 28M9QOPihQg1z doAJM3bEUULZYlog4j.appender.file=org.apache.log4j.RollingFileAppenderH320cX6p7ZUHv Bpg9UnMlog4j.appender.file.Threshold=error7SCN2w9lcbx96 22JBm153DxrKm9log4j.appender.file.File=E:\\test.logXxqpQZs2A 6tzHoH5LoR1Mylog4j.appender.file.MaxFileSize=10MBKldmhx2387B jX2A4UV45063yjlog4j.appender.file.MaxBackupIndex=5eg6ZJzuHM46 yQWwAnblog4j.appender.file.layout=org.apache.log4j.PatternLayoutDp948Nr8r8Q4uo dvRG6GDlog4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n 运行RootClass: 2018-11-12 23:02:44 [cn.RootClass]-[INFO] RootClass 2018-11-12 23:02:44 [cn.RootClass]-[ERROR] RootClass 运行AC1: 2018-11-12 23:03:08 [cn.a.AC1]-[INFO] AC1 2018-11-12 23:03:08 [cn.a.AC1]-[ERROR] AC1 运行BC1UPBEDAIOjFC:hl25tM0GL0hi2u 2018-11-12 23:03:33 [cn.b.BC1]-[INFO] BC1 2018-11-12 23:03:33 [cn.b.BC1]-[INFO] BC1 2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1 2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1 运行CC1: 2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1 查看test.log: 2018-11-12 23:02:44 [cn.RootClass]-[ERROR] RootClass 2018-11-12 23:03:08 [cn.a.AC1]-[ERROR] AC1 2018-11-12 23:03:33 [cn.b.BC1]-[ERROR] BC1 2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1 2018-11-12 23:04:25 [cn.c.CC1]-[ERROR] CC1 所以总结上面的日记记录级别的设置优先级可以总结为:Threshold > 具体包的设置 > rootLogger的全局配置 【当你用心写完每一篇博客之后D53goc,x8mOzK44rc8Yb8你会发现它比你用代码实现功能更有成就感!】