使我的记录器对我的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++方法?

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

然后,我鼓励你看看一个完善的日志记录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编译时编织可用于实现类似于您要实现的目标。它将允许您使用条件语句包装所有日志记录语句,以便删除样板检查。

最新的日志记录库,包括java.util.logging,有第二种形式的方法,采用Supplier<String>

例如log.info( ()->"Hello");而不是log.info("Hello");.

仅当必须有效记录消息时,才会调用供应商的 get() 方法,因此您的字符串仅在这种情况下构造。

我认为这里要了解的最重要的事情是,C/C++宏解决方案不会通过不构造记录的消息来节省计算工作量,以防日志级别使得消息不会被记录。 为什么会这样?仅仅因为宏方法会使预处理器替换宏的所有用法:

LOG_IT(level, message)

使用代码:

if(level>=App.actLevel_) LOG_MSG(message);

替换您作为级别传递的任何内容和作为消息传递的任何内容以及宏本身。要编译的结果代码将与将宏代码复制并粘贴到程序中的任何位置完全相同。宏唯一能帮助您的是避免实际的复制和粘贴,并使代码更具可读性和可维护性。
有时他们设法做到这一点,有时他们使代码更加神秘,因此更难维护。在任何情况下,宏都不会提供延迟执行来避免您实际构造字符串,就像Java8 Logger 类使用 lambda 表达式所做的那样。Java 将 lambda 主体的执行推迟到最后一个可能的时间。换句话说,lambda 的主体在 if 语句之后执行。
回到 C\C++ 中的示例,作为开发人员,您可能希望代码无论日志级别如何都能正常工作,因此您将被迫构造一个有效的字符串消息并将其传递给宏。否则在某些日志级别,程序会崩溃!因此,由于消息字符串构造代码必须在调用宏之前,因此无论日志级别如何,您每次都将执行它。

因此,在 Java 6 中,制作等效于您的代码非常简单!您只需使用内置类:记录器。此类提供对自动日志记录级别的支持,因此您无需创建它们的自定义实现。
但是,如果您要问的是如何在没有lambda的情况下实现延迟执行,我认为这是不可能的。

如果你想在 C\C++ 中进行真正的延迟执行,你必须制作这样的日志记录代码,以便将函数指针指向返回消息字符串的函数,您将使您的代码执行由 if 语句内的函数指针传递给您的函数,然后您将调用宏传递的不是字符串而是创建和返回字符串的函数!我相信执行此操作的实际 C\C++ 代码超出了这个问题的范围......这里的关键概念是,C\C++为您提供了进行延迟执行的工具,因为它们支持函数指针。Java不支持函数指针,直到Java8

相关内容

  • 没有找到相关文章

最新更新