java - jdk14logger - org apache commons logging logfactory




Java日誌記錄:顯示調用者的源行號(而不是日誌記錄助手方法) (6)

Java的眾多(嘆氣......)日誌框架都可以很好地顯示創建日誌消息的方法的源文件名的行號:

log.info("hey");

 [INFO] [Foo:413] hey

但是如果在它們之間有一個輔助方法,那麼實際的調用者將是輔助方法,這不是太多的信息。

log_info("hey");

[INFO] [LoggingSupport:123] hey

有沒有辦法告訴日誌記錄系統在確定要打印的源位置時從callstack中刪除一個幀?

我想這是具體實施的; 我需要的是Log4J通過Commons Logging,但我很想知道其他選項。


也許您可以使用堆棧跟踪元素實現日誌幫助函數,獲取行號,並使用帶有某些特定註釋的方法繞過框架,例如,

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註釋,您將獲得正確的源行號,這是您真正想要的。


如果您有自己的日誌記錄實用程序方法,則可以將linenumber和filename添加到日誌記錄參數列表中並使用cpp路由。 即在進行編譯之前預處理源代碼以替換_ LINE _和_ FILE _等標記。 作為一個額外的獎勵,這不會像在運行時弄清楚那麼多的資源。


替代答案。

可以通過使用該方法要求log4j排除幫助程序類

Category.log(String callerFQCN,Priority level,Object message,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將照常工作,如果不需要,則避免計算堆棧跟踪。


添加細節到KLE答案。 (抱歉,noob用戶,不知道比創建單獨答案更好的方法)

您可以將其放在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>

注意:允許用戶控制行號在消息中的顯示位置和方式。 但是,由於獲取堆棧跟踪的成本非常高,因此您仍需要找到關閉該功能的方法。


請注意,提供行號非常昂貴 ,無論是從Log4j還是以下內容中獲得的。 你必須接受這個成本......

您可以使用以下API:

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

更新:

你必須自己計算。 所以:

  • 請求log4j不輸出它(以您的日誌格式),
  • 並在郵件的開頭插入行號explicitement(發送到log4j的String)。

根據您喜歡的記錄器,您的幫助方法可能:

  • 在適當的時候使用顯式的Logger(作為我猜的參數傳遞)(我們有時為特定的上下文定義特定的記錄器;例如,我們有一個記錄器來發送我們的數據庫請求,無論它是什麼類;這使我們能夠減少當我們想要(取消)激活它們時,在一個地方對我們的配置文件進行更改...)
  • 使用Logger作為調用類:在這種情況下, 您可以同樣推導出調用者類名稱 ,而不是傳遞參數。

開箱即用是不可能的。 在這種情況下,您可以做的最好的事情是在調用者中創建記錄器並將其傳遞給util方法。 這樣,您至少可以了解來電的來源。







apache-commons-logging