首页 > 解决方案 > 让我的记录器对我的 Java 应用程序非常有效

问题描述

我正在努力解决以下问题并寻求帮助。

我的应用程序有一个记录器模块。这需要跟踪级别和消息(作为字符串)。

通常应该是从不同来源和/或不同方式构造的消息(例如,在记录之前使用 String.format,其他时候使用不同对象的 .toString 方法等)。因此:错误信息的构造方法不能一概而论。

我想要的是使我的记录器模块有效。这意味着:只有在实际跟踪级别获得消息时,才会构建跟踪消息。这是通过防止在我的应用程序中复制粘贴代码来实现的。

使用 C/C++,通过使用宏很容易实现:

#define LOG_IT(level, message) if(level>=App.actLevel_) LOG_MSG(message);

仅当跟踪级别启用该消息时,才完成 LOG_MSG 和字符串构造。

对于 Java,我没有发现任何类似的可能性。为了防止:日志记录将是一行(没有 if-else 复制粘贴无处不在),并且仅在必要时才进行字符串构造(昂贵的操作)。

我知道的唯一解决方案是用 IF 语句包围每个记录器调用。但这正是我之前在 C++ 应用程序中避免的,也是我在实际 Java 实现中想要避免的。

我的问题是,在目标系统上只有 Java 1.6 可用。因此,供应商不是一个选择。

我可以在 Java 中做什么?这种 C/C++ 方法如何轻松完成?

标签: javaloggingmacroseffective-java

解决方案


首先,如果您正在考虑实现自己的记录器,我鼓励您阅读本文。

然后,我鼓励您查看完善的日志记录 API,例如 SLF4j。虽然可以创建自己的 API,但使用预先存在的 API 将为您节省时间、精力,最重要的是为您提供更多开箱即用的功能和灵活性(即基于文件的配置、可定制性(查看映射诊断上下文) )。

对于您的具体问题,没有一种简单的方法可以做您想做的事情。C/C++ 与 java 的根本不同之处在于预处理器允许使用您在上面创建的宏。Java 并没有真正易于使用的等价物,尽管有一些项目示例确实利用了编译时代码生成,这可能是最接近的等价物(即 Project Lombok、Mapstruct)。

我知道在记录时避免昂贵的字符串构建操作的最简单方法是用一个简单的条件围绕字符串的构建:

if ( logger.isTraceEnabled() )
{
    // Really expensive operation here
}

或者,如果您使用的是 Java 8,则标准日志库采用一个java.util.function.Supplier<T>参数,该参数仅在当前日志级别与所调用的日志记录方法的级别匹配时才会执行:

 log.fine(()-> "Value is: " + getValue());

目前还为 SLF4j 开放了一张票,用于在此处实现此功能。

如果您真的打算实现自己的记录器,那么上述两个功能很容易自己实现,但我再次鼓励您不要这样做。

编辑:Aspectj 编译时编织可用于实现类似于您想要实现的目标。它将允许您使用条件语句包装所有日志记录语句,以删除样板检查。


推荐阅读