logback的自定义,也是类似的,都是基于一个基类appender来实现。本身logback提供了AppenderBase和UnsynchronizedAppenderBase两个抽象类(同步和非同步),所以我们自定义时,只需要看实际业务继承其中的一个即可。先看下其类继承结构:
0.编写自定义appender类。
MyLogbackAppender.java
@Getter @Setter public class MyLogbackAppender extends UnsynchronizedAppenderBase<ILoggingEvent>{ Layout<ILoggingEvent> layout; //自定义配置 String printString; @Override public void start(){ //这里可以做些初始化判断 比如layout不能为null , if(layout == null) { addWarn("Layout was not defined"); } //或者写入数据库 或者redis时 初始化连接等等 super.start(); } @Override public void stop() { //释放相关资源,如数据库连接,redis线程池等等 System.out.println("logback-stop方法被调用"); if(!isStarted()) { return; } super.stop(); } @Override public void append(ILoggingEvent event) { if (event == null || !isStarted()){ return; } // 此处自定义实现输出 // 获取输出值:event.getFormattedMessage() // System.out.print(event.getFormattedMessage()); // 格式化输出 System.out.print(printString + ":" + layout.doLayout(event)); } }也简单说明下,相关注意点:
start方法:初始时调用。故在编写如数据库入库,连接缓存或者mq时,可以在这个方法里面进行初始化操作。
stop:当停止时,调用。可做些资源释放操作。
1.使用自定义appender:
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 --> <property value="/home" /> <!-- 控制台输出 --> <appender> <filter> <!-- 日志收集最低日志级别 --> <level>INFO</level> </filter> <layout> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </layout> <!-- 自定义参数 --> <printString>一枚趔趄的猿(logback)</printString> </appender> <!-- 自定义包下设置为INFO,则可以看见输出的日志不包含debug输出了 --> <logger level="INFO" /> <!-- 日志输出级别 --> <root level="INFO"> <appender-ref ref="MyLogback" /> </root> </configuration>2.应用启动,查看控制台输出,效果是一样的:
...部分省略... 一枚趔趄的猿(logback):2018-08-25 15:01:57.486 [main] INFO org.apache.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"] 一枚趔趄的猿(logback):2018-08-25 15:01:57.497 [main] INFO org.apache.tomcat.util.net.NioSelectorPool - Using a shared selector for servlet write/read 一枚趔趄的猿(logback):2018-08-25 15:01:57.520 [main] INFO o.s.b.c.e.tomcat.TomcatEmbeddedServletContainer - Tomcat started on port(s): 8080 (http) 一枚趔趄的猿(logback):2018-08-25 15:01:57.523 [main] INFO c.l.l.springboot.chapter25.Chapter25Application - Started Chapter25Application in 54.349 seconds (JVM running for 55.377) 一枚趔趄的猿(logback):2018-08-25 15:01:57.524 [main] INFO c.l.l.springboot.chapter25.Chapter25Application - Chapter25启动! 关于ShutdownHook当你运行了以上的自定义appender后,停止应用时,你会发现定义的stop方法并没有被执行。还需要配置一个ShutdownHook系统钩子,使得在jvm在退出时之前会调用。
一点知识我们知道,在java中,注册一个关闭钩子是很简单的,使用Runtime类即可,具体用法如下:
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { // 执行资源释放操作 } }));而在SpringBoot中,只需要配置logging.register-shutdown-hook为true即可。
logging.register-shutdown-hook=true对于logback而言,也可以在logback-spring.xml中配置:
<shutdownHook/>也是可以的。再或者在启动类手动注册这个DelayingShutdownHook也是可以的
这里有个坑,log4j2而言,配置失效了。谷歌了一圈也没有发现解决方法,网上的方案试了一遍都是不行。。很尴尬。要是使用log4j2的话,可以取巧下,在start()方法里面,注册钩子之后调用stop方法。希望有知道的大神分享下如何解决!
参考资料
https://blog.csdn.net/zhoucheng05_13/article/details/78494458
https://logback.qos.ch/manual/appenders.html
https://blog.csdn.net/hupoling/article/details/75353854
总结