首页 > 其他分享 >集中化日志管理平台的应用day01 一般有用 看1

集中化日志管理平台的应用day01 一般有用 看1

时间:2023-05-23 23:45:52浏览次数:36  
标签:logging 集中化 day01 slf4j apache org 日志 logback log4j

学习⽬标 1·学习java⽇志体系及⽇志⼯具的演进 2·了解⽇志采集、处理、分析等各阶段的常⽤中间件 3·学会搭建完整的 elk⽇志平台 4·学习⽇志打点,切⾯,⽇志⽂件等输出⼿段 5·项⽬实战,完成⼀访问⽇志链路的跟踪 1、java⽇志体系 1.1 体系概述 1.1.1 ⽇志接⼝ JCL:Apache基⾦会所属的项⽬,是⼀套Java⽇志接⼝,之前叫Jakarta Commons Logging,后更 名为Commons Logging,简称JCL SLF4J:Simple Logging Facade for Java,缩写Slf4j,是⼀套简易Java⽇志⻔⾯,只提供相关接 ⼝,和其他⽇志⼯具之间需要桥接 1.1.2 ⽇志实现     JUL:JDK中的⽇志⼯具,也称为jdklog、jdk-logging,⾃Java1.4以来sun的官⽅提供。 Log4j:⾪属于Apache基⾦会的⼀套⽇志框架,现已不再维护 Log4j2:Log4j的升级版本,与Log4j变化很⼤,不兼容 Logback:⼀个具体的⽇志实现框架,和Slf4j是同⼀个作者,性能很好 1.2 发展历程 1.2.1 上古时代   在JDK 1.3及以前, Java打⽇志依赖 System.out.println(), System.err.println() 或者 e.printStackTrace() ,Debug ⽇志被写到 STDOUT流,错误⽇志被写到STDERR流。这样打⽇志有⼀个⾮ 常⼤的缺陷,⾮常机械,⽆法定制,且⽇志粒度不够细分。 代码: 1.2.2 开创先驱   于是,Ceki Gülcü 于2001年发布了Log4j,并将其捐献给了Apache软件基⾦会,成为Apache 基⾦ 会的顶级项⽬。后来衍⽣⽀持C, C++, C#, Perl, Python, Ruby等语⾔。   Log4j 在设计上⾮常优秀, 它定义的Logger、Appender、Level等概念对后续的 Java Log 框架有深远的影响,如今的很多⽇志框 架基本沿⽤了这种思想。Log4j 的性能是个问题,在Logback 和 Log4j2 出来之后,2015年9⽉, Apache软件基⾦会宣布,Log4j不再维护,建议所有相关项⽬升级到Log4j2 pom: 配置: System.out.println("123"); System.err.println("456"); <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>apache-log4j-extras</artifactId> <version>1.2.17</version> </dependency> log4j.rootLogger=debug #console     代码: 1.2.3 搞事情的JUL   sun公司对于log4j的出现内⼼隐隐表示嫉妒。于是在jdk1.4版本后,开始搞事情,增加了⼀个包为 java.util.logging,简称为JUL,⽤以对抗log4j ,但是却给开发造成了麻烦。相互引⽤的项⽬之间可能使 ⽤了不同的⽇志框架,经常将代码搞得⼀⽚混乱。 代码: 配置路径:   JUL功能远不如log4j完善,⾃带的Handlers有限,性能和可⽤性上也⼀般,JUL在Java1.5以后才有 所提升。 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern= log4j:[%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n #dailyfile log4j.appender.dailyfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyfile.DatePattern ='_'yyyy-MM-dd'.log' log4j.appender.dailyfile.File =./log4j.log log4j.appender.dailyfile.Append =true log4j.appender.dailyfile.Threshold=INFO log4j.appender.dailyfile.layout =org.apache.log4j.PatternLayout log4j.appender.dailyfile.layout.ConversionPattern =log4j:[%d{yyyy-MM-dd HH :mm:ss a}] [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n import org.apache.log4j.Logger; Logger logger = Logger.getLogger(Demo.class); logger.info("xxxx"); import java.util.logging.Logger; Logger loggger = Logger.getLogger(Demo.class.getName()); logger.finest("xxxx"); $JAVA_HOME/jre/lib/logging.properties     1.2.4 JCL应运⽽⽣   从上⾯可以看出,JUL的api与log4j是完全不同的(参数只接受string)。由于⽇志系统互相没有关 联,彼此没有约定,不同⼈的代码使⽤不同⽇志,替换和统⼀也就变成了⽐较棘⼿的⼀件事。假如你的 应⽤使⽤log4j,然后项⽬引⽤了⼀个其他团队的库,他们使⽤了JUL,你的应⽤就得使⽤两个⽇志系统 了,然后其他团队⼜使⽤了simplelog……这个时候如果要调整⽇志的输出级别,⽤于跟踪某个信息,简 直就是⼀场灾难。   那这个状况该如何解决呢?答案就是进⾏抽象,抽象出⼀个接⼝层,对每个⽇志实现都适配或者转 接,这样这些提供给别⼈的库都直接使⽤抽象层即可 ,以后调⽤的时候,就调⽤这些接⼝。(⾯向接⼝ 思想)   于是,JCL(Jakarta Commons Logging)应运⽽⽣,也就是commons-logging-xx.jar组件。JCL 只提 供 log 接⼝,具体的实现则在运⾏时动态寻找。这样⼀来组件开发者只需要针对 JCL 接⼝开发,⽽调⽤ 组件的应⽤程序则可以在运⾏时搭配⾃⼰喜好的⽇志实践⼯具。   那接⼝下真实的⽇志是谁呢?参考下图:   JCL会在ClassLoader中进⾏查找,如果能找到Log4j 则默认使⽤log4j 实现,如果没有则使⽤ JUL(jdk⾃带的) 实现,再没有则使⽤JCL内部提供的SimpleLog 实现。(代码验证) pom: 代码:   JCL缺点也很明显,⼀是效率较低,⼆是容易引发混乱,三是JCL的机制有很⼤的可能会引发内存泄 露。   同时,JCL的书写存在⼀个不太优雅的地⽅,典型的场景如下:   假如要输出⼀条debug⽇志,⽽⼀般情况下,⽣产环境 log 级别都会设到 info 或者以上,那这条 log 是不会被输出的。于是,在代码⾥就出现了 <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; Log log =LogFactory.getLog(Demo.class); log.info('xxx'); logger.debug("this is a debug info , message :" + msg);       这个有什么问题呢?虽然⽣产不会打出⽇志,但是这其中都会做⼀个字符串连接操作,然后⽣成⼀ 个新的字符串。如果这条语句在循环或者被调⽤很多次的函数中,就会多做很多⽆⽤的字符串连接,影 响性能。   所以,JCL推荐的写法如下:   虽然解决了问题,但是这个代码实在看上去不怎么舒服 ... 1.2.5 再起波澜   于是,针对以上情况,log4j的作者再次出⼿,他觉得JCL不好⽤,⾃⼰⼜写了⼀个新的接⼝api,就 是slf4j,并且为了追求更极致的性能,新增了⼀套⽇志的实现,就是logback,⼀时间烽烟⼜起…… 坐标: 配置: if (logger.isDebugEnabled()) { logger.debug ("this is a debug info , message :" + msg); } <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false">   <property name="logPattern" value="logback:[ %-5level] [%date{yyyy-MM-dd HH:mm:ss.SSS}] %logger{96} [%line] [%thread]- %msg%n"></property>       logback-core 提供基础抽象,logback-classic 提供⽇志实现,并且直接就是基于Slf4j API。所以 slf4j配合logback来完成⽇志时,不需要像其他的⽇志框架⼀样提供适配器。   slf4j本身并没有实际的⽇志输出能⼒,它底层还是需要去调⽤具体的⽇志框架API,也就是它需要跟 具体的⽇志框架结合使⽤。由于具体⽇志框架⽐较多,⽽且互相也⼤都不兼容,⽇志⻔⾯接⼝要想实现 与任意⽇志框架结合就需要额外对应的桥接器。   有了新的slf4j后,上⾯的字符串拼接问题,被以下代码所取代,⽽logback也提供了更⾼级的特 性,如异步 logger,Filter等。      事情结束了吗?没有,log4j的粉丝们并不开⼼,于是下⼀代诞⽣了…… <!-- 控制台的标准输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>UTF-8</charset> <pattern>${logPattern}</pattern> </encoder> </appender> <root level ="DEBUG"> <appender-ref ref="STDOUT"/> </root> </configuration > logger.debug("this is a debug info , message : {}", msg);     1.2.6 再度⻘春   前⾯提到,log4j由apache宣布,2015年后,不再维护。推荐⼤家升级到log4j2,虽然log4j2沿袭 了log4j的思想,然⽽log4j2和log4j完全是两码事,并不兼容。   log4j2以性能著称,它⽐其前身 Log4j 1.x 提供了重⼤改进,同时类⽐logback,它提供了 Logback中 可⽤的许多改进,同时修复了 Logback 架构中的⼀些固有问题。功能上,它有着和 Logback相同的基本 操作,同时⼜有⾃⼰独特的部分,⽐如:插件式结构、配置⽂件优化、异步⽇志等。 pom: 代码: <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.13.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.0</version> </dependency> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.1</version> </dependency>     配置:   到log4j2,轰轰烈烈的java log战役基本就结束了。下⾯的章节,我们将进⼊⽇志⼯具的详细配置阶 段。 1.3 配置讲解 1.3.1 概述 1)⽇志级别   ⼀个完整的⽇志组件都要具备⽇志级别的概念,每种⽇志组件级别定义不同,⽇常编码最经常⽤到 的主流分级如下(由低到⾼): trace:路径跟踪 debug:⼀般⽤于⽇常调式 import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; Logger logger = LogManager.getLogger(Demo.class); logger.debug("debug Msg"); <?xml version="1.0" encoding="UTF-8"?> <configuration status="info" monitorInterval="30"> <Properties> <Property name="pattern">log4j2:[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n</Property> </Properties> <appenders> <!--console :控制台输出的配置--> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${pattern}"/> </Console> </appenders>   <loggers> <logger name="org.springframework" level="INFO"></logger> <root level="info"> <appender-ref ref="Console"/> </root> </loggers> </configuration>     info:打印重要信息 warn:给出警告 error:出现错误或问题   每个⽇志组件的具体级别划分稍有不同,参考下⽂各章节。 2)⽇志组件 appender:⽇志输出⽬的地,负责⽇志的输出 (输出到什么 地⽅) logger:⽇志记录器,负责收集处理⽇志记录 (如何处理⽇志) layout:⽇志格式化,负责对输出的⽇志格式化(以什么形式展现) 1.3.2 jul 1)配置⽂件:   默认情况下配置⽂件路径为$JAVAHOME\jre\lib\logging.properties   可以指定配置⽂件:   代码实践:配置⽂件位置,⽇志输出级别,如何输出低于INFO级别的信息 2)级别: SEVERE(最⾼值) WARNING INFO CONFIG FINE FINER FINEST(最低值) OFF,关闭⽇志。 ALL,启⽤所有⽇志。 3)处理器: StreamHandler:⽇志记录写⼊OutputStream。 ConsoleHandler:⽇志记录写⼊System.err。 FileHandler:⽇志记录写⼊单个⽂件或⼀组滚动⽇志⽂件。 static { System.setProperty("java.util.logging.config.file",   Demo.class.getClassLoader().getResource("logging.properties").getPath()); }     SocketHandler:⽇志记录写⼊远程TCP端⼝的处理程序。 MemoryHandler:缓冲内存中⽇志记录。 4)格式化: SimpleFormatter:格式化为简短的⽇志记录摘要。 XMLFormatter:格式化为详细的XML结构信息。 可⾃定输出格式,继承抽象类 java.util.logging.Formatter即可。 5) 代码实践: 如何修改输出级别? 1.3.3 log4j 1)配置⽂件: 启动时,默认会寻找source folder下的log4j.xml 若没有,会寻找log4j.properties 2)级别: FATAL(最⾼) ERROR WARN INFO DEBUG (最低) OFF,关闭⽇志。 ALL,启⽤所有⽇志。 3)处理器: org.apache.log4j.ConsoleAppender(控制台) org.apache.log4j.FileAppender(⽂件) org.apache.log4j.DailyRollingFileAppender(每天产⽣⼀个⽇志⽂件) org.apache.log4j.RollingFileAppender(⽂件⼤⼩到达指定尺⼨的时候产⽣⼀个新的⽂件) org.apache.log4j.WriterAppender(将⽇志信息以流格式发送到任意指定的地⽅) 4)格式化: org.apache.log4j.HTMLLayout(以HTML表格形式布局) org.apache.log4j.PatternLayout(可以灵活地指定布局模式) org.apache.log4j.SimpleLayout(包含⽇志信息的级别和信息字符串) org.apache.log4j.TTCCLayout(包含⽇志产⽣的时间、线程、类别等等信息) 5) 代码实践:     Appender:Console,DailyRollingFile Layout:Pattern log4j.rootLogger=debug,stdout,dailyfile #console log4j.appender.stdout =org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout =org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n #dailyfile log4j.appender.dailyfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyfile.DatePattern='_'yyyy-MM-dd'.log' log4j.appender.dailyfile.File=./log4j.log log4j.appender.dailyfile.Append=true log4j.appender.dailyfile.Threshold=INFO log4j.appender.dailyfile.layout=org.apache.log4j.PatternLayout log4j.appender.dailyfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'> <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value=""/> </layout> <filter class="org.apache.log4j.varia.LevelRangeFilter"> <param name="LevelMin" value="DEBUG"/> <param name="LevelMax" value="DEBUG"/> </filter> </appender> <appender name="DAILYROLLINGFILE" class="org.apache.log4j.DailyRollingFileAppender"> <param name="File" value="log4j.log"/> <param name="DatePattern" value="yyyy-MM-dd"/> <param name="Append" value="true"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c Method: %l ]%n%p:%m%n"/> </layout>     </appender> <root> <appender-ref ref="CONSOLE"/> <appender-ref ref="DAILYROLLINGFILE"/> </root> </log4j:configuration >     语法 说明 %c a.b.c %c{2} b.c %20c (若名字空间⻓度⼩于20,则左边⽤空格填充) %-20c (若名字空间⻓度⼩于20,则右边⽤空格填充) %.30c (若名字空间⻓度超过30,截去多余字符) %20.30c (若名字空间⻓度⼩于 20,则左边⽤空格填充;若名字空间⻓度超 过 30,截去多余字符) %-20.30c (若名字空间⻓度⼩于20,则右边⽤空格填充;若名字空间⻓度超 过30,截去多余字符) %C org.apache.xyz.SomeClass %C{1} SomeClass %d{yyyy/MM/dd HH:mm:ss,SSS} 2000/10/12 11:22:33,117 %d{ABSOLUTE} 11:22:33,117 %d{DATE} 12 Oct 2000 11:22:33,117 %d{ISO8601} 2000-10-12 11:22:33,117 %F MyClass.java %l MyClass.main(MyClass.java:123) %L 123 %m This is a message for debug. %M main %n Windows平台下表示rn,UNIX平台下表示n %p INFO %r 1215 %t MyClass %% % 1.3.4 logback http://logback.qos.ch/manual/index.html     1)配置⽂件: Logback tries to fifind a fifile called logback-test.xml in the classpath. If no such fifile is found, logback tries to fifind a fifile called logback.groovy in the classpath. If no such fifile is found, it checks for the fifile logback.xml in the classpath.. If no such fifile is found, service-provider loading facility (introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Confifigurator interface by looking up the fifile META-INF\services\ch.qos.logback.classic.spi.Con fifigurator in the class path. Its contents should specify the fully quali fified class name of the desired Confifigurator implementation. If none of the above succeeds, logback con fifigures itself automatically using the BasicCon fifigurator which will cause logging output to be directed to the console. 2)级别: ⽇志打印级别 ALL > TRACE > FATAL > DEBUG > INFO > WARN > ERROR > OFF 3)处理器: http://logback.qos.ch/manual/appenders.html 4)格式化: http://logback.qos.ch/manual/layouts.html           5) 代码实战: Appender:Console,Rollingfifile Layout:Xml,Pattern,Html , ⾃定义 <?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="3 seconds" debug="false"> <!-- lOGGER PATTERN 根据个⼈喜好选择匹配 --> <property name="logPattern" value="logback:[ %-5level] [%date{yyyy-MM-dd HH:mm:ss.SSS}] %logger{96} [%line] [%thread]- %msg%n"></property> <!-- 动态⽇志级别 --> <jmxConfigurator/> <!-- 控制台的标准输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <charset>UTF-8</charset> <pattern>${logPattern}</pattern> </encoder> </appender> <!-- 滚动⽂件 --> <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <file>./logback.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>./logback.log.%d{yyyy-MM-dd}.zip</fileNamePattern> <!-- 最⼤保存时间 --> <maxHistory > 2</maxHistory> </rollingPolicy > <encoder >   <pattern >${logPattern}</pattern> </ encoder > </appender > <!-- DB --> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>com.mysql.jdbc.Driver</driverClass> <url>jdbc:mysql://172.17.0.203:3306/log?useSSL=false</url> <user>root</user> <password>root</password> </connectionSource> </appender>   <!-- ASYNC_LOG --> <appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender"> <!-- 不丢失⽇志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的⽇志 - -> <discardingThreshold>0</discardingThreshold> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <queueSize>3</queueSize> <appender-ref ref="STDOUT"/> </appender> <!-- ⽇志的记录级别 --> <!-- 在定义后引⽤APPENDER --> <root level="DEBUG"> <!-- 控制台 --> <appender-ref ref="STDOUT"/> <!-- ROLLING_FILE --> <appender-ref ref="ROLLING_FILE"/> <!-- ASYNC_LOG --> <appender-ref ref="ASYNC_LOG"/> </root> </configuration>     1.3.5 jcl 1)配置⽂件: ⾸先在classpath下寻找commons-logging.properties⽂件。如果找到,则使⽤其中定义的Log实 现类;如果找不到,则在查找是否已定义系统环境变量org.apache.commons.logging.Log,找到 则使⽤其定义的Log实现类; 查看classpath中是否有Log4j的包,如果发现,则⾃动使⽤Log4j作为⽇志实现类; 否则,使⽤JDK⾃身的⽇志实现类(JDK1.4以后才有⽇志实现类); 否则,使⽤commons-logging⾃⼰提供的⼀个简单的⽇志实现类SimpleLog; 2)级别: jcl有5个级别:trace < debug < info < warn < error 3)代码实战: ⽇志查找顺序: log4j-jul-slog commons-logging.properties配置 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <!--<charset>UTF-8</charset>--> <!--<pattern>${logPattern}</pattern>--> <!--<layout class="com.itheima.logback.MySampleLayout" />--> <layout class="ch.qos.logback.classic.html.HTMLLayout"> <pattern>%relative%thread%mdc%level%logger%msg</pattern> </layout > <!--<layout class="ch.qos.logback.classic.log4j.XMLLayout">--> <!--<locationInfo>false</locationInfo>--> <!--</layout>--> </encoder> </appender> #指定⽇志对象: #org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog #org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger #指定⽇志⼯⼚: org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl     1.3.6 log4j2 1)配置⽂件: Log4j will inspect the log4j.configurationFile system property and, if set, will attempt to load the confifiguration using the ConfigurationFactory that matches the fifile extension. If no system property is set the YAML Con fifigurationFactory will look for log4j2-test.yaml or log4j2-test.yml in the classpath. If no such fifile is found the JSON Con fifigurationFactory will look for log4j2-test.json or log4j2-test.jsn in the classpath. If no such fifile is found the XML Con fifigurationFactory will look for log4j2-test.xml in the classpath. If a test fifile cannot be located the YAML ConfifigurationFactory will look for log4j2.yaml or log4j2.yml on the classpath. If a YAML fifile cannot be located the JSON ConfifigurationFactory will look for log4j2.json or log4j2.jsn on the classpath. If a JSON fifile cannot be located the XML ConfifigurationFactory will try to locate log4j2.xml on the classpath. If no confifiguration fifile could be located the DefaultConfiguration will be used. This will cause logging output to go to the console. 2)级别: 从低到⾼为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF 3)处理器: http://logging.apache.org/log4j/2.x/manual/appenders.html FileAppender   普通地输出到本地⽂件 KafkaAppender 输出到kafka队列 FlumeAppender  将⼏个不同源的⽇志汇集、集中到⼀处。 JMSQueueAppender,JMSTopicAppender  与JMS相关的⽇志输出 RewriteAppender   对⽇志事件进⾏掩码或注⼊信息 RollingFileAppender  对⽇志⽂件进⾏封存(详细) RoutingAppender  在输出地之间进⾏筛选路由 SMTPAppender  将LogEvent发送到指定邮件列表 SocketAppender  将LogEvent以普通格式发送到远程主机 SyslogAppender  将LogEvent以RFC 5424格式发送到远程主机 AsynchAppender   将⼀个LogEvent异步地写⼊多个不同输出地 ConsoleAppender  将LogEvent输出到命令⾏ FailoverAppender  维护⼀个队列,系统将尝试向队列中的Appender依次输出LogEvent,直到 有⼀个成功为⽌ 4)格式化: http://logging.apache.org/log4j/2.x/manual/layouts.html           5)代码实战: <?xml version="1.0" encoding="UTF-8"?> <!--⽇志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--status="WARN" :⽤于设置log4j2⾃身内部⽇志的信息输出级别,默认是OFF--> <!--monitorInterval="30" :间隔秒数,⾃动检测配置⽂件的变更和重新配置本身--> <configuration status="info" monitorInterval="30"> <Properties> <!--⾃定义⼀些常量,之后使⽤${变量名}引⽤--> <Property name="pattern">log4j2:[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n</Property> </Properties> <!--appenders:定义输出内容,输出格式,输出⽅式,⽇志保存策略等,常⽤其下三种标签 [console,File,RollingFile]--> <appenders> <!--console :控制台输出的配置--> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${pattern}"/> </Console> <!--File :同步输出⽇志到本地⽂件--> <!--append="false" :根据其下⽇志策略,每次清空⽂件重新输⼊⽇志,可⽤于测试--> <File name="File" fileName="./log4j2-file.log" append="false"> <PatternLayout pattern="${pattern}"/> </File> <RollingFile name="RollingFile" fileName="./log4j2-rollingfile.log" filePattern="./$${date:yyyy-MM}/log4j2-%d{yyyy-MM-dd}- %i.log"> <!--ThresholdFilter :⽇志输出过滤--> <!--level="info" :⽇志级别,onMatch="ACCEPT" :级别在info之上则接 受,onMismatch="DENY" :级别在info之下则拒绝--> <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="${pattern}"/> <!-- Policies :⽇志滚动策略--> <Policies> <!-- TimeBasedTriggeringPolicy :时间滚动策略,   默认 0点产⽣新的⽂件 ,   interval="6" : ⾃定义⽂件滚动时间间隔 ,每隔6⼩时产⽣新⽂件,   modulate="true" : 产⽣⽂件是否以 0点偏移时间 , 即6点,12点 ,18点,0 点-->   <TimeBasedTriggeringPolicy interval ="6" modulate ="true" />   <!-- SizeBasedTriggeringPolicy : ⽂件⼤⼩滚动策略 -->   <SizeBasedTriggeringPolicy size= "1 MB"/> </Policies> <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同⼀⽂件夹下7个⽂ 件,这⾥设置了20 --> <DefaultRolloverStrategy max="20"/> </RollingFile> </appenders> <!--然后定义logger,只有定义了logger并引⼊的appender,appender才会⽣效--> <loggers> <!--过滤掉spring和mybatis的⼀些⽆⽤的DEBUG信息--> <!--Logger节点⽤来单独指定⽇志的形式,name为包路径,⽐如要为org.springframework 包下所有⽇志指定为INFO级别等。 --> <logger name="org.springframework" level="INFO"></logger> <logger name="org.mybatis" level="INFO"></logger> <!--AsyncLogger :异步⽇志,LOG4J有三种⽇志模式,全异步⽇志,混合模式,同步⽇志,性能 从⾼到底,线程越多效率越⾼,也可以避免⽇志卡死线程情况发⽣--> <!--additivity="false" : additivity设置事件是否在root logger输出,为了避免重 复输出,可以在Logger 标签下设置additivity为”false”--> <AsyncLogger name="AsyncLogger" level="trace" includeLocation="true" additivity="true"> <appender-ref ref="Console"/> </AsyncLogger> <logger name="Kafka" additivity="false" level="debug"> <appender-ref ref="Kafka"/> <appender-ref ref="Console"/> </logger> <!-- Root节点⽤来指定项⽬的根⽇志,如果没有单独指定Logger,那么就会默认使⽤该Root ⽇志输出 --> <root level="info"> <appender-ref ref="Console"/> <!--<appender-ref ref="File"/>--> <!--<appender-ref ref="RollingFile"/>--> <!--<appender-ref ref="Kafka"/>-->     1.3.7 slf4j 1)配置⽂件:   具体⽇志输出内容取决于⽣效的具体⽇志实现 2)级别:   slf4j⽇志级别有五种:ERROR、WARN、INFO、DEBUG、TRACE,级别从⾼到底 3)slf⽇志实现: </root> </loggers> </configuration> <!--slf转其他⽇志--> <!--slf - jcl--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jcl</artifactId> <version>1.7.30</version> </dependency> <!-- slf - log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> <!-- slf4j - log4j2 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.13.0</version> </dependency> <!--slf - jul--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.30</version> </dependency> <!--slf - simplelog--> <dependency>     问题:多个桥接器的话,slf4j怎么处理呢?   使⽤在class path中较早出现的那个,如在maven中,会使⽤在pom.xml中定义较靠前的桥接器 (代码验证) ⼩知识:   桥接器会传递依赖到对应的下游⽇志组件,⽐如slf4j-log4j12会附带log4j的jar包依赖(代码验证) 4)其他⽇志转slf <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.30</version> </dependency> <!--slf - logback--> <dependency> <groupId>ch.qos.logback </ groupId > <artifactId >logback-core </ artifactId > <version > 1.2.3</version> </dependency > <dependency > <groupId >ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!--其他⽇志转slf--> <!--jul - slf--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.30</version> </dependency> <!--jcl - slf--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.30</version> </dependency> <!--log4j - slf--> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId>     5)slf4j⽇志环 <version>1.7.30</version> </dependency> <!--log4j2 - slf--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.13.0 </version> </dependency> <!-- 演示实例:slf4j - log4j - slf4j --> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>apache-log4j-extras</artifactId> <version>1.2.17</version> </dependency> <!--slf4j--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <!--log4j - slf--> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.30</version> </dependency> <!-- slf - log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> <exclusions> <exclusion> <groupId>*</groupId>     依赖展示: 报错结果: 经验:使⽤slf桥接和绑定的时候要留⼼,不要⾃相⽭盾形成环 1.4⽇志建议 1.4.1 ⻔⾯约束   使⽤⻔⾯,⽽不是具体实现   使⽤ Log Facade 可以⽅便的切换具体的⽇志实现。⽽且,如果依赖多个项⽬,使⽤了不同的Log Facade,还可以⽅便的通过 Adapter 转接到同⼀个实现上。如果依赖项⽬直接使⽤了多个不同的⽇志 实现,会⾮常糟糕。   经验之谈:⽇志⻔⾯,⼀般现在推荐使⽤ Log4j-API 或者 SLF4j,不推荐继续使⽤ JCL。 <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> SLF4J: Detected both log4j -over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError . SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details. java.lang.ExceptionInInitializerError at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:72) at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:45) at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150) at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124) at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:417) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:362) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:388) at com.itheima.slf4j.Demo.<clinit>(Demo.java:8) Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details. at org.slf4j.impl.Log4jLoggerFactory.<clinit>(Log4jLoggerFactory.java:54) ... 8 more Exception in thread "main" Process finished with exit code 1     1.4.2 单⼀原则   只添加⼀个⽇志实现   项⽬中应该只使⽤⼀个具体的 Log Implementation,如果在依赖的项⽬中,使⽤的 Log Facade不 ⽀持当前 Log Implementation,就添加合适的桥接器。   经验之谈:jul性能⼀般, log4j性能也有问题⽽且不再维护,建议使⽤ Logback 或者Log4j2。 1.4.3 依赖约束   ⽇志实现坐标应该设置为 optional并使⽤runtime scope   在项⽬中,Log Implementation的依赖强烈建议设置为runtime scope,并且设置为optional。例 如项⽬中使⽤了 SLF4J 作为 Log Facade,然后想使⽤ Log4j2 作为 Implementation,那么使⽤ maven 添加依赖的时候这样设置:   设为optional,依赖不会传递,这样如果你是个lib项⽬,然后别的项⽬使⽤了你这个lib,不会被引 ⼊不想要的Log Implementation 依赖;   Scope设置为runtime,是为了防⽌开发⼈员在项⽬中直接使⽤Log Implementation中的类,强制 约束开发⼈员使⽤Facade接⼝。 1.4.4 避免传递   尽量⽤exclusion排除依赖的第三⽅库中的⽇志坐标   同上⼀个话题,第三⽅库的开发者却未必会把具体的⽇志实现或者桥接器的依赖设置为optional, 然后你的项⽬就会被迫传递引⼊这些依赖,⽽这些⽇志实现未必是你想要的,⽐如他依赖了Log4j,你 想使⽤Logback,这时就很尴尬。另外,如果不同的第三⽅依赖使⽤了不同的桥接器和Log实现,极有 可能会形成环。 <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> <optional>true</optional> </dependency>       这种情况下,推荐的处理⽅法,是使⽤exclude来排除所有的这些Log实现和桥接器的依赖,只保留 第三⽅库⾥⾯对Log Facade的依赖。   实例:依赖jstorm会引⼊Logback和log4j-over-slf4j,如果你在⾃⼰的项⽬中使⽤Log4j或其他Log 实现的话,就需要加上exclusion:

 

1.4.5 注意写法   避免为不会输出的log买单   Log库都可以灵活的设置输出级别,所以每⼀条程序中的log,都是有可能不会被输出的。这时候要 注意不要额外的付出代价。实例如下:

 

  前⾯讲到,第⼀条的字符串拼接,即使⽇志级别⾼于debug不会打印,依然会做字符串连接操作; 第⼆条虽然⽤了SLF4J/Log4j2 中的懒求值⽅式,但是toJson()这个函数却是总会被调⽤并且开销更⼤。 推荐的写法如下:

 

<dependency> <groupId>com.alibaba.jstorm </groupId > <artifactId >jstorm-core</artifactId > <version >2.1.1 </version> <exclusions > <exclusion >   <groupId >org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </exclusion> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency> logger.debug("this is debug: " + message); logger.debug("this is json msg: {}", toJson(message)); // SLF4J/LOG4J2 logger.debug("this is debug:{}", message); // LOG4J2 logger.debug("this is json msg: {}", () -> toJson(message)); // SLF4J/LOG4J2 if (logger.isDebugEnabled()) { logger.debug("this is debug: " + message); }     1.4.6 减少分析   输出的⽇志中尽量不要使⽤⾏号,函数名等信息   原因是,为了获取语句所在的函数名,或者⾏号,log库的实现都是获取当前的stacktrace,然后分 析取出这些信息,⽽获取 stacktrace的代价是很昂贵的。如果有很多的⽇志输出,就会占⽤⼤量的 CPU。在没有特殊需要的情况下,建议不要在⽇志中输出这些这些字段。 1.4.7 精简⾄上   log中尽量不要输出稀奇古怪的字符,这是个习惯和约束问题。有的同学习惯⽤这种语句:   输出了⼤量⽆关字符,虽然⾃⼰⼀时痛快,但是如果所有⼈都这样做的话,那log输出就没法看了! 正确的做法是⽇志只输出必要信息,如果要过滤,后期使⽤grep来筛选,只查⾃⼰关⼼的⽇志。 logger.debug("=====================================:{}",message);      

标签:logging,集中化,day01,slf4j,apache,org,日志,logback,log4j
From: https://www.cnblogs.com/shan13936/p/17426790.html

相关文章

  • Day01-常见的dos命令
    常见的dos命令windows打开cmd方式开始+系统+命令提示符win键+R输入cmd打开控制台(推荐使用)在任意的文件夹下面,按住shfit键+鼠标右键点击,在此处打开命令行窗口资源管理器的地址栏前面加上cmd路径管理员方式运行选择以管理员方式运行常用的dos命令 #盘符切......
  • Day01-Typora工具使用
    Markdown学习二级标题三级标题四级标题 字体helloworldhelloworldhelloworldhelloworld 引用学习java第一天 分割线 图片 超链接点击跳转到小兔子的博客 列表ABCABC 表格快捷键⌘+⌥+T姓名性别年纪张......
  • unity学习日志3(麦扣老师3DRPG项目学习)
    1.ShaderGraphy基本使用利用unity自带的菲利涅效果通过Multiply用Color使其改变颜色,操作如上如所示将需要调整的变量放到左上角中,即可和在inspector中随时调整shaderAlphaClipping:用于透明与非透明之间进行过渡AlphaThreshold代表阈值:没到达这个值不会进行渲染DithCoun......
  • #yum安装mysql8.0.32修改二进制日志位置报错mysqld: File '/data/mysql/logbin/mysql-
    #yum安装mysql8.0.32修改二进制日志位置报错mysqld:File'/data/mysql/logbin/mysql-bin.index'notfound(OSerrno13-Permissiondenied)[root@master-DNSmysql]#cat/var/log/mysql/mysqld.log2023-05-22T09:08:36.149861Z0[Warning][MY-010918][Server]'d......
  • 监控调用接口记录日志
    1、监控中间件publicclassOuterApiMonitorMiddleware:IMiddleware{//privatereadonlyILogger<OuterApiMonitorMiddleware>_logger;privatereadonlyIOuterApiLogger_apiLog;publicOuterApiMonitorMiddleware(/*ILogger<OuterApiMonitorMiddlewa......
  • oralce参数(块跟踪,parallel,附加日志)
    Oracle部分参数接触记录块跟踪问题背景:一个业务大库进行迁移后,数据库增量备份变得异常缓慢,甚至一天无法完成,影响业务安全性,提出开启块跟踪加快增备。开启(如需手动指定,rac需要在asm存储,文件系统可设置为本地)alterdatabaseenableblockchangetrackingusingfile'+DATA';或alt......
  • 锐捷三层交换机密码重置操作日志
       近来拿到了一台已经下架的三层交换机,想着拿来练手,做拓展WAN使用,用xshell连接交换机,发现设备有帐号密码的。然后就开始的百度重置交换机的方法:   看到这个教程,实际操作的时候,发现第一步都进不去,换了连接软件,各种方法测试过很多次,都没有用,还是进不去,只能重新找其它的......
  • C++ Today01
    1.1C++初始#include<iostream>usingnamespacestd;intmain(){cout<<"HelloC++"<<endl;system("pause");return0;}1.单行注释#include<iostream>usingnamespacestd;//1.单行注释//2.多行注释intma......
  • SpringBoot处理日志
    SpringBoot处理日志工作需求需要把不同类的日志分开存储,方便查阅。例如Controller的日志存一个文件,Service的日志存一个文件。需求分析日志一般都用slf4j,意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的......
  • Qt+QtWebApp开发笔记(二):http服务器日志系统介绍、添加日志系统至Demo测试
    前言  上一篇使用QtWebApp的基于Qt的轻量级http服务器实现了一个静态网页返回的Demo,网页服务器很重要的就是日志,因为在服务器类上并没有直接返回,所以,本篇先把日志加上。 Demo  下载地址  链接:https://pan.baidu.com/s/1BPVRLS07qk-WPi-txERKbg?pwd=1234......