2011-07-31 99 views
7

是否可以在由java.util.logging.Logger生成的日誌語句中打印線程名稱? 一種選擇是像做以下幾點:使用java.util.logging打印線程名稱

logger.info(thread.getName() +" some useful info"); 

但它的重複和日誌框架應當予以受理。

+0

我相信,使用log4j或slf4j將比建議的答案更清晰。 :) – Diablo

回答

7

尷尬,但看起來像java.util.logging不能做到這一點...

默認java.util.logging.SimpleFormatter沒有登錄線程名在所有的能力。 java.util.logging.FileHandler支持很少的模板佔位符,它們都不是線程名稱。

java.util.logging.XMLFormatter是最接近的一個,但只記錄線程ID:

<record> 
    <date>2011-07-31T13:15:32</date> 
    <millis>1312110932680</millis> 
    <sequence>0</sequence> 
    <logger></logger> 
    <level>INFO</level> 
    <class>java.util.logging.LogManager$RootLogger</class> 
    <method>log</method> 
    <thread>10</thread> 
    <message>Test</message> 
</record> 

如果您認爲我們已經很接近了 - 我們不是。 LogRecord類只保存線程ID,而不是它的名稱 - 不是很有用。

1

某些應用程序服務器隱式記錄線程ID(我知道WebSphere)。您可以創建自己的LogFormatter。傳遞給格式化程序的記錄包含線程標識,請參閱here。我多次爲Tomcat實現了這種方法,但它也可以在Java SE環境中工作。

BTW:線程名稱不可用於LogRecord。

1

java.util.logging有許多奇怪的特性。你可以添加一個門面API來調整自己的行爲

public class Log 

    Logger logger; 

    static public Log of(Class clazz) 
     return new Log(Logger.getLogger(clazz.getName())); 

    public void error(Throwable thrown, String msg, Object... params) 
    { 
     log(ERROR, thrown, msg, params); 
    } 

    void log(Level level, Throwable thrown, String msg, Object... params) 
    { 
     if(!logger.isLoggable(level)) return; 

     // bolt on thread name somewhere 
     LogRecord record = new LogRecord(...); 
     record.setXxx(...); 
     ... 
     logger.log(record); 
    } 

---- 

static final Log log = Log.of(Foo.class); 
.... 
log.error(...); 

人們使用Java的記錄,主要是因爲他們不希望有第三方的依賴。這也是爲什麼他們不能依賴像apache或slf4j這樣的現有日誌外觀。

2

我有類似的問題。如這裏回答How to align log messages using java.util.logging可以延長java.util.logging.Formatter而是讓LogRecord#getThreadID()您可以通過調用Thread.currentThread().getName()這樣得到線程名:

public class MyLogFormatter extends Formatter 
{ 

    private static final MessageFormat messageFormat = new MessageFormat("[{3,date,hh:mm:ss} {2} {0} {5}]{4} \n"); 

    public MyLogFormatter() 
    { 
     super(); 
    } 

    @Override 
    public String format(LogRecord record) 
    { 
     Object[] arguments = new Object[6]; 
     arguments[0] = record.getLoggerName(); 
     arguments[1] = record.getLevel(); 
     arguments[2] = Thread.currentThread().getName(); 
     arguments[3] = new Date(record.getMillis()); 
     arguments[4] = record.getMessage(); 
     arguments[5] = record.getSourceMethodName(); 
     return messageFormat.format(arguments); 
    } 

} 
+7

這不會放入調用格式化程序的線程的線程名稱,而不是創建日誌條目的線程的線程名稱?我想他們在某些情況下可能是一樣的,但不能保證。 – pauli

1

上述幾個問題的答案表明,LogRecord.getThreadId()返回一個有意義的線程ID和我們所缺少的是一種將其與線索名稱相關聯的方式。

不幸的是LogRecord.getThreadId()返回一個int值,它不對應於誘導日誌消息的線程的長ID。

所以我們不能只使用ManagementFactory.getThreadMXBean()來解析線程名。它會導致隨機的線程名稱。

如果您確定您的日誌記錄工具始終在與調用方相同的線程中進行格式化,則可以按照上述建議創建自定義格式化程序,然後調用Thread.currentThread()。getName()。

這似乎是一個登錄門面或第三方庫是唯一完全安全的選項。

-1

爲了補充@ l245c4l答案:不要使用SimpleFormatter(的)使用:

//fileHandler.setFormatter(new SimpleFormatter()); 

class MyFormatter extends Formatter { 
    private final MessageFormat messageFormat = new MessageFormat("{0,date}, {0,time} {1} {2}: {3} [T:{4}] {5}\n"); 

    public String format(LogRecord record) 
    { 
     Object[] arguments = new Object[6]; 
     arguments[0] = new Date(record.getMillis()); 
     arguments[1] = record.getSourceClassName(); 
     arguments[2] = record.getSourceMethodName(); 
     arguments[3] = record.getLevel(); 
     arguments[4] = Long.toString(Thread.currentThread().getId()); 
     arguments[5] = record.getMessage(); 

     return messageFormat.format(arguments); 
    } 
} 

fileHandler.setFormatter(new MyFormatter()); 

Logger myLogger = Logger.getLogger("<LOGGER_NAME>"); 
myLogger.addHandler(fileHandler); 

其中T:{4}是線程ID(參數4)。