Wir haben eine Enterprise-Anwendung (als Ohr implementiert) ist ein Batch-Prozessor, der mehrere Threads erstellt, um gleichzeitig an den Batch-Elementen zu arbeiten (bis zu einer maximalen Anzahl gleichzeitiger Threads). Als Teil der Verarbeitung werden Aufrufe an einige RESTful-Webdienste in demselben Glassfish, jedoch über zwei Domänen hinweg, ausgeführt. Jede Anwendung protokolliert ihre eigene Anwendungsprotokolldatei auf dem Server und alle Protokolle werden auch von einem Splunk-Server aufgenommen.So "folgen" Sie einzelnen Transaktionen in Protokollen (Java EE)
Wir wurden gebeten, eine Möglichkeit zu finden, jede Log-Anweisung zu "taggen", so dass wir alle Protokolle durchsuchen und alle Anweisungen abrufen können, die sich mit der Verarbeitung eines Batch-Elements befassen.
Jedes zu verarbeitende Element verfügt über eine eindeutige ID, sodass das Hinzufügen zu den Prozessorprotokollanweisungen einfach ist. Die Frage ist, wie wir die Protokolle aus den Web-Services markieren?
Ein Vorschlag bestand darin, jedem Webservice-Aufruf einen Parameter hinzuzufügen, der diese ID annimmt und diese an jede Methode dieser Dienste weitergibt. Ich denke, es ist eine verrückte Idee, diese Art von Code zu ändern, um einen Wert einfach für die Protokollierung zu übergeben.
Hat jemand so etwas getan? Irgendwelche Vorschläge, wie Log-Statements zu identifizieren sind, die "zusammengehören"?
Übrigens verwenden wir slf4j mit log4j, aber wir erwägen die Verwendung von Logback.
UPDATE
Ich habe auf das Bestehen der Transaktions-ID als HTTP-Header gearbeitet, aber kann nicht scheinen recht arbeiten, um es zu machen. Ich verwende Jersey für meine und hier ist, was ich habe:
My Processor Klasse, die ihren Wert in der Logging-MDC als transactionId und verwendet einen REST-Service-Client für einige Verarbeitung setzt:
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
}
}
Mein RESTClient für den Zugriff auf den REST-Service. Es ist hier, dass ich die transactionId aus dem MDC ziehen und sie als Header auf die Anforderung hinzu:
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
}
}
}
Meine REST-Service-Ressourcen-Klasse, die die transactionId in seinen Anfrage-Header und legt sie in seiner Protokollierung haben sollte 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");
}
}
}
Aufgrund meiner Protokollierung, ich weiß, dass die transactionId im Prozessor MDC gesetzt wird, und wird von ihr durch die RESTClient Klasse gezogen. Es wird jedoch nicht als HTTP-Header an den REST-Service übergeben. Kann mir jemand sagen warum nicht?
Prozessor-Protokolldatei:
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 Service-Protokolldatei:
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.
UPDATE ZWEI
den logischen Fehler in meinem obigen Code gefunden:
if (transactionID != null && transactionID.isEmpty())
Sie den SOAP-Umschlag zu „verstecken“, dass lästigen Job-ID aus den Geschäftsdaten verwenden können, Vielleicht:
hätte sein sollen:
if (transactionID != null !&& transactionID.isEmpty())
Danke für den Vorschlag. Leider sind unsere Dienste RESTful Dienste. Ich habe das OP zur Klarstellung aktualisiert. – sdoca
@sdoca: Ich bin mir sicher, dass entweder die JAX-RS-Spezifikation oder Ihr freundlicher JEE-Server-Hersteller Interzeptoren für JAX-RS-Anfragen bereitstellt. Und der HTTP-Header kann das zusätzliche Tag enthalten. Das Prinzip ist genauso, nur der Wortlaut ist ein bisschen anders. –
Sie waren die Idee, eine Kopfzeile hinzuzufügen, war großartig. Vielen Dank! – sdoca