<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5940718241117156720</id><updated>2024-10-07T07:08:01.920+02:00</updated><category term="AOP"/><category term="AspectJ"/><category term="Java"/><category term="Logging"/><category term="AjLog"/><category term="Debugging"/><category term="Java5 Annotation"/><category term="refactoring"/><title type='text'>Marko&#39;s Software Development Blog</title><subtitle type='html'>Überlegungen zu Themen aus dem Reich der Softwareentwicklung im Dunstkreis von Java, Groovy, Grails und AOP.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://marko-software-developer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://marko-software-developer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marko</name><uri>http://www.blogger.com/profile/17347155121148315991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_ga0bTnCW9wA/S0Shz9ndeVI/AAAAAAAAAC0/aFhtCsEVPAo/S220/Foto+4.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5940718241117156720.post-499996982048568832</id><published>2010-02-01T15:07:00.008+01:00</published><updated>2010-05-19T13:09:10.766+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AjLog"/><category scheme="http://www.blogger.com/atom/ns#" term="AOP"/><category scheme="http://www.blogger.com/atom/ns#" term="AspectJ"/><category scheme="http://www.blogger.com/atom/ns#" term="Debugging"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Java5 Annotation"/><category scheme="http://www.blogger.com/atom/ns#" term="Logging"/><title type='text'>AOP und Logging - Teil III</title><content type='html'>&lt;div class=&quot;post-content&quot; style=&quot;font-family: inherit;&quot;&gt;Inhaltsübersicht:&lt;br /&gt;
&lt;dl&gt;&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html&quot;&gt;AOP und Logging - Teil I&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Einführung in das Thema Logging und AOP. Was ist Logging? Was ist Tracing? Motivation für einen neuen Ansatz.&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/01/aop-und-logging-teil-ii.html&quot;&gt;AOP und Logging - Teil II&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Eine Lösungsansatz ohne AspectJ.&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/02/aop-und-logging-teil-iii.html&quot;&gt;AOP und Logging - Teil III&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;b&gt;Logging vs. Debugging und eine erste einfache Lösung.&lt;/b&gt;&lt;/dd&gt; &lt;/dl&gt;&lt;/div&gt;Bevor ich eine erste Lösung für das Logging Problem mittels AspectJ präsentiere, möchte ich mich noch dem Thema Logging und Debugging beschäftigen. Auch diese werden nicht sauber getrennt: Der Adressat (oder primäre Stakeholder) von Logging- bzw. Debugginginformationen wird nicht beachtet und ausserdem wird der Logging-Level einerseits als Filter, andererseits als Gewichtung verstanden. &lt;br /&gt;
&lt;br /&gt;
In der Javawelt (wahrscheinlich nicht nur dort) ist der Zweck und der Adressat von Logging ein wenig unter die Räder gekommen, darum werde ich zu diesem Zwecke ein Schritt zurücktreten und schauen: Wie sieht es den in der Realen Welt aus? Was sind die Ursprünge des Loggings?&lt;br /&gt;
&lt;br /&gt;
Wen das nicht interessiert kann sich direkt die &lt;a href=&quot;http://www.blogger.com/post-edit.g?blogID=5940718241117156720&amp;amp;postID=499996982048568832#log_0_1&quot;&gt;Version 0.1&lt;/a&gt; anschauen. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Das Logbuch in der Schifffahrt&lt;/h3&gt;&lt;br /&gt;
Ein Kapitän der Seefahrt ist gezwungen ein &lt;a href=&quot;http://de.wikipedia.org/wiki/Logbuch&quot;&gt;Logbuch&lt;/a&gt; zu führen. Es dient dem Zweck seine &lt;b&gt;Entscheidungen&lt;/b&gt; und die &lt;b&gt;Entscheidungsgrundlagen&lt;/b&gt; zu dokumentieren. Diese können und werden bei notwendigen Untersuchen z.B. in juristischen Prozessen benutzt. Das bedeutet natürlich auch das Kapitän nicht Dinge in dieses Logbuch schreibt, wie zum Beispiel die Konsistenz seines Stuhlganges, die nicht von Bedeutung sind. (Dies hat er vielleicht in sein Tagebuch geschrieben.) Entscheidungsgrundlagen können Zustände des Schiffs sein wie z.B. Art und Menge der Beladung. Aber auch der aktuelle Kurs, Funksprüche und natürlich die Wetterlage bilden Entscheidungsgrundlagen.&lt;br /&gt;
&lt;br /&gt;
Ein weiter wichtiger Punkt ist, das nicht der Kapitän entscheidet was ins Logbuch gehört, sondern dies ist eine von Dritten verfasste Vorschrift.&lt;br /&gt;
&lt;br /&gt;
Also zusammenfassend: Ein &lt;b&gt;Logbuch&lt;/b&gt; enthält also alle &lt;b&gt;potentiell relevante Informationen&lt;/b&gt;, die nötig sind &lt;b&gt;Entscheidungen nachträglich beurteilen&lt;/b&gt; zu können.&lt;br /&gt;
&lt;br /&gt;
Was hat das mit Debugging zu tun? Natürlich nichts. Debugginginformationen werden nicht aufgezeichnet. In der Schifffahrt wird &lt;i&gt;post mortem&lt;/i&gt; beispielsweise auf die Besatzung zurückgegriffen, falls eine Untersuchung notwendig sein sollte. Also irrelevante Informationen, die ich mal als Debugginginformationen definiere, haben nichts im Logbuch verloren. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Die Entwicklung von Autos&lt;/h3&gt;&lt;br /&gt;
Nun ist Logging nur bedingt mit dem Logbuch eines Schifffahrtskapitän vergleichbar. Ein anderes passendes &lt;b&gt;Beispiel&lt;/b&gt; zur Softwareentwicklung ist die &lt;b&gt;Entwicklung von Autos&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Während der Entwicklung wird ein Auto mit einer Vielzahl an Sensoren versehen, die in ein produktiven Version entfernt werden. Übrig bleiben Sensoren und entsprechende Aufzeichnungselektronik, die den Werkstätten der Wartung des Fahrzeuges dienen oder den Besitzer auf Missstände hinweisen. Nach der Entwicklung wird der Umfang und Detaillierungsgrad der Informationen reduziert.&lt;br /&gt;
&lt;br /&gt;
Die in der Produktion übrig bleibenden Sensorik würde dem Logging und die Entwicklungssensorik dem Debugging entsprechen. Und man beachte das Bild: Sensor- und Aufzeichnungselektronik. Der Sensor entspricht den &lt;b&gt;Aufrufen&lt;/b&gt; der Logging-Library und die Aufzeichnungselektronik der eingesetzen Library.&lt;br /&gt;
&lt;br /&gt;
Wie man unschwer erkennen kann, macht es wenig Sinn alle Sensoren in der Produktion zu belassen:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;zu teuer und&lt;/li&gt;
&lt;li&gt;der fehlender Adressat.&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Während der fehlende Adressat kein schlagendes Argument ist, sind Kosten immer ein Argument. Kurz: Das Gute in der Autoentwicklung ist, das die Kosten ein disziplinierendes Element sind.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Logging und Debugging&lt;/h3&gt;&lt;br /&gt;
Dieses Disziplin haben wir in der Softwareentwicklung leider nicht. Hier wird protokolliert was das Zeug hält. Einzig der Entwickler entscheidet, was protokolliert wird und was nicht. Es ist nicht mehr wirklich ersichtlich, welche Bedeutung ein Loggingeintrag hat.&lt;br /&gt;
&lt;br /&gt;
In C/C++ kann mittels eines Compilerflags alle Debugginginformationen aus dem Code entfernt werden. In Java gibt es diese Möglichkeit nicht, das hat dazu geführt, dass in LOG4J und Co ein Level DEBUG eingeführt wurde. Der Level DEBUG hat zwei verschiedene Bedeutungen: &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Die Information richtet sich an die Entwickler. &lt;/li&gt;
&lt;li&gt;DEBUG ist eine Gewichtung der Information (mit einer Wichtigkeit unterhalb INFO).&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;Der wesentliche Punkt ist, dass durch die Markierung einer Meldung mit dem Level DEBUG diese den Adressat Entwickler hat. Die darüberliegenden Level (INFO, WARNING, ...) richten sich an die Applikationsbetreuer. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Zusammenfassung&lt;/h3&gt;&lt;br /&gt;
In der nachfolgenden Tabelle habe ich die drei Bedeutungen der Protokollierung zusammengefasst: &lt;br /&gt;
&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;thead&gt;
&lt;tr&gt;     &lt;th&gt;&lt;br /&gt;
&lt;/th&gt;     &lt;th&gt;Wem dient es?&lt;/th&gt;     &lt;th&gt;Wann?&lt;/th&gt;     &lt;th&gt;Wozu?&lt;/th&gt;   &lt;/tr&gt;
&lt;/thead&gt; &lt;tbody&gt;
&lt;tr&gt;      &lt;td&gt;Tracing&lt;/td&gt;      &lt;td&gt;Entwickler&lt;/td&gt;      &lt;td&gt;gelegentlich bei Tests&lt;/td&gt;      &lt;td&gt;Dient zur Verfolgung von Abläufen. Kann auch dem Refactoring oder Einarbeitung dienen. &lt;/td&gt;    &lt;/tr&gt;
&lt;tr&gt;      &lt;td&gt;Debugging&lt;/td&gt;      &lt;td&gt;Entwickler&lt;/td&gt;      &lt;td&gt;Unit- und Integrationstest&lt;br /&gt;
(evtl. BETA Test)&lt;/td&gt;      &lt;td&gt;Vom Entwickler eingestreute (lokale) Information dient der Fehlerbeseitigung.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;      &lt;td&gt;Logging&lt;/td&gt;      &lt;td&gt;Applikationsbetreuer&lt;/td&gt;      &lt;td&gt;Produktion&lt;/td&gt;      &lt;td&gt;Ein für den Applikationsbetreuer global relevante Informationen, die der u.a. der Überwachung der Applikation bzw. einen Moduls dient.&lt;/td&gt;     &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Obwohl Debugging sehr viel Gemeinsamkeiten mit Logging hat (zumindest in technischer Hinsicht), macht es Sinn Logging,&amp;nbsp; Debugging und natürlich auch Tracing für sich zu betrachten, da sich Adressat und Zweck unterscheiden.&lt;br /&gt;
&lt;br /&gt;
In AOP bedeutet dies, für jeden einen eigenen Aspekt bereitzustellen, auch wenn darunter die gleiche Logging-Library genutzt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;&lt;a href=&quot;http://www.blogger.com/post-edit.g?blogID=5940718241117156720&amp;amp;postID=499996982048568832&quot; name=&quot;log_0_1&quot;&gt;Logging - Version 0.1&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;
Da wir nun hoffentlich den gordischen Knoten des Loggings sprachlich und gedanklich zerschlagen haben, können wir uns einer ersten naiven Lösung des Loggings respektive Logbuches widmen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// MyLogbook Example 
package ajlog.example;

import ajlog.annotations.Info;
import ajlog.annotations.Logbook;

// #1#
@Logbook
public class MyLogbook {
  // #2#
  @Info(&quot;&#39;{}&#39; is not a tiny number ({}&amp;gt;={})&quot;)
  public static void isNotATinyNumber1(String varName, Number currValue,
      int compValue) {
  }
}&lt;/pre&gt;&lt;br /&gt;
Ein Logbuch ist eine mit Logbook Annotation (#1#) markierte Utility-Klasse, also einer Klasse ohne Konstruktor ausschliesslich aus Klassenmethoden bestehend.&lt;br /&gt;
&lt;br /&gt;
(#2#) Jede Klassenmethode, die mit einem Level markiert ist (hier exemplarisch &lt;i&gt;Info&lt;/i&gt;) entspricht einem potentiellen Logbucheintrag. Die Annotation &lt;i&gt;Info&lt;/i&gt; enthält den Ausgabetext mit den Platzhaltern &lt;i&gt;{}&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Wie man sieht gibt es keine einzige Referenz zu einer Logging-Implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Die Nutzung ist trivial. Einfach die Klassenmethoden aufrufen. Hier der Einfachheit wegen in einem JUnit-Test demonstriert:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// JUnit-Test
package ajlog.example;

import junit.framework.TestCase;

public class MyLogbookTest extends TestCase {
  public void testAnnontationBasedLogging() {
    MyLogbook.isNotATinyNumber1(&quot;any var&quot;, new Long(100), 99);
  }
}&lt;/pre&gt;&lt;br /&gt;
Die zugehörige Ausgabe könnte dann wie folgt aussehen.&lt;br /&gt;
&lt;pre&gt;23:39:34.884 [main] INFO  ajlog.example.MyLogbook - &#39;any var&#39; is not a tiny number (100&amp;gt;=99)&lt;/pre&gt;&lt;br /&gt;
Ein entsprechender Aspekt könnte folgendermassen aussehen: &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;package ajlog.aspects.simple;

// #1#
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ajlog.annotations.Info;
import ajlog.annotations.Logbook;

public aspect LoggingAspect {
  // &lt;span style=&quot;background-color: yellow;&quot;&gt;#1#&lt;/span&gt; The Info pointcut defintion
  &lt;span style=&quot;background-color: yellow;&quot;&gt;pointcut infoMethodPc&lt;/span&gt;(&lt;b&gt;Info&lt;/b&gt; &lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;) :
     // #4# any public void class method within @Logbook annotated class
     execution(public static void (@&lt;b&gt;Logbook&lt;/b&gt; *).*(..) ) 
     // #5# Method annotation Info
     &amp;amp;&amp;amp; @annotation(&lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;);
     

  // &lt;span style=&quot;background-color: lime;&quot;&gt;#2#&lt;/span&gt; the advice header
  &lt;span style=&quot;background-color: lime;&quot;&gt;before&lt;/span&gt;(&lt;b&gt;Info&lt;/b&gt; &lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;) : &lt;span style=&quot;background-color: lime;&quot;&gt;infoMethodPc&lt;/span&gt;(&lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;) {
    // &lt;span style=&quot;background-color: red;&quot;&gt;#3# the advice body&lt;/span&gt;

    // #7# resolve Logger instance
    Logger logger = LoggerFactory.getLogger(thisJoinPointStaticPart
        .getSignature().getDeclaringType());

    if (logger.isInfoEnabled()) {
      // #6# Perform the logging using @Info.value() 
      logger.info(&lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;.value(), thisJoinPoint.getArgs());
    }
  }
}&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein Aspekt ist ein Bündelung von drei Dingen:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;i&gt;(#1#) pointcut definition&lt;/i&gt;. &lt;b style=&quot;background-color: yellow;&quot;&gt;Wo&lt;/b&gt; soll die Funktionalität eingebunden werden?&lt;/li&gt;
&lt;li&gt;(#2#) Der &lt;i&gt;advice&lt;/i&gt; &lt;i&gt;header&lt;/i&gt; gibt an &lt;b style=&quot;background-color: lime; color: black;&quot;&gt;Wann&lt;/b&gt; (&lt;i&gt;before, after&lt;/i&gt;) und eventuell auch Ob (&lt;i&gt;around&lt;/i&gt;) die Funktionalität ausgeführt werden soll.&lt;/li&gt;
&lt;li&gt;(#3#) Der &lt;i&gt;advice body&lt;/i&gt; legt fest &lt;b style=&quot;background-color: red;&quot;&gt;Was&lt;/b&gt; ausgeführt werden soll. Der &lt;i&gt;advice body&lt;/i&gt; enthält die Funktionalität des Advices.&lt;/li&gt;
&lt;/ol&gt;In einem Satz kann man den LoggingAspect wie folgt ausdrücken: &lt;span style=&quot;background-color: yellow; color: black;&quot;&gt;An jeder mit &lt;/span&gt;&lt;i style=&quot;background-color: yellow; color: black;&quot;&gt;Logbook&lt;/i&gt; &lt;span style=&quot;background-color: yellow;&quot;&gt;markierten Utilityklasse&lt;/span&gt; &lt;span style=&quot;background-color: red;&quot;&gt;führe&lt;/span&gt; &lt;span style=&quot;background-color: lime;&quot;&gt;vor &lt;span style=&quot;background-color: yellow;&quot;&gt;der Ausführung&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;background-color: yellow;&quot;&gt;jede mit &lt;/span&gt;&lt;i style=&quot;background-color: yellow;&quot;&gt;Info&lt;/i&gt;&lt;span style=&quot;background-color: yellow;&quot;&gt; markierten öffentlichen Klassenmethode (ohne Rückgabewert)&lt;/span&gt; &lt;span style=&quot;background-color: red;&quot;&gt;ein Logging mittels &lt;/span&gt;&lt;a href=&quot;http://www.slf4j.org/&quot;&gt;SLF4J&lt;/a&gt;&lt;span style=&quot;background-color: red;&quot;&gt; durch&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
Der benannte &lt;i&gt;pointcut&lt;/i&gt; &lt;i&gt;infoMethodPc&lt;/i&gt; (#1#) setzt sich zusammen aus:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;(#4#)&amp;nbsp; Ausführung (&lt;i&gt;execution&lt;/i&gt;) von öffentlichen (&lt;i&gt;public&lt;/i&gt;) Klassenmethoden (&lt;i&gt;static&lt;/i&gt;) ohne Rückgabewert (&lt;i&gt;void&lt;/i&gt;) die Teil einer mit &lt;i&gt;@Logbook&lt;/i&gt; markierten Klassen sind&amp;nbsp;&amp;nbsp; &lt;i&gt;&lt;b&gt;und&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;(#5#) die Methode ist mit &lt;i&gt;@Info&lt;/i&gt; markiert.&lt;/li&gt;
&lt;/ul&gt;Mittels &lt;i&gt;infoMethodePc(Info &lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;): /*... */ &amp;amp;&amp;amp; @annotation(&lt;span style=&quot;color: red;&quot;&gt;level&lt;/span&gt;)&lt;/i&gt;&amp;nbsp; kann im &lt;i&gt;advice body&lt;/i&gt; (#3#) auf den Logging Textvorlage (&lt;i&gt;level.value()&lt;/i&gt; #6#) zugegriffen werden. (Das Format des in &lt;i&gt;@Info&lt;/i&gt; hinterlegten Textes entspricht dem von SLF4J&#39;s &lt;a href=&quot;http://www.slf4j.org/api/org/slf4j/helpers/MessageFormatter.html&quot;&gt;MessageFormatter&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Mittels des Schlüsselwortes &lt;i&gt;before&lt;/i&gt; wird im &lt;i&gt;advice header&lt;/i&gt; (#2#) festgelegt, das &lt;b style=&quot;background-color: lime;&quot;&gt;vor&lt;/b&gt; dem &lt;i&gt;pointcut&lt;/i&gt; &lt;i&gt;infoMethodPc&lt;/i&gt; der nachfolgende &lt;i&gt;advice body&lt;/i&gt; ausgeführt wird. D.h. insbesondere werden die vom &lt;i&gt;pointcut&lt;/i&gt; selektierten Methoden immer ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Der &lt;i&gt;advice body&lt;/i&gt; (#3#) ist hingegen sehr einfach und bedarf eigentlich keiner Erklärung, sondern entspricht bis auf (#7#) der Erwartung: Es ist allerdings unschön und auch nicht sonderlich der Performance dienlich, bei jedem Aufruf erneut die &lt;i&gt;Logger&lt;/i&gt; Instanz holen zu müssen. (Aber hier geht es erst einmal um das Prinzip und das wird einer späteren Version verbessert werden.) Schön ist, dass man auf die aktuellen Variablen direkt zugreifen kann, da diese im &lt;i&gt;JointPoint Objekt&lt;/i&gt; als Object-Array abgelegt sind (&lt;i&gt;thisJointPoint.getArgs()&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
Abschliessend, der Vollständigkeit wegen, die beiden Annotations:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// Logbook annotation 
package ajlog.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited @Documented
public @interface &lt;b&gt;Logbook&lt;/b&gt; {
}&lt;/pre&gt;&lt;br /&gt;
und&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;// Info annotation
package ajlog.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface &lt;b&gt;Info&lt;/b&gt; {
  String value() default &quot;&quot;;
}&lt;/pre&gt;&lt;br /&gt;
Natürlich ist dies erst eine naive Lösung, aber es zeigt die wichtigsten Elemente:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Die Logbook-Annotation und die&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Level-Annotation(s) mit einer Textvorlage. Exemplarisch habe ich dies für den Level Info aufgezeigt. Weitere Levels können analog zu Info bereitgestellt werden.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;br /&gt;
Was haben wir erreicht?&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Allein die Annotations bilden die &quot;Schnittstelle&quot;. Man kann es sehr einfach erweitern ohne bestehende Nutzungen zu beeinträchtigen (mittels sinnvollen Defaults).&lt;/li&gt;
&lt;li&gt;Die Entscheidung für eine Logging-Library kann auf einen sehr späten Zeitpunkt verlagert werden. Zur Not sogar auf den Auslieferungszeitpunkt der fertigen Software.&lt;/li&gt;
&lt;li&gt;Wenn kein Logging erwünscht wird, kann dieses komplett entfernt werden.&lt;/li&gt;
&lt;li&gt;Durch die Festlegung von Annotations ist es möglich eine ganz andere Implementation zu hinterlegen, ohne das die Entwicklung davon betroffen ist. Sogar die Entscheidung eine gänzlich neue Logging-Library zu entwickeln ist möglich.&lt;/li&gt;
&lt;li&gt;Keine Logging-Instanz mehr in den Klassen.&lt;/li&gt;
&lt;li&gt;Es können Statistiken über die Logeinträge geführt werden, da diese eindeutige Namen haben.&lt;/li&gt;
&lt;li&gt;An den Methoden können weitere Aspekte greifen. &lt;/li&gt;
&lt;/ul&gt;Und einige interessante Möglichkeiten möchte ich für Entwicklern von Libraries, Frameworks und Co unterstreichen:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Der Nutzer entscheidet welche Logging-Library eingesetzt wird. (Auch wenn dies mit SLF4J bzw. Jakarta Commons Logging (JCL) jetzt schon möglich ist.)&lt;/li&gt;
&lt;li&gt;Noch wichtiger: Die Logbook-Instanzen sind mittels Javadoc &lt;b&gt;dokumentiert&lt;/b&gt; und würden für mich zur Auslieferungsdokumentation gehören. D.h. die Entwickler von Libraries müssen sich Gedanken dazumachen, wozu ein Logeintrag vorhanden ist und was für den Anwendungsentwickler bzw. Anwendungsbetreuer daraus abzuleiten ist! Das entspricht der Diskussion die ich oben geführt habe.&lt;/li&gt;
&lt;li&gt;Da Level und Texte anpassbar sind (jetzt noch nicht implementiert), hat der Nutzer die Möglichkeit das Logging &lt;b&gt;an seine Bedürfnisse&lt;/b&gt; hin &lt;b&gt;auszupassen&lt;/b&gt; ohne auf den &lt;i&gt;source code&lt;/i&gt; zurückgreifen zu müssen.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Was ist noch verbesserungswürdig?&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Das Format der Textvorlage (&lt;i&gt;@Info.value()&lt;/i&gt;) ist an SLF4J gebunden. &lt;/li&gt;
&lt;li&gt;Der Zugriff auf die Logging-Instanz innerhalb des Advices ist nicht besonders hübsch. Mit ein paar Tricks ist es möglich die Logging-Instanz genau einmal zu ermitteln.&lt;/li&gt;
&lt;li&gt;Zwei Versprechen sind noch nicht eingelöst worden: Der Level und der Text kann nicht revidiert werden ohne eine erneutes Build.&lt;/li&gt;
&lt;li&gt;Es ist noch recht mühsam die Logging-Library zu ersetzen. Das geht (noch) besser.&lt;/li&gt;
&lt;li&gt;Internationalisierung.&lt;/li&gt;
&lt;li&gt;Es gibt eine nette Lösung für Bedingte Logbucheinträge mittels AspectJ (&lt;i&gt;conditional logging&lt;/i&gt;).&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Aber diese Verbesserungen sind das Thema meines nächsten Beitrages.</content><link rel='replies' type='application/atom+xml' href='http://marko-software-developer.blogspot.com/feeds/499996982048568832/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://marko-software-developer.blogspot.com/2010/02/aop-und-logging-teil-iii.html#comment-form' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/499996982048568832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/499996982048568832'/><link rel='alternate' type='text/html' href='http://marko-software-developer.blogspot.com/2010/02/aop-und-logging-teil-iii.html' title='AOP und Logging - Teil III'/><author><name>Marko</name><uri>http://www.blogger.com/profile/17347155121148315991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_ga0bTnCW9wA/S0Shz9ndeVI/AAAAAAAAAC0/aFhtCsEVPAo/S220/Foto+4.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5940718241117156720.post-4493869150581007409</id><published>2010-01-02T17:10:00.026+01:00</published><updated>2010-02-11T15:52:51.321+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AOP"/><category scheme="http://www.blogger.com/atom/ns#" term="AspectJ"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Logging"/><category scheme="http://www.blogger.com/atom/ns#" term="refactoring"/><title type='text'>AOP und Logging - Teil II</title><content type='html'>&lt;div class=&quot;post-content&quot; style=&quot;font-family: inherit;&quot;&gt;Inhaltsübersicht:&lt;br /&gt;
&lt;dl&gt;&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html&quot;&gt;AOP und Logging - Teil I&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Einführung in das Thema Logging und AOP. Was ist Logging? Was ist Tracing? Motivation für einen neuen Ansatz.&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/01/aop-und-logging-teil-ii.html&quot;&gt;AOP und Logging - Teil II&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;b&gt;Eine Lösungsansatz ohne AspectJ.&lt;/b&gt;&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/02/aop-und-logging-teil-iii.html&quot;&gt;AOP und Logging - Teil III&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Logging vs. Debugging und eine erste einfache Lösung.&lt;/dd&gt; &lt;/dl&gt;&lt;/div&gt;&lt;div&gt;Im letzten &lt;a href=&quot;http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html&quot;&gt;Beitrag&lt;/a&gt; habe ich versprochen eine Lösung für das Logging mittels AOP bzw. AspectJ zu präsentieren. In einem ersten Schritt werde ich erst einmal eine Lösung ohne AspectJ präsentieren und dann werde ich diese Lösung in späteren Beiträgen weiter verfeinern.&lt;br /&gt;
&lt;br /&gt;
Zunächst werden alle identifizierten Tracing-Einträge des &lt;a href=&quot;http://www.blogger.com/2009/12/aop-und-logging.html#example_1&quot;&gt;Beispiels&lt;/a&gt; entfernt, da diese relativ einfach mit einem Aspect behandelt werden können. Dann sieht die Klasse wie folgt aus:&lt;/div&gt;&lt;pre&gt;&lt;span style=&quot;font-size: small;&quot;&gt;package ajlog.example;

// #1#
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class MyClass {
  // #2#
  private static Logger logger = LoggerFactory.getLogger(MyClass.class);

  public Object doSomethingWith2Objects(Object a, Object b) {

    try {
      Number ai = (Number) a;
      Number bi = (Number) b;

      if (ai.intValue() &amp;gt; 100)
        logger.warn(&quot;a is not a tiny number&quot;); // #3#

      if (bi.intValue() &amp;gt; 100)
        logger.warn(&quot;b is not a tiny number&quot;); // #3#

      return new Long(ai.intValue() + bi.longValue());
    }
    catch (RuntimeException ex) {
    }

    return null;
  }
}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
Nachdem die Tracing-Einträge entfernt wurden, sieht das ganze schon deutlich übersichtlicher und wartbarer aus. Unschön ist, dass es nach wie vor eine explizite Abhängigkeit zur Logging-Library und der Erzeugung einer Logging-Instanz habe (#1# und #2#). Zudem ist die Bedeutung, die hinter dem Loggingaufruf&amp;nbsp; (#3#) steht, nicht repräsentiert. Der nächste Schritt ist also: Den Logging-Einträgen eine Bedeutung geben. Das könnte dann wie folgt aussehen:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;package ajlog.example;

public class MyClass {

  public Object doSomethingWith2Objects(Object a, Object b) {

    try {
      Number ai = (Number) a;
      Number bi = (Number) b;

      if (ai.intValue() &amp;gt; 100)
        MyLog.isNotATinyNumber(&quot;a&quot;, ai, 100);

      if (bi.intValue() &amp;gt; 100)
        MyLog.isNotATinyNumber(&quot;b&quot;, bi, 100);

      return new Long(ai.intValue() + bi.longValue());
    }
    catch (RuntimeException ex) {
    }

    return null;
  }

}
&lt;/pre&gt;&lt;br /&gt;
und die dazugehörige Implementation von &lt;i&gt;MyLog ...&lt;br /&gt;
&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;package ajlog.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyLog {
  // #1# Only drawback : It&#39;s MyLog not MyClass the logger belongs to.
  private static Logger logger = LoggerFactory.getLogger(MyLog.class);

  public static void isNotATinyNumber(
         String varName, Number currValue, int compValue
      )
  {
    if (logger.isWarnEnabled()) {
      logger.warn(&quot;{} is not a tiny number ({} &amp;gt; {})&quot;,
          new Object[]{
              varName, currValue, new Integer(compValue)
          }
      );
    }
  }
}

&lt;/pre&gt;&lt;br /&gt;
Was haben wir dadurch dieses &lt;i&gt;refactoring &lt;/i&gt;erreicht?&lt;br /&gt;
&lt;br /&gt;
Zunächst mal das Offensichtliche: &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Es wird keine Logging-Instanz mehr zur Klasse &lt;i&gt;MyClass&lt;/i&gt; hinzugefügt und auch die &lt;i&gt;imports&lt;/i&gt; fehlen. Die direkte Abhängigkeit ist aufgelöst worden.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Es gibt nur noch eine (Klassen-)Methode &lt;i&gt;isNotATinyNumber()&lt;/i&gt;. D.h. es gibt nur noch eine (Logging-)Methode, egal ob dies Variable &quot;a&quot; oder &quot;b&quot; betrifft.&lt;/li&gt;
&lt;/ul&gt;Das wichtigste an dieser Änderung ist aber folgendes:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Aus &lt;b&gt;Logging-Eintrag ist eine bedeutungstragende Einheit&lt;/b&gt;, eine Logging-Methode geworden, die einer Logging-Klasse zusammengefasst werden können. &lt;/li&gt;
&lt;li&gt;Die erzeugte Logging-Methode ist &lt;b&gt;wiederverwendbar&lt;/b&gt;. &lt;/li&gt;
&lt;li&gt; Das &lt;b&gt;Logging kann systematisiert&lt;/b&gt; werden.&lt;/li&gt;
&lt;li&gt;Die Logging Library ist (relativ schnell) austauschbar.&lt;/li&gt;
&lt;li&gt;Es kann eine Cross Referenz Liste erstellt werden.&lt;/li&gt;
&lt;li&gt;Mittels JavaDoc kann das gesamte Logging dokumentiert werden.&lt;/li&gt;
&lt;li&gt;Der Level lässt sich ändern.&lt;/li&gt;
&lt;li&gt;Der Text lässt sich ändern.&lt;/li&gt;
&lt;/ul&gt;Und noch ein Sahnehäubchen:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt; Diese Art von Logging kann von einer &lt;b&gt;IDE&lt;/b&gt; besser &lt;b&gt;unterstützt&lt;/b&gt; werden: Die Logging-Klasse (&lt;i&gt;MyLog&lt;/i&gt;) und die Logging-Methode (&lt;i&gt;isNotATinyNumber&lt;/i&gt;) mit all ihren Parametern wird&amp;nbsp; mehr oder weniger auf Knopfdruck erzeugt, bzw. bestehende Klassen und Methoden werden aufgelistet.&lt;/li&gt;
&lt;li&gt;Eine einfache Art der Systematik: Man kann zwischen globalen (relevanten) und lokalen (weniger relevanten) Logging unterscheiden. Man nutzt einfach &lt;i&gt;public static&lt;/i&gt; und &lt;i&gt;(package) static&lt;/i&gt; zur Markierung der Logging-Methoden, also eine Klassenmethode ohne jeden Zugriffsqualifizierer (public, protected, private). Leztere wären dann Debug-Ausgaben. Erstere wären Info-, Warning-, Error- und Fatal-Ausgaben.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;Kurz: Dieses &lt;i&gt;refactoring&lt;/i&gt; müsste schon an sich sinnvoll, unabhängig davon, ob man AspectJ einsetzen will oder nicht.&lt;br /&gt;
&lt;br /&gt;
Ein &quot;&lt;i&gt;&lt;b&gt;Nachteil&lt;/b&gt;&lt;/i&gt;&quot; (#1#) will nicht verschweigen: In der Logging-Ausgabe wird nicht protokoliert, wer die Quelle des Log-Eintrags war, also der Aufrufer von &lt;i&gt;MyLog&lt;/i&gt;.&lt;i&gt;isNotATinyNumber(). &lt;/i&gt;Aber dies gehört meiner Meinung nach nur in den Bereich eines Log-Eintrages auf dem Level des Debugging und ist ein zu verkraftender Nachteil (und lässt sich mit einem etwas einmalig erhöhten Aufwand sogar eliminieren). &lt;br /&gt;
&lt;br /&gt;
Natürlich bin ich noch am Ziel meiner Träume, aber der erste grosse Schritt ist vollzogen.&amp;nbsp;&lt;b&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;background-color: white; color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-2&quot; style=&quot;color: black;&quot;&gt;AspectJ&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt; hat nun Angriffspunkte&lt;/b&gt;: das Ausführen (&lt;i&gt;execution&lt;/i&gt;) oder Aufrufen (&lt;i&gt;call&lt;/i&gt;) von &lt;i&gt;MyLog&lt;/i&gt;.&lt;i&gt;isNotATinyNumber(). &lt;/i&gt;Für &lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;background-color: white; color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-3&quot; style=&quot;color: black;&quot;&gt;AspectJ&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt;&lt;/layer&gt; sind dies zwei mögliche sogenannte &lt;a href=&quot;http://www.eclipse.org/aspectj/doc/released/progguide/examples-basic.html#examples-joinPoints&quot;&gt;joint points&lt;/a&gt;, die mit einem &lt;a href=&quot;http://www.eclipse.org/aspectj/doc/released/progguide/starting-aspectj.html#pointcuts&quot;&gt;poincut&lt;/a&gt; Designator selektierbar sind.&lt;br /&gt;
&lt;br /&gt;
Was fehlt mir zu meinem Glück?&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Ich würde gerne das ganze auch ausführen können, ohne das ich eine Logging Library im &lt;i&gt;classpath&lt;/i&gt; habe.&lt;/li&gt;
&lt;li&gt;Ich würde gerne Texte und Level anpassen können ohne neu zu builden.&lt;/li&gt;
&lt;li&gt;Die versprochene Internationalisierung fehlt auch noch. &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Ich will die Logging Library schmerzlos austauschen können. D.h. indem ich ein JAR im &lt;i&gt;classpath &lt;/i&gt;austausche&lt;i&gt;.&lt;br /&gt;
&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Ich mache es spannend und werde ein ersten &lt;i&gt;naiven&lt;/i&gt; Aspekt im Teil III entwickeln ;-)</content><link rel='replies' type='application/atom+xml' href='http://marko-software-developer.blogspot.com/feeds/4493869150581007409/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://marko-software-developer.blogspot.com/2010/01/aop-und-logging-teil-ii.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/4493869150581007409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/4493869150581007409'/><link rel='alternate' type='text/html' href='http://marko-software-developer.blogspot.com/2010/01/aop-und-logging-teil-ii.html' title='AOP und Logging - Teil II'/><author><name>Marko</name><uri>http://www.blogger.com/profile/17347155121148315991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_ga0bTnCW9wA/S0Shz9ndeVI/AAAAAAAAAC0/aFhtCsEVPAo/S220/Foto+4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5940718241117156720.post-3991580374447012326</id><published>2009-12-30T13:28:00.038+01:00</published><updated>2010-02-11T15:53:19.118+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AOP"/><category scheme="http://www.blogger.com/atom/ns#" term="AspectJ"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Logging"/><title type='text'>AOP und Logging - Teil I</title><content type='html'>&lt;div class=&quot;post-content&quot; style=&quot;font-family: inherit;&quot;&gt;Inhaltsübersicht:&lt;br /&gt;
&lt;dl&gt;&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html&quot;&gt;AOP und Logging - Teil I&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;b&gt;Einführung in das Thema Logging und AOP. Was ist Logging? Was ist Tracing? Motivation für einen neuen Ansatz.&lt;/b&gt;&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/01/aop-und-logging-teil-ii.html&quot;&gt;AOP und Logging - Teil II&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Eine Lösungsansatz ohne AspectJ.&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&quot;http://marko-software-developer.blogspot.com/2010/02/aop-und-logging-teil-iii.html&quot;&gt;AOP und Logging - Teil III&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;Logging vs. Debugging und eine erste einfache Lösung.&lt;/dd&gt; &lt;/dl&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;In meinem ersten Beiträgen möchte ich mit einem meiner Lieblingsthemen beschäftigen: Aspect Oriented Programming (&lt;a href=&quot;http://de.wikipedia.org/wiki/Aspektorientierte_Programmierung&quot;&gt;AOP&lt;/a&gt;). &lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;AOP hat längst den Mainstream der (Java) Entwickler erreicht, ohne das die meisten Aspekte selber entwickeln (das muss nicht unbedingt schlecht sein): Man nutzt AOP im Rahmen eines Frameworks wie z.B. &lt;a href=&quot;http://www.springsource.org/&quot;&gt;Spring&lt;/a&gt; ohne jedoch eigene Aspekte zu entwickeln. Dabei will AOP ein Problem lösen, das jeden Entwickler früher oder später (be-)trifft: &lt;a href=&quot;http://en.wikipedia.org/wiki/Separation_of_concerns&quot; style=&quot;font-style: italic;&quot;&gt;Seperation of Concerns&lt;/a&gt;. Wenn eine neue Applikation erstellt wird, dann wird zunächst von den Kernfunktionalitäten (core concerns) gesprochen, den dahinter steht die Motivation die Applikation überhaupt zu erstellen. Aber leider ist dies nur die halbe Wahrheit ist. Die Kernfunktionalität ist vielleicht hinreichend für einen Prototyp, aber für eine lieferbare, wartbare Applikation, die den Entwickler ruhig schlafen lässt, ist dies nicht ausreichend. Ernsthafte Softwareentwicklung muss sich um die &lt;a href=&quot;http://de.wikipedia.org/wiki/Cross-Cutting_Concern&quot; style=&quot;font-style: italic;&quot;&gt;cross-cutting concerns&lt;/a&gt; kümmern, wie zum Beispiel die allseits bekannten &lt;a href=&quot;http://de.wikipedia.org/wiki/Anforderung_%28Informatik%29#Klassifikation_nichtfunktionaler_Anforderungen&quot;&gt;nicht funktionale Anforderungen&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Das bekanntesten und damit am häufigsten genannten &lt;span style=&quot;font-style: italic;&quot;&gt;cross-cutting concerns&lt;/span&gt; sind &lt;b&gt;Tracing und Logging&lt;/b&gt;.&amp;nbsp; Die&amp;nbsp; Anwendung dieser Aspekte durchziehen die meisten Applikationen. Diese beiden Aspekte sind so essentiell, das sie auch zur &lt;a href=&quot;http://de.wikipedia.org/wiki/Aspektorientierte_Programmierung#Motivation&quot;&gt;Motivation&lt;/a&gt; und als &lt;a href=&quot;http://www.developer.com/java/other/article.php/3109831/Simplify-your-logging-with-AspectJ.htm&quot;&gt;Standardbeispiele&lt;/a&gt; von AOP herhalten müssen. &lt;b&gt;Leider hat Logging als Beispiel für AOP einen Webfehler&lt;/b&gt;: Logging und Tracing werden nicht sauber unterschieden.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;post-remark&quot; style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Eine Anmerkung zum Thema Logging&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;/b&gt;Immer wieder wird AOP mit Logging erklärt. Warum schon wieder Logging? Gibt es nichts anderes auf dieser Welt wozu AOP dienen kann? Und ob. Aber Logging (das meist mit Tracing verwechselt wird) verunstaltet wie kein anderer Aspekt unseren Code. Ausserdem will ich zeigen, das hinter dem Thema Logging mehr steckt als man auf den ersten Blick erkennen kann.&lt;br /&gt;
Ich habe also eine Bitte an euch: Geduld. Am Ende soll neben eine verbessertes Verständnis von Logging und AspectJ, eine kleine aber feine AspectJ-Library entstehen: &lt;b&gt;ajlog&lt;/b&gt;.&lt;br /&gt;
&lt;b&gt; &lt;/b&gt;&lt;br /&gt;
Wozu AOP noch taugt ausser Tracing und Logging, werde ich in weiteren Artikeln behandeln.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Wenn eine Library wie &lt;a href=&quot;http://logging.apache.org/log4j/index.html&quot;&gt;Log4J&lt;/a&gt; oder &lt;a href=&quot;http://www.slf4j.org/&quot;&gt;SLF4J&lt;/a&gt; eingesetzt wird, dann ist Tracing ein &lt;a href=&quot;http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html#TRACE&quot;&gt;Level&lt;/a&gt;, der alle anderen Levels (DEBUG, INFO, ...) enthält. Aus Sicht der Levelhierachie ist somit ein Loggingeintrag ein verfolgbarer (traceable) Eintrag. Aus technischer Sicht ist dies auch richtig. Macht dies aber auch tatsächlich Sinn?&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;Schauen wir uns mal ein (zugegeben künstliches) &lt;a href=&quot;http://www.blogger.com/post-edit.g?blogID=5940718241117156720&amp;amp;postID=3991580374447012326&quot; name=&quot;example_1&quot;&gt;Beispiel&lt;/a&gt; an:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;pre&gt;package ajlog.example;

// #7#
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class MyClass {
// #7# 
private static Logger logger = LoggerFactory.getLogger(MyClass.class);

  public Object doSomethingWith2Objects(Object a, Object b) {
    // #1#  Tracing : Enter method
    logger.trace(&quot;Enter doSomethingWith2Objects({},{})&quot;, a, b);

    try {
      // #5# : throws Exception
      Number ai = (Number) a;
      Number bi = (Number) b;

      if (ai.intValue() &amp;gt; 100)
        logger.warn(&quot;a is not a tiny number&quot;); // #6#

      if (bi.intValue() &amp;gt; 100)
        logger.warn(&quot;b is not a tiny number&quot;); // #6#

      Number result = new Long(ai.intValue() + bi.longValue());

      // #2#  Tracing : Leave method
      logger.trace(&quot;Leave doSomethingWith2Objects(...) -&amp;gt; {}&quot;, result);

      return result;
    }
    catch (RuntimeException ex) {
      // #4#  Tracing? : Report unexpected behaviour
      logger.error(&quot;a or b is not a number&quot;, ex);
    }

    // #3#  Tracing : Leave method
    logger.trace(&quot;Leave doSomethingWith2Objects(...) -&amp;gt; null&quot;);
    return null;
  }
}
&lt;/pre&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;#1#, #2# und #3# sind unbestreitbar Tracing-Einträge und dies nicht wegen des Levels. Über #4# lässt sich streiten, da hier nicht nur die Exception ausgegeben wird, sondern auch in den Verlauf eingegriffen wird. Würde die Exception anschliessend wieder geworfen wäre dies IMHO ein Tracing (trotz des Levels ERROR). Diese Tracingmeldung kann durch eine potentielle Exception bei #5# ausgelöst werden.&lt;br /&gt;
Bleiben die beiden &lt;span style=&quot;font-style: italic;&quot;&gt;logger.warn()&lt;/span&gt; Einträge (#6#): Dies sind Logging-Einträge, wie sie Entwickler immer wieder in den Code einstreuen, die dem Applikationsbetreuer wertvolle Informationen während der Laufzeit oder &lt;span style=&quot;font-style: italic;&quot;&gt;post mortem&lt;/span&gt; hinterlässt - auch wenn sie in diesem Fall sehr technisch erscheinen.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Die Tracing-Einträge lassen sich sehr einfach mit &lt;a href=&quot;http://www.eclipse.org/aspectj/&quot; style=&quot;background-color: white;&quot;&gt;&lt;layer id=&quot;google-toolbar-hilite-0&quot; style=&quot;color: black;&quot;&gt;AspectJ&lt;/layer&gt;&lt;/a&gt; behandeln, da sie sich mit einem &lt;a href=&quot;http://www.eclipse.org/aspectj/doc/released/progguide/starting-aspectj.html#pointcuts&quot;&gt;Pointcut&lt;/a&gt; Definition (z.B. &lt;i&gt;pointcut traceable() : execution(public * *.*(..)&lt;/i&gt;) erreichen lassen. Für die beiden Logging-Einträge gilt dies nicht. Warum ist dies so?&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt; &lt;br /&gt;
Sie haben eine Bedeutung, die nicht durch den Aufruf von &lt;span style=&quot;font-style: italic;&quot;&gt;logger.warn()&lt;/span&gt; abgedeckt ist. Ihre Expressivität erhalten sie durch den Logging Inhalt (&quot;&lt;span style=&quot;font-style: italic;&quot;&gt;a is not a tiny number&lt;/span&gt;&quot;) und der ist für Code Weaver (so) nicht erreichbar. Eine mögliche Lösung wäre, das man ein zusätzliche Methode einführt, dann wäre diese wieder verfolgbar, aber dann wäre Logging identisch mit Tracing und man hätte Schwierigkeiten den Level gescheit zu setzen.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;Natürlich würde kein Entwickler, der bei Sinnen ist, auf so wenig Codezeilen soviele Tracing- respektive Logging-Einträge vornehmen - es ist ein künstliches Beispiel. Aber selbst wenn man die offensichtlichen Tracing-Einträge entfernt, verbleibt die direkte Abhängigkeit zur Logging-Library (#7#) und die Logging-Einträge. Und diese müssen bleiben! Was nicht bleiben muss ist die direkte Abhängigkeit zur Logging-Library.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&amp;nbsp; &lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt; &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
Zusammenfassend:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;ul style=&quot;font-family: inherit;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging als Motivation für AOP ist in Ordnung, den unbestreitbar handelt es sich um ein cross-cutting concern. Aber Logging ist aber kein einfach zu lösendes Beispiel für den Einsatz von AOP.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;ul style=&quot;font-family: inherit;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;LOG4J und der legitime Nachfolger SLF4J (bzw. &lt;a href=&quot;http://logback.qos.ch/&quot;&gt;logback&lt;/a&gt;) sind grossartige Software. Aber leider reduzieren sie Logging auf den technischen Aspekt. Sie sind (leider?) so erfolgreich, das sie über die Welt von Java hinaus Einfluss hatten und haben.&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;ul style=&quot;font-family: inherit;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Auch das automatische Induzieren von Logging-Instanzen (wie z.B. in &lt;a href=&quot;http://grails.org/&quot;&gt;Grails&lt;/a&gt;) löst dieses Problem nicht. Sie spart nur Tipparbeit, mit dem kleinen Haken, dass man sich an den Namen der Logging-Instanz erinnern muss.&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Kurz: Es bedarf einer besseren Lösung. Aber einer Lösung, die auf bestehenden aufsetzt. &lt;/span&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt; &lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;&lt;br /&gt;
Im den nächsten Beiträgen werde ich eine elegante Lösung Logging mit AOP &lt;b&gt;erarbeiten&lt;/b&gt;, die einige&amp;nbsp; Vorteile in sich trägt:&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;ul style=&quot;font-family: inherit;&quot;&gt;&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging Einträge lassen sich sammeln&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging Einträge lassen sich klassifizieren (unabhängig vom Level)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging Einträge lassen sich systematisieren und sind nicht mehr von den persönlichen Vorlieben des Entwicklers abhängig&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Möglichkeit der Internationalisierung&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Wiederverwendung von Logging Einträgen&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging Texte lassen sich ändern (ohne Rebuild)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Logging Level lassen sich ändern (ohne Rebuild)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Die Entscheidung für eine Logging Library kann spät getroffen oder sogar revidiert &lt;/span&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;werden&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Cross Referenzen können gebildet werden &lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: 100%;&quot;&gt;Unittest ohne Logging möglich&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://marko-software-developer.blogspot.com/feeds/3991580374447012326/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/3991580374447012326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5940718241117156720/posts/default/3991580374447012326'/><link rel='alternate' type='text/html' href='http://marko-software-developer.blogspot.com/2009/12/aop-und-logging.html' title='AOP und Logging - Teil I'/><author><name>Marko</name><uri>http://www.blogger.com/profile/17347155121148315991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_ga0bTnCW9wA/S0Shz9ndeVI/AAAAAAAAAC0/aFhtCsEVPAo/S220/Foto+4.jpg'/></author><thr:total>0</thr:total></entry></feed>