我們有一個企業應用程序(部署爲EAR)單個交易是創建多個線程批處理器對一批項目工作的同時(併發線程的最大數量)。作爲處理的一部分,它調用了部署在同一個Glassfish中的兩個RESTful Web服務,但跨兩個域。每個應用程序都會記錄到服務器上的自己的應用程序日誌文件中,並且所有日誌也將被Splunk服務器接收。如何「跟進」,在日誌(Java EE)
我們被要求找到一個方法來「標記」每個日誌語句,這樣,我們可以做的所有日誌搜索,並獲得所有與一批項目的加工處理的語句。
正在處理的每個項目都有一個唯一的ID,從而將這個給處理器日誌語句是容易的。問題是我們如何標記來自Web服務的日誌?
一個建議一直是一個參數添加到每個Web服務調用負責這種ID和propogates下來到這些服務的每個方法。我認爲將這種類型的更改編碼爲傳遞值僅用於日誌記錄是一個瘋狂的想法。
有沒有人做過這樣的事?關於如何識別「屬於一個」的日誌語句的任何建議?
順便說一句,我們使用log4j的使用SLF4J,但使用的logback正在考慮。
UPDATE
我一直在努力通過交易ID作爲HTTP頭,但似乎無法比較,使其工作。我使用的球衣我這裏是我得到了什麼:
我的處理器類,把它的值在日誌MDC作爲transactionId的和使用REST服務客戶端的一些處理:
public Processor
{
RESTClient myRESTClient = new RESTClient("http://path/to/restService");
public void process(final Object object)
{
//Put the object ID in the logging MDC
log.debug("Putting '{}' in the MDC as the {} header value.", object.getObjectID(), "transactionID");
MDC.put("transactionID", object.getObjectID());
//Do some stuff
Object anotherObject = myRESTClient.doQuery(object.getValue());
//Do more some stuff
}
}
我的RESTClient訪問REST服務。它在這裏,我是拉的transactionId出MDC,並添加它作爲一個頭的要求:
public RESTClient
{
public Object doQuery(String value)
{
Object object = null;
try
{
Builder builder = myRestService.queryParam(PARAM_KEY_VALUE, value)
.accept(MediaType.APPLICATION_XML);
String transactionId = (String) MDC.get("transactionID");
logger.debug("Retrieved '{}' from MDC for key {}",
transactionId,
"transactionID");
if (this.getTransactionID() != null)
{
builder = builder.header("transactionID", transactionId);
}
object = builder.get(Object.class);
}
catch (Throwable ex)
{
//Do error handling
}
}
}
我的REST服務資源類應具備的transactionId在其請求頭,並將其放置在其日誌MDC:
@Path("/myPath")
public class MyResource
{
@Context
private HttpContext httpContext;
@GET
@Produces(MediaType.APPLICATION_XML)
public Object doQuery(@QueryParam("value") String value)
{
putTransactionIdInMDC();
SubscriberAccount account = null;
try
{
//Do query stuff
}
catch (Exception ex)
{
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
return account;
}
private void putTransactionIdInMDC()
{
if (httpContext != null)
{
String transactionID = httpContext.getRequest()
.getHeaderValue("transactionID");
if (transactionID != null && transactionID.isEmpty())
{
/*
* It's not likely, but possible that two headers with the same
* header key were put in the request. If so, the value will be
* a comma separated list. We're using the first one.
*/
String[] strings = transactionID.split(",");
logger.debug("Header '{}' value(s): {}",
"transactionID",
strings);
MDC.put("transactionID", strings[0]);
}
else
{
logger.debug("The header '{}' was not included in the request.",
"transactionID");
}
}
else
{
logger.info("Could not get an HttpContext for the request");
}
}
}
根據我的記錄,我知道正在把中的transactionID處理器MDC並通過RESTClient實現類從它被拉出。但是,它不會作爲HTTP標頭傳遞給REST服務。誰能告訴我爲什麼不呢?
處理器日誌文件:
2012-04-13T17:30:36.541 MDT INFO [Ejb-Async-Thread-2] DEBUG my.package.Processor - Putting '12311497-2279-4516-af7d-cf9716f7748a' in the MDC as the transactionId header value.
2012-04-13T17:30:36.541 MDT INFO [Ejb-Async-Thread-2] DEBUG my.package.RESTClient- Retrieved '12311497-2279-4516-af7d-cf9716f7748a' from MDC for key transactionId
REST服務日誌文件:
2012 Apr 13 17:30:36,337 MDT [http-thread-pool-80(3)] DEBUG my.package.MyResource - The header 'transactionId' was not included in the request.
更新兩個
實測值的邏輯錯誤在我的上述代碼:
if (transactionID != null && transactionID.isEmpty())
應該是:
if (transactionID != null !&& transactionID.isEmpty())
感謝您的建議。不幸的是,我們的服務是RESTful服務。我已經更新了OP的澄清。 – sdoca 2012-04-01 23:57:13
@sdoca:我確定無論是JAX-RS規範還是友好的JEE服務器供應商都會爲JAX-RS請求提供攔截器。而且HTTP頭可以包含額外的標籤。原則是一樣的,只有措辭有點不同。 – 2012-04-02 17:44:34
你想添加標題非常棒。謝謝! – sdoca 2012-04-16 16:13:55