Nicht-invasive Audit-Protokollierung
Welcher Entwickler hat nicht schon einmal an einem Projekt gearbeitet, bei dem irgendwann vor der endgültigen Auslieferung ein Mitarbeiter der Wartungsabteilung aufwacht und das Entwicklungsteam fragt, ob sie eine Audit-Protokollierung durchführen können... Genauer gesagt möchte er ein "detailliertes Protokoll" haben. Es sollte die IP-Adresse des Benutzers, seinen Anmeldenamen und einige Informationen darüber enthalten, welche Aktionen er durchgeführt hat und was die Ergebnisse waren...
Im Grunde genommen ist die Protokollierung ein alltäglicher Bestandteil des Lebens eines Entwicklers. Es ist einfacher, Fehler zu beheben, wenn Sie eine klare und präzise Protokollierung haben, und es gibt Ihnen einen Überblick darüber, was Ihre Anwendung tut. Aber jetzt bittet Sie der Wartungstechniker, die Protokollierung an bestimmten Stellen in Ihrer Anwendung einzubauen. Außerdem möchte er, dass Sie die Schnittstellen Ihrer Dienste anpassen, denn Sie müssen auch die IP-Adresse und den Benutzernamen des Benutzers protokollieren. Bei den meisten Webanwendungen weiß nur das Frontend, dass Sie sich im Web befinden. Wie können Sie das also erreichen...?
Geben Sie Spring-AOP und Log4J ein...
Mit der aspektorientierten Programmierung können Sie die Protokollierung deklarativ zu Ihrer Anwendung hinzufügen, was genau das ist, was wir in diesem Fall wollen. Wir möchten nicht durch unsere Anwendung gehen, um die Protokollierung hinzuzufügen, insbesondere nicht, da wir bereits wissen, dass der Wartungsmitarbeiter, sobald er die Protokollierung gesehen hat, wahrscheinlich weitere Standorte protokolliert haben möchte oder ein anderes Format wünscht. Also führen wir die folgende AuditLogAdvice ein
public class AuditLogAdvice implements MethodInterceptor {
private static final Log log = LogFactory.getLog("AuditLogger");
/**
* @see org.aopalliance.intercept.MethodInterceptor#invoke(
* org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
StringBuilder logLine = new StringBuilder();
logLine.append("Anrufe: ");
Methode m = invocation.getMethod();
logLine.append(m.getDeclaringClass().getName())
.append(".")
.append(m.getName())
.append("(");
Object[] params = invocation.getArguments();
if (params != null && params.length > 0) {
int Zähler = 0;
for (Objekt param : params) {
logLine.append(param);
Zähler++;
wenn (Zähler < params.length) {
logLine.append(", ");
}
}
}
logLine.append(")");
log.debug(logLine);
Object returnValue = invocation.proceed();
StringBuilder logReturnLine = new StringBuilder();
logReturnLine.append("Zurückgegeben: ").append(returnValue);
log.debug(logReturnLine);
return returnValue;
}
}
Dieser Hinweis kann nun auf Methodenaufrufe angewendet werden, indem Sie einen Pointcut in Ihrer Spring applicationContext.xml-Datei verwenden. Dieser Ausschnitt passt zum Beispiel zu allen Aufrufen der DAO-Klassen Ihrer Anwendung:
*DAO.*
Das war's, wir sind fertig... Aber Moment, wollte der Wartungstechniker nicht auch die IP-Adresse und den Benutzernamen protokollieren lassen? Wie können wir das tun? Zu unserem Glück verwenden wir Log4J für die Protokollierung. Log4J enthält ein Objekt namens NDC (Nested Diagnostic Context), das es uns ermöglicht, einige spezifische Informationen für einen Thread zu registrieren. Jetzt brauchen wir einen Ort, an dem wir Zugriff auf die HttpServletRequest haben. Wir wollen die IPAdresse des Benutzers nicht in jeder Struts Action / Spring-MVC Controller / Tapestry Page auf dem NDC-Stapel ablegen, sondern wir wollen dies an genau einer Stelle tun. Einer der idealen Orte ist ein javax.servlet.Filter, da jede Anfrage vom Browser des Clients diesen Filter durchläuft (wenn er in Ihrer web.xml korrekt zugeordnet ist). Lassen Sie uns also den Filter definieren:
public class AuditLogFilter implements Filter {
private static final Logger logger = Logger.getLogger("AuditLogger");
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig arg0) throws ServletException {
}
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String ndc = request.getRemoteAddr();
ndc += "/" + request.getParameter("userId");
NDC.push(ndc);
chain.doFilter(Anfrage, Antwort);
NDC.pop();
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
NDC.remove();
}
}
Jetzt sind wir wirklich fertig. Mit diesen Klassen können wir deklarativ protokollieren, was der Wartungstechniker will (IPAdresse, Benutzername, Aktionen und Ergebnisse), und zwar in einem einheitlichen Format. Und es ist einfach, sie später anzupassen! Verfasst von

Jeroen van Erp
Unsere Ideen
Weitere Blogs
Contact
Let’s discuss how we can support your journey.



