Flogger是由Google开发、使用和推荐的,是一个Java的流畅式日志API。除了流畅性之外,Flogger还提供了比现有日志框架更多的其他功能,我们将在本教程中学习。
1.Flogger的依赖性
Flogger与SLF4J类似,作为一个抽象概念,使用底层日志框架作为实现。我们可以将Flogger与Java Logging API、Log4j2甚至SLF4J一起使用。默认情况下,flogger使用Java Util Logging API(JUL)。
1.1.Flogger核心
为了将flogger添加到应用程序中,我们需要添加com.google.flogger:flogger 和com.google.flogger:flogger-system-backend 依赖关系,这些依赖关系提供了编写日志信息的核心类和接口。
<dependency>
<groupId>com.google.flogger</groupId>
<artifactId>flogger</artifactId>
<version>0.7.4</version>
</dependency>
<!-- The Java Util Logging backend -->
<dependency>
<groupId>com.google.flogger</groupId>
<artifactId>flogger-system-backend</artifactId>
<version>0.7.4</version>
</dependency>
Flogger APIs内部依赖于flogger-system-backend,对于我们添加的任何日志平台,该系统都会被拉入中转。
1.2.底层日志后端
接下来我们需要从给定的日志平台中添加一个运行时依赖。我们将使用它的配置文件来定制日志级别和应用者等。
例如,如果我们使用Flogger和Log4j2,那么我们需要添加flogger-log4j2-backend 依赖关系。在导入这个依赖关系后,我们可以从log4j2.xml文件中控制日志级别、应用者、布局等。
<!-- The SLF4J backend -->
<dependency>
<groupId>com.google.flogger</groupId>
<artifactId>flogger-slf4j-backend</artifactId>
<version>0.7.4</version>
</dependency>
<!-- The Log4j backend -->
<dependency>
<groupId>com.google.flogger</groupId>
<artifactId>flogger-log4j-backend</artifactId>
<version>0.7.4</version>
</dependency>
<!-- The Log4j2 backend -->
<dependency>
<groupId>com.google.flogger</groupId>
<artifactId>flogger-log4j2-backend</artifactId>
<version>0.7.4</version>
</dependency>
2.Flogger API
2.1.FluentLogger
在应用类中使用Flogger提供的Fluent API,首先要创建一个FluentLogger 的实例。
import com.google.common.flogger.FluentLogger;
public class Main {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
}
接下来,我们可以开始使用FluentLogger实例来编写日志信息。
注意,我们不使用大括号{} 作为数据占位符,我们可以使用任何Java的printf() 格式指定器,如%s ,%d 等。
logger.atWarning().log("Warning message");
Article a = Article.builder(1L).title("Test Article").tag("Data").build();
logger.atInfo().log("Article found : %s", a);
这将以配置好的附加器和布局来打印日志信息。
2022-01-10 20:34:37.621 WARN [main] [com.howtodoinjava.demo.flogger.Main.main(Main.java:17)] - Warning message
2022-01-10 20:34:37.632 INFO [main] [com.howtodoinjava.demo.flogger.Main.main(Main.java:20)] - Article found : Article(id=1, title=Test Article, tags=[Data])
2.2.日志级别
在API层面,flogger支持由JDK Logging提供的日志级别。
- 关闭: 关掉日志记录。
- SEVERE。(最高值):一个严重的故障。
- WARNING: 一个潜在的问题。
- INFO: 信息性消息。
- 配置: 记录静态配置信息。
- 精细: 记录跟踪信息。
- 更多: 记录相当详细的追踪信息。
- FINEST:(最低值):记录一个高度详细的跟踪信息。
- 所有: 启用所有信息的日志记录。
我们可以使用下面的方法调用来记录特定级别的消息。
logger.atInfo().log("...");
logger.atWarning().log("...");
logger.atSevere().log("...");
logger.atFine().log("...");
logger.atFiner().log("...");
logger.atFinest().log("...");
logger.atConfig().log("...");
//Can be used for any log level
logger.at(Level.SEVERE).log("...");
日志级别可以使用底层日志平台的配置文件来设置*(logging.properties*,log4j.properties等)。
或者我们可以使用LoggerConfig类,以编程方式为一个记录器设置日志级别。
LoggerConfig.of(logger).setLevel(Level.INFO);
2.3.记录异常情况
使用withStackTrace() 方法来记录一个Throwable实例。
logger.atInfo()
.withStackTrace(StackSize.SMALL)
.withCause(new NullPointerException())
.log("NullPointerException Received");
2022-01-10 21:14:49 INFO Main:26 - NullPointerException Received
java.lang.NullPointerException: null
at com.howtodoinjava.demo.flogger.Main.main(Main.java:26) [classes/:?]
堆栈大小enum有3个常量。
- 堆栈大小。SMALL: 产生一个小的堆栈,适合于更精细的调试。
- 堆栈大小。MEDIUM: 产生一个中等大小的堆栈,适合为大多数日志语句提供上下文信息。
- 堆栈大小。LARGE: 产生一个大的堆栈,适合提供高度详细的上下文信息。
- 堆栈大小。FULL: 提供完整的堆栈跟踪。
- 堆栈大小。NONE。不提供堆栈跟踪。当堆栈大小是有条件的时候,这很有用。
logger.atWarning()
.withStackTrace(showTrace ? StackSize.MEDIUM : StackSize.NONE)
.log("message");
2.4.速率限制
这是一个有趣的功能,我们不希望在一个语句的每一次发生时都有一个日志信息。我们想在每一次出现的时候记录信息。
在给定的例子中,我们在每10次迭代中记录信息。
IntStream.range(0, 50).forEach(value -> {
logger.atInfo().every(10).log("The counter is => %d", value);
});
2022-01-10 21:13:23 INFO Main:30 - The counter is => 0
2022-01-10 21:13:23 INFO Main:30 - The counter is => 10
2022-01-10 21:13:23 INFO Main:30 - The counter is => 20
2022-01-10 21:13:23 INFO Main:30 - The counter is => 30
2022-01-10 21:13:23 INFO Main:30 - The counter is => 40
3.Flogger相对于其他日志框架的优势
现在我们对Flogger API有了基本的了解,让我们了解一下是什么让它如此有用,以至于谷歌推荐在组织内部使用它。
3.1.性能
根据谷歌的说法,Flogger通过构建一套精心构建的API,包括前端和后端,来设计和实现高性能的日志记录。
Flogger的API工作在日志平台之上,以提供尽可能好的性能。
3.2.禁用日志信息的成本
大多数日志框架在info()、debug()等方法中广泛地使用varargs。这些方法需要在被调用的方法被调用之前分配和填充一个新的Object[] 。此外,传入的任何基本类型必须是自动装箱的。
由于这个原因,一个简单的log.info(String, Object...) 方法在源代码层面上是简洁的,但在字节码中会引入令人惊讶的成本。更糟的是,即使日志语句被禁用,这种开销的字节码也会被执行。
从Google中对大型应用的日志行为的分析来看,禁用的日志语句比启用的日志语句被击中的次数要多出很多数量级。这是应该优先避免的事情。
当使用Flogger的流畅APIlogger.atInfo().log("My message: %s", arg); ,**我们可以知道在用atInfo()方法调用级别选择器时,日志记录是否被禁用。因此,如果日志记录被禁用,我们可以选择返回一个不同的日志记录上下文的实现,它在每一个后续的方法调用中都会抛弃所有的参数(一个 "No-Op "实例)。
方便的是,这个实例可以是自然不变的,并且是线程安全的,所以我们可以每次都返回相同的单子实例,这就避免了在禁止日志记录时分配任何形式的内存,从而提高了性能。
4.总结
Flogger似乎是非常有前途的API,具有上面讨论的一些伟大的优势。为了使其更加熟悉,我们可以使用现有的Log4j2或SLF4J配置,以便更容易地进行迁移。
在本教程中,我们学会了导入Flogger的依赖关系,并使用Flogger API来记录各种消息。你可以在Flogger的官方Github页面上阅读更多关于它的信息。
学习愉快!!