Java记录:表明呼叫者的源代码行号(未记录辅助方法)(Java Logging: show the

2019-07-19 20:10发布

Java的许多(叹气......)日志框架都这样做显示了创建日志信息的方法的源文件名行号的一个很好的工作:

log.info("hey");

 [INFO] [Foo:413] hey

但是,如果有一个辅助方法之间,实际的来电将是辅助方法,这是不是太丰富。

log_info("hey");

[INFO] [LoggingSupport:123] hey

有没有办法告诉测井系统从调用栈中删除一个帧搞清楚源位置打印时?

我想,这是具体的实施; 我需要的是通过共享日志记录Log4J的,但我很感兴趣地听到有关其他选项。

Answer 1:

备选答案。

它可以让log4j的使用方法排除辅助类

Category.log(字符串callerFQCN,优先级,消息对象,的Throwable t)的

并指定辅助类为“callerFQCN”。

例如,以下是使用辅助类:

public class TheClass {
    public static void main(String...strings) {
        LoggingHelper.log("Message using full log method in logging helper.");
        LoggingHelper.logNotWorking("Message using class info method");
}}

和辅助的代码:

public class LoggingHelper {
private static Logger LOG = Logger.getLogger(LoggingHelper.class);

public static void log(String message) {
    LOG.log(LoggingHelper.class.getCanonicalName(), Level.INFO, message, null);
}

public static void logNotWorking(String message) {
    LOG.info(message);
} }

第一种方法将输出您预期的结果。

Line(TheClass.main(TheClass.java:4)) Message using full log method in logging helper.
Line(LoggingHelper.logNotWorking(LoggingHelper.java:12)) Message using class info method

使用此方法时,将Log4j中照常工作,避免计算堆栈跟踪如果不需要它。



Answer 2:

请注意,给行号是一件很昂贵的 ,无论是对你的Log4j或以下得到什么自然。 你必须接受成本...

您可以使用下列API:

    StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
    StackTraceElement stackTraceElement = ...;
    stackTraceElement.getLineNumber();

更新:

你将不得不自己进行计算。 所以:

  • 问log4j的不输出它(在你的日志记录格式),
  • 并插入自己的行号explicitement在你的消息(您发送到log4j的字符串)的开始。

您可以根据自己喜欢的记录器,你的helper方法可以:

  • 使用一个明确的记录器,(作为参数我想通过)在适当的时候(有时我们定义了特定上下文中的具体记录仪;例如,我们对把我们的数据库请求一个记录器,不管是什么类做;这使我们能够减少到一个地方改变我们的配置文件进行,当我们想要(去)激活它们......)
  • 使用调用类记录器:在这种情况下,而不是传递参数, 同样可以推断出呼叫者的类名 ...


Answer 3:

出来的,有一个非常简单的解决方案,只需添加FQCN (包装类完全合格的类名)到你的记录帮手:

public class MyLogger extends Logger {

private static final String FQCN = MyLogger.class.getName() + ".";

protected MyLogger(String name) {
    super(name);
}

public void info(final Object msg) {
    super.log(FQCN, Level.INFO, msg, null);
}

//etc...

在你的工人阶级你只是做:

public class MyClass {

private static final Logger LOG = MyLogger.getLogger();   

private void test()
{
    LOG.info("test");
}

}


Answer 4:

添加细节KLE答案。 (对不起,小白用户,不知道是不是创建一个单独的答案更好的办法)

相反,坚持行号的消息,你可以把它放在MDC环境。 见org.apache.log4j.MDC

例如:

StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace();
StackTraceElement stackTraceElement = ...;
int l = stackTraceElement.getLineNumber();

MDC.put("myLineNumber", l);

这允许用户在他们的log4j的配置文件使用mylineNumber

<layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" 
           value="Line(%X{myLineNumber})- %m%n"/>
</layout>

注意:允许用户控制在何处和行号的显示在消息中。 然而,由于越来越堆栈跟踪是非常昂贵的,你还需要找到一种方法来关闭该功能。



Answer 5:

对于Log4j2如下的Log4j2手册中描述的答案是完全由使用记录器包装纸提供一个记录器生成的包装示例用法 。 人们可以简单地生成(使用说明那里的org.apache.logging.log4j.core.tools.Generate $ ExtendedLogger工具)记录仪的包装与单株水平,然后适应,要创建自定义日志记录方法模仿使用logIfEnabled的(FQCN,LEVEL,标记,消息的Throwable) - 可能忽略STUB水平和使用常规的 -​​ 然后如果需要的话,删除或注释出STUB水平和它的方法)。 为了这个目的,FormattedMessage能有所帮助。

源极线,而昂贵,然后可以很容易地通过使用在所述%升位置变换图案元件示出为的全部位置信息的一部分的PatternLayout在配置给定的,或者更具体地使用%L线数量和/或% M法转换。

现在提供完整的例子在: Java记录:Log4j的Version2.x:显示最终客户机调用者(未中间记录辅助方法)的方法



Answer 6:

这是不可能的开箱。 你可以在这种情况下,做的最好的是在调用创建记录器,并将其传递到UTIL方法。 这样,你至少可以得到一个想法,其中呼叫从何而来。



Answer 7:

如果你有自己的日志记录的实用方法,您可以添加行号和文件名记录参数列表,并采取CPP路线。 即预处理你的源更换标签,如_ LINE _和_ 文件 _你做编译之前。 作为额外的奖励,这将不采取nerly尽可能多的资源,因此在运行时搞清楚。



Answer 8:

也许你可以实现使用堆栈跟踪元素的日志辅助函数,得到了行号,并绕过与方法的框架与一些特定的注解,比如,

public @interface SkipFrame {}

// helper function
@SkipFrame // not necessary on the concrete log function
void log(String... message) {
    // getStackTrace()...
    int callerDepth = 2;  // a constant number depends on implementation
    StackTraceElement callerElement = null; 
    for (StackTraceElement e: stackTrace) {
         String className, methodName = e.getClassName, getMethodName()...
         Class callClass = Class.forName(className);
         // since there maybe several methods with the same name
         // here skip those overloaded methods
         Method callMethod = guessWhichMethodWithoutSignature(callClass, methodName);
         SkipFrame skipFrame = callMethod.getAnnotation(SkipFrame.class); 
         if (skipFrame != null)
             continue; // skip this stack trace element
         if (callerDepth-- == 0) {
             callerElement = e; 
             break;
         }
     }
     assert callerDepth == 0; 
     assert callerElement != null;
     Log4j.info(callerElement.getLineNumber()... + "message... "); 
}

@SkipFrame
void logSendMail(Mail mailObject) {
    log("Send mail " + mailObject.getSubject()); 
}

因此,如果辅助函数嵌套,或有更多的利用辅助功能,只是标记在所有设备上的SkipFrame注释,你会得到正确的源代码行数是你真正想要的。



文章来源: Java Logging: show the source line number of the caller (not the logging helper method)