实际上Appender可能是logback框架中最重要的组件之一,虽然Logger是记录日志的接口,但是如果一个Logger没有关联到任何Appender的话,那么这个Logger就无法记录任何信息。此外虽然logback提供了很多扩展点,但是在应用中,我们可能很少会扩展filter,很少扩展layout和encoder,但是我们扩展Appender的机会却是很多的

老规矩,首先上图,看一下Appender的大图景,这里要说明的是,实现Appender接口有2个base类,一个是AppenderBase,另一个是UnsynchronizedAppenderBase,这2个类非常接近,80%以上的代码都是相同的。如果我们自己要自定义Appender的话,只要写一个类继承自这2个base类就好

首先是有一个Appender接口,然后如上文所说,UnsynchronizedAppenderBase类实现了这个接口,但是它本身是一个抽象类,需要继承它才能得到真正的实现类。Appender接口继承了FilterAttachable接口,而UnsynchronizedAppenderBase类持有一个FilterAttachableImpl类,委托这个类来实现FilterAttachable接口里定义的方法

然后OutputStreamAppender是继承自UnsynchronizedAppenderBase的Appender实现类,虽然它已经不是抽象类了,但是实际也是不能直接使用的,它的实现类就是最常见的ConsoleAppender和FileAppender

只要自己使用过logback的朋友都知道,appender元素下面还需要配置encoder元素,这里的Encoder接口就是对应这个encoder元素的,因为其实Appender组件还不是最终实际记录日志信息的组件,它要委托encoder组件来完成LoggingEvent的格式化和记录

介绍完了大体的结构,我们接下来就看看,从Appender接口的doAppend()方法,是怎么一步步地最终记录日志的

首先是UnsynchronizedAppenderBase里面的doAppend()方法,它主要是记录了Status状态,然后检查Appender上的Filter是否满足过滤条件,最后再调用实现子类的appender()方法。很眼熟是吗,这里用到了一个设计模式——模板方法

Java代码 收藏代码

public void doAppend(E eventObject) {  // WARNING: The guard check MUST be the first statement in the  // doAppend() method.  // prevent re-entry.  if (Boolean.TRUE.equals(guard.get())) {  return;  }  try {  guard.set(Boolean.TRUE);  if (!this.started) {  if (statusRepeatCount++ < ALLOWED_REPEATS) {  addStatus(new WarnStatus(  "Attempted to append to non started appender [" + name + "].",  this));  }  return;  }  if (getFilterChainDecision(eventObject) == FilterReply.DENY) {  return;  }  // ok, we now invoke derived class' implementation of append  this.append(eventObject);  } catch (Exception e) {  if (exceptionCount++ < ALLOWED_REPEATS) {  addError("Appender [" + name + "] failed to append.", e);  }  } finally {  guard.set(Boolean.FALSE);  }  }  abstract protected void append(E eventObject);

上面的代码非常简单,就不用说了,我们就直接看看实现类的append()方法是怎么实现的,这里我们选择OutputStreamAppender实现类

Java代码 收藏代码

@Override  protected void append(E eventObject) {  if (!isStarted()) {  return;  }  subAppend(eventObject);  }  

首先检查一下这个Appender是否已经启动,如果没启动就直接返回,如果已经启动,则又进入一个subAppend()方法

Java代码 收藏代码

/** * Actual writing occurs here. * <p> * Most subclasses of <code>WriterAppender</code> will need to override this * method. *  * @since 0.9.0 */  protected void subAppend(E event) {  if (!isStarted()) {  return;  }  try {  // this step avoids LBCLASSIC-139  if (event instanceof DeferredProcessingAware) {  ((DeferredProcessingAware) event).prepareForDeferredProcessing();  }  // the synchronization prevents the OutputStream from being closed while we  // are writing. It also prevents multiple thread from entering the same  // converter. Converters assume that they are in a synchronized block.  synchronized (lock) {  writeOut(event);  }  } catch (IOException ioe) {  // as soon as an exception occurs, move to non-started state  // and add a single ErrorStatus to the SM.  this.started = false;  addStatus(new ErrorStatus("IO failure in appender", this, ioe));  }  }  

这个方法居然什么事也不干。。做了一些检查以后,又进入writeOut()方法。。。

Java代码 收藏代码

protected void writeOut(E event) throws IOException {  this.encoder.doEncode(event);  }  

writeOut()方法委托配置给它的Encoder组件来记录

Java代码 收藏代码

public void doEncode(E event) throws IOException {  String txt = layout.doLayout(event);  outputStream.write(convertToBytes(txt));  outputStream.flush();  }  

到这里,终于完了。Encoder组件又委托其Layout组件来将LoggingEvent进行格式化,返回一个String,然后通过OutputStream.write()方法,把格式化之后的日志信息写到目的地

耐心看到这里的朋友,可能已经有点被绕晕了,怎么Appender需要这么麻烦吗?其实我们这里说的只是ConsoleAppender的doAppend()全流程,并不是所有Appender都这么复杂的,当然也有一些更复杂的。。

下面看一个简单的Appender,就是我自己写的MyAppender

Java代码 收藏代码

public class MyAppender extends AppenderBase<LoggingEvent> {  @Override  protected void append(LoggingEvent eventObject) {  System.out.println(eventObject.getMessage());  }  }

好吧,非常简单是不是,如果把这个Appender配置到logback.xml中,那么当Logger.info()调用的时候,就会先走进AppenderBase类的doAppend()方法里,进行Filter校验等等,然后进入MyAppender的append()方法,不做其他的操作,直接把message给打印到Console上。当然,由于这个类是极度简化的,没有Encoder和Layout,也就没办法控制输出日志的时间,也没有办法对%thread等标记进行解析处理了。但是这个类可能可以很清晰地表达出,Appender组件是怎么工作的:由AppenderBase类来调用Filter链,然后由Appender实现类来委托Encoder解析LoggingEvent,再输出到目的地

实习成长:logback收集项目日志,实现日志告警机器人相关推荐

  1. 启动项目无法打印日志处理及logback简单使用

    一.启动项目无法打印日志处理 运行maven web项目是提示如下代码 WARN No appenders could be found for logger 处理 在resources 目录下创建l ...

  2. golang练手项目日志收集项目(二)

    项目介绍:日志收集项目 主要功能:收集日志并且可视化查询日志 开发环境 :windos+idea 项目描述:收集日志并且在可视化页面中查询日志信息 主要技术:etcd+kafka+ElasticSea ...

  3. Day3-T31项目 异常处理与日志——2021-11-02

    Day3-T31项目 异常处理与日志 2021-10-30 按道理来说应该是在10月30号完成第三天的笔记,但是因为个人原因,要去学校办理实习的相关证书和表格耽误了,拖到现在补交.嘿嘿~ 起始站 Da ...

  4. springboot项目输入打印日志文件到本地

    springboot项目输入打印日志文件到本地 pom.xml中添加jar包: <dependency><groupId>ch.qos.logback</groupId& ...

  5. Logback 配置文件这么写,日志 TPS 提高 10 倍

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 何甜甜在吗 来源 | juejin.im/post/5d4d61326fb9a06 ...

  6. Spring Boot(十)Logback和Log4j2集成与日志发展史

    一.简介 Java知名的日志有很多,比如:JUL.Log4j.JCL.SLF4J.Logback.Log4j2,那么这些日志框架之间有着怎样的关系?诞生的原因又是解决什么问题?下面一起来看. 1.1 ...

  7. 收集、分析线上日志数据实战——ELK

    本文来自网易云社区 作者:田躲躲 用户行为统计(User Behavior Statistics, UBS)一直是互联网产品中必不可少的环节,也俗称埋点.对于产品经理,运营人员来说,埋点当然是越多,覆 ...

  8. 项目中统一日志文件配置

    1.统一日志处理的目的: 将日志记录在文件中,方便运维和开发做错误排查 文件日志需要做滚动输出(输出到更多的日志文件中),避免单日志体积过大,拖垮服务器 可以方便的在开发环境和生产环境等环境中切换输出 ...

  9. 系统集成项目需求调研日志

    最近正在负责一个套产品的实施工作,虽然我们的产品在功能上已经覆盖的相对比较完善了,但是在某些地方还是不能满足个别客户个性化的需求,因此得对这种具有个性化需求的客户展开额外的需求调研工作.我们的产品实施 ...

  10. java常用日志框架日志门面及实现 SLF4J 、Jboss-logging 、JCL、Log4j、Logback、Log4j2、JUL,springboot集成 log4j、log4j2

    java常用日志框架日志门面SLF4J .Jboss-logging .JCL.Log4j及实现 Logback.Log4j2.JUL,springboot集成 log4j.log4j2 .logba ...

最新文章

  1. linux 内核编译详解
  2. Vivado无法双击打开xpr工程文件的解决办法
  3. 数据结构与算法 / 红黑树
  4. 眺望全真互联时代!TVP音视频技术闭门会闪耀上海
  5. c语言sizeof和strlen哪个大,C语言的sizeof和strlen区别与联系
  6. 任务状态段TSS和TSS描述符
  7. LeetCode: Single Number I II
  8. 中文信息处理——使用结巴分词系统
  9. 智能手机之新手篇[转]
  10. 51单片机开发工具安装
  11. FANUC系统开发API(FOCAS2)pc应用开发,机加工领域
  12. 高校校园网建设方案【含网络拓扑图+拓扑结构图+配置命令】(详细版)
  13. 计算机在环境工程专业中的应用,计算机在环境科学与工程方向的应用.pdf
  14. 小提琴机器人拉法_手工小提琴价格,小提琴左手持琴姿势和肩托的使用
  15. Apple 等六大生态系统的崛起
  16. 计算机平面设计评分标准,竞赛各专业评分标准.DOC
  17. 【光学】Matlab模拟几何光学中的球差、彗差、像散、场曲四种像差
  18. 回收站清空的文件怎么恢复?学会这2招,简单又实用
  19. 三菱mode bus tcp通讯_泰州三菱MR-J4
  20. C语言图形库EasyX安装及基本使用

热门文章

  1. 计算机管理 窗口中找到 guest 用户,Guest 来宾用户不见了??
  2. Javascript特效:图片切换
  3. python中match用法_python re.match()用法相关示例
  4. FFmpeg学习(10)—— ffmpeg最全的命令参数
  5. 小目标到大目标一网打尽!阿里提出首个轻骨干重Neck的轻量级目标检测器GiraffeDet...
  6. ICCV 2021|“白嫖”性能的MixMo,一种新的数据增强or模型融合方法
  7. CNN已老,GNN来了:重磅论文讲述深度学习的因果推理(附资源)
  8. 如何使用git把本地代码上传(更新)到github上
  9. 字符串格式连接sqlserver数据库的字段概念解释
  10. spring boot 2.0.3+spring cloud (Finchley)1、搭建服务注册和发现组件Eureka 以及构建高可用Eureka Server集群...