本系列的博客从logback怎么对接slf4j开始,逐步介绍了LoggerContext、Logger、ContextInitializer、Appender、Action等核心组件。跟读logback的源码到这个程度,虽然不能说精通,不过至少日常的配置,和简单的自定义扩展都不会有问题了。
这一篇是本系列博客的最后一节,介绍一下实际记录日志的类Encoder。其实继续深入下去,logback还是有很多值得研究的地方,比如Layout、Listener等。不过我个人感觉对logback框架已经比较熟悉了,所以就告一段落,有兴趣的朋友可以自己再深入下去。下一步我准备读一读struts2的源码,因为个人感觉spring、tomcat、hibernate可能难了一点,最近的工作比较忙,不会有太多的时间钻研技术,所以就挑选比较简单的struts2来读一读。
前面的文章我们已经介绍过,logback记录日志的入口是Logger类,然后Logger类又是委托Appender来记录日志,但是实际上,Appender还不是实际工作的类,Appender往往还要委托Encoder来记录日志。可能会觉得有点绕,但是一直跟下来的朋友可能会跟我有一样的感觉,就是logback框架的这种设计风格,虽然复杂了一点,但是在可扩展性上确实比较好
好了,老规矩,首先上图:
从图中我们可以看到,Encoder是一个接口,定义了3个方法,其中最重要的方法是doEncode(ILoggingEvent event)方法
然后EncoderBase抽象类部分实现了Encoder接口,其实就是持有了一个OutputStream的引用,这是为了后面调用outputStream.write(byte[] b)方法,毕竟最终,日志信息是要写到输出流里才可以的
EncoderBase又有若干个具体的实现类,但是实际上真正有意义的就是LayoutWrappingEncoder,这个实现类持有一个Layout字段,委托Layout的doLayout(ILoggingEvent event)方法,来把一个日志事件转换成String。由于基本上只会使用PatternLayoutEncoder,所以在logback.xml里这是无需配置的,如果使用了<encoder>标签,不指定实现类,那么就会默认使用PatternLayoutEncoder
上面大致介绍了一下结构,下面就来看具体的代码
public interface Encoder<E> extends ContextAware, LifeCycle {
/**
* This method is called when the owning appender starts or whenever output
* needs to be directed to a new OutputStream, for instance as a result of a
* rollover. Implementing encoders should at the very least remember the
* OutputStream passed as argument and use it in future operations.
*
* @param os
* @throws IOException
*/
void init(OutputStream os) throws IOException;
/**
* Encode and write an event to the appropriate {@link OutputStream}.
* Implementations are free to differ writing out of the encoded event and
* instead write in batches.
*
* @param event
* @throws IOException
*/
void doEncode(E event) throws IOException;
/**
* This method is called prior to the closing of the underling
* {@link OutputStream}. Implementations MUST not close the underlying
* {@link OutputStream} which is the responsibility of the owning appender.
*
* @throws IOException
*/
void close() throws IOException;
}
这是Encoder的接口定义,大致上,只要关注doEncode()方法就可以了
abstract public class EncoderBase<E> extends ContextAwareBase implements Encoder<E> {
protected boolean started;
protected OutputStream outputStream;
public void init(OutputStream os) throws IOException {
this.outputStream = os;
}
public boolean isStarted() {
return started;
}
public void start() {
started = true;
}
public void stop() {
started = false;
}
}
如前所述,EncoderBase主要是为了方便用户的自定义扩展(在使用logback框架的时候,基本上只要是允许扩展的组件,都提供了一个Base抽象类,所以要自定义扩展,最简单的办法就是写一个类继承自XXXBase),这里持有了一个OutputStream对象,目的是为了稍后调用outputStream.write()方法
public class EchoEncoder<E> extends EncoderBase<E> {
String fileHeader;
String fileFooter;
public EchoEncoder() {
}
public void doEncode(E event) throws IOException {
String val = event + CoreConstants.LINE_SEPARATOR;
outputStream.write(val.getBytes());
}
public void close() throws IOException {
if (fileFooter == null) {
return;
}
outputStream.write(fileFooter.getBytes());
}
public void init(OutputStream os) throws IOException {
super.init(os);
if (fileHeader == null) {
return;
}
outputStream.write(fileHeader.getBytes());
}
}
这是EchoEncoder,基本上,这个类只是起一个示例的作用,在实际应用中,不能配置Layout的Encoder没有太大的意义。该类的doEncode()方法就是对日志事件加上一个分行符,然后通过outputStream输出,也就是说,使用这个encoder的时候,不需要配置layout。下面看一下关键性的LayoutWrappingEncoder,由于持有了Layout组件,所以这个Encoder有了自定义输出格式的能力,所以也是目前基本上唯一有实用性的Encoder组件
public void init(OutputStream os) throws IOException {
super.init(os);
writeHeader();
}
void writeHeader() throws IOException {
if (layout != null && (outputStream != null)) {
StringBuilder sb = new StringBuilder();
appendIfNotNull(sb, layout.getFileHeader());
appendIfNotNull(sb, layout.getPresentationHeader());
if (sb.length() > 0) {
sb.append(CoreConstants.LINE_SEPARATOR);
// If at least one of file header or presentation header were not
// null, then append a line separator.
// This should be useful in most cases and should not hurt.
outputStream.write(convertToBytes(sb.toString()));
outputStream.flush();
}
}
}
这个类在初始化的时候,会把文件头首先输出,这主要是在HTMLLayoutBase中的,如果不准备以HTML格式输出日志,这2个方法是可以忽略的
public void doEncode(E event) throws IOException {
String txt = layout.doLayout(event);
outputStream.write(convertToBytes(txt));
outputStream.flush();
}
然后看一下最最关键的doEncode()方法,它委托layout组件将日志事件转换成String字符串,然后通过outputStream输出。。。
好吧,所以到这里其实还没有完,接下来就要看看Layout组件是怎么把ILoggingEvent转换成String的了。不过这已经不是本篇的主题,本人也不准备继续了,只能告诉大家,Layout组件是委托Converter组件,按照配置文件里定义的格式,得到格式化之后的字符串的,有兴趣的朋友可以继续研究研究
本系列博客就到此结束了,个人感觉从中收获最大的代码有以下几个地方:
1、logback框架用JoranConfigurator来实现配置的设计思路是非常值得借鉴的,这部分内容记录在ContextInitializer那篇博客里
2、logback通过Logger-->Appender-->Encoder层层委托,来实现日志记录的思路也很精彩,通过这种层层委托的方式,使整个框架的灵活性和扩展性都很强
3、用StaticLoggerBinder类来实现具体日志框架和slf4j门面的对接,这部分的设计思路和代码也相当不错
4、ContextSelectorStaticBinder类,解决了在JNDI等环境下,不同应用使用不同的LoggerContext的问题,解决问题的思路也很值得学习
5、用XXXBase类来提供自定义组件扩展点的方法,在设计系统时也可以借鉴
总的来说,logback是一个很优秀的开源日志框架,阅读其源码除了可以加深对其理解,更好地使用它之外,还可以通过其中优秀的设计思想和代码实现,提高自己的编程水平。我认为如果想阅读源码的话,logback框架是一个不错的开始
本系列博客就到这里了,后面我准备读一读struts2框架
- 大小: 107.5 KB
分享到:
相关推荐
Spring Boot与Logback源码解读涉及了Spring Boot框架在启动过程中如何与Logback日志系统集成,以及Logback是如何进行初始化和配置的。下面将详细解读Logback和Spring Boot的相关知识点。 ### Logback初始化过程 ...
- `ch.qos.logback.classic.encoder` 包含了用于格式化日志消息的 Encoder 类,如 PatternLayoutEncoder。 - `ch.qos.logback.classic.filter` 提供了多种过滤器,如 LevelMatchFilter、DenyAllFilter 等,允许...
Logback是一个广泛使用的Java日志框架,它提供了高效、灵活的日志记录功能。而Kafka是一个分布式流处理平台,常用于实时数据管道和流应用,它具有高吞吐量、可持久化以及容错性等特性。当我们需要将日志实时地传输到...
《Shiro简单登录+Logback日志记录》 在现代Web开发中,权限管理和日志记录是两个不可或缺的环节。Apache Shiro是一个强大且易用的Java安全框架,提供了认证、授权、会话管理和加密等功能,而Logback作为Log4j的替代...
`logback-demo`项目就是一个典型的日志记录示例,它基于流行的Java日志框架——Logback,展示了如何在实际应用中有效地管理和使用日志。 **Logback 框架简介** Logback是由Ceki Gülcü创建的,作为Log4j的后继者...
Logback 提供了高效的日志记录能力,适用于各种规模的应用程序。本教程将详细介绍如何配置 logback 以实现日志记录,并探讨不同配置方式。 首先,`pom.xml` 文件是 Maven 项目的配置文件,它包含了项目的依赖信息。...
Logback允许用户通过实现`ch.qos.logback.core.UnsynchronizedAppenderBase`或`ch.qos.logback.core.AppenderBase`类并覆盖`append()`方法来自定义日志处理逻辑。例如,我们可以解析JSON格式的日志,从中提取关键...
《Logback配置文件根据LEVEL级别将日志分类保存到不同文件》 日志管理是软件开发中的重要一环,它能帮助开发者追踪程序运行状态,定位问题,优化性能。Logback是一个广泛使用的日志框架,它允许我们高效地处理日志...
本资源包含的是关于`SpringMVC`、`Log4j2`、`Logback`以及`Jackson`的日志脱敏实现源码,提供了多种实现方式,旨在帮助开发者在保障信息安全的同时,充分利用日志进行系统分析。 1. **基于正则表达式的日志脱敏实现...
本文将详细介绍如何使用logback-test.xml配置文件进行日志记录,并通过一个简单的项目DEMO来演示其运行过程。** **SLF4J 是一个日志门面,它为各种日志框架提供了统一的接口,如Log4j、Logback等。这样做的好处是,...
《基于SpringBoot的日志脱敏:Logback与Slf4j的实战应用》 在现代的软件开发中,日志系统是不可或缺的一部分,它为开发者提供了系统运行时的详细信息,帮助排查问题,优化性能。SpringBoot框架以其简洁的配置和强大...
Logback是Java世界中广泛使用的日志记录工具,它提供了高效的日志记录功能,而WebSocket则是一种在客户端和服务器之间建立持久连接的协议,允许双向通信。这种组合使得应用程序能够实时地将日志信息推送到前端展示,...
在实际应用中,根据项目需求,可以通过修改 `logback.txt` 文件来调整日志系统的行为,确保日志记录既满足调试需求,又不会过度消耗系统资源。Logback 的高效性能和强大的功能使其成为 Java 开发中的首选日志解决...
这里,`LoggerFactory.getLogger(MyClass.class)`会返回一个与当前类关联的Logger实例,然后可以通过`info`和`error`方法记录不同级别的日志。 6. **高级配置** Logback支持更复杂的配置,如文件输出、日志滚动、...
Logback 是一个流行的开源日志记录框架,广泛用于Java应用程序中。它提供了高效、灵活的日志记录机制,允许开发者根据需要调整日志级别、格式和输出目的地。在某些情况下,尤其是处理异常时,Logback可能会生成大量...
如果我们想使用 Log4J2 作为日志记录工具,我们需要去除 Logback JAR 并且在类路径中加入 Log4J2 的依赖。 例如,我们可以在 pom.xml 文件中添加以下依赖项: <groupId>org.springframework.boot <artifactId>...
Logback 是一个用于日志记录的开源框架,由 Ceki Gülcü(SLF4J 的创始人)开发。它是 log4j 的后继者,旨在提供更高的性能、更灵活的配置以及更好的可扩展性。Logback 主要由三部分组成:`logback-core`(基础组件...
Logback是Spring Boot默认的日志实现,它提供了一种高效且灵活的日志记录方式。本文将介绍如何利用Spring Boot和Logback来实现一个简单的链路追踪功能,以便更好地跟踪用户在系统中的操作。 链路追踪(Traceability...
标题中的“扩展logback将日志输出到Kafka实例扩展源码”指的是在Java应用程序中,使用logback作为日志框架,并通过自定义appender(输出模块)将日志信息发送到Apache Kafka的消息队列中。Logback是SLF4J(Simple ...
本篇文章将深入探讨logback的核心概念、配置以及如何在实际项目中通过代码进行日志记录。 一、Logback 简介 Logback 是一个完整的日志解决方案,它包括三个主要组件:logback-classic、logback-core 和 logback-...