2010-06-22 3 views
5

Ich habe einige Java-Code, den ich mit Protokollmeldungen für Debugging-Zwecke instrumentieren möchte. Der endgültige (kompilierte) Produktionscode sollte jedoch keine Protokollierung enthalten, da dies die Ausführungszeit verlangsamen würde. Gibt es in Java eine Möglichkeit, einen Logger zur Kompilierzeit zu deaktivieren?Deaktivieren Sie die Protokollierung in Java zur Kompilierzeit

Ich habe keine Angst vor dem Fußabdruck eine Überprüfung in der Protokollmethode eines Laufzeit-aktivierten/deaktivierten Loggers hinzufügen würde.

if (logging==enabled) {// do logging} 

Aber ich möchte Parameter Aufbau wie die folgende in meiner Produktionscode vermeiden:

Logger.log("undefined state" + state + " @ " + new Date()); 

Ich bin mit Suns Java-Compiler.

Antwort

0

Ich kenne keine Compiler-Funktionalität zu diesem Thema, aber Sie könnten auch ein Build-Skript erstellen. Dieses Skript kopiert die ursprünglichen (Debug-) Java-Quelldateien, kopiert sie an einen temporären Speicherort, entfernt die Protokollierungsanweisungen von ihnen und kompiliert dann die neuen Quelldateien, die dann ohne Debug-Code sind.

1

Es gibt keine integrierte Möglichkeit, die dies ermöglicht. Vielleicht möchten Sie einen Java Preprocessor verwenden.

+0

Ich dachte so, als ich googeln ... – Max

2
if(logger.isDebugEnabled()) { 
    logger.debug(expression); 
} 

Jedes Logging-Framework ich verwendet habe, müssen Sie die oben genannten Muster verwenden unnötige Auswertung des Logging Ausdrucks zu vermeiden.

+2

{Untersuchung} -Platzhalter in slf4j. –

+0

@ Thorbjørn Ravn Andersen - ordentlich - das ist deutlich besser für viele Anwendungsfälle. Ich würde mich über die Objekt-Array-Instanziierung, das Potenzial für unnötiges Autoboxing und so weiter ärgern, aber vieles davon sollte sowieso zur Laufzeit JIT-kompiliert werden. Die API slf4j schließt die Verwendung von booleschen Wächtern bei Bedarf nicht aus. – McDowell

+0

Das ist Geschmackssache. Für mich ergibt die {} -Notierung weniger Code (no if) und weniger Clutter (keine String-Verkettung). –

1

Eine Möglichkeit besteht darin, eine Überprüfung außerhalb der Protokollmethode durchzuführen. Fast die gleiche Prüfung wie Sie erwähnt haben, aber Sie tun es selbst:

if (LOGGER.isLoggable(Level.DEBUG)) { 
    LOGGER.log("undefined state" + state + " @ " + new Date()); 
} 

Diese Methode kann mit jeder Protokollebene verwendet werden. Weitere Informationen finden Sie unter Logger#isLoggable(Level). Beachten Sie, dass dies der empfohlene Weg ist, den Aufbau von Log-Methodenparametern zu vermeiden.

+0

Du hast mich hier geschlagen! – Riduidel

+0

Inlining der Protokollanruf ist nicht meine bevorzugte Option, da es eine Menge Unordnung hinzufügt. – Max

+0

dann die Optionen die Quelle vorverarbeiten oder Dinge wie AOP verwenden, um die Protokollierung hinzuzufügen, wenn Sie müssen. – unbeli

0

Ein hässlicher Hack, die funktionieren könnte ist die Umsetzung der Logger-Bibliothek mit einer leeren Implementierung zu verstecken. Der Optimierer wird sie inline einfügen, und die Entfernung von Deadcode sollte die Parameterkonstruktion entfernen. Dies funktioniert nicht, wenn die Parameterkonstruktion Nebenwirkungen enthält.

Jetzt ist dies Theorie, ich habe dies in der Praxis nicht getestet. Ich bin aber neugierig darauf. Vielleicht rechtfertigt dies eine separate Frage?

+0

Ich war mir nicht sicher, ob der Compiler "schlau" genug wäre, um das zu optimieren. Ich könnte es ausprobieren ... – Max

+0

Der Compiler scheint den Code nicht zu optimieren. Die Ausführungszeit für den Aufruf einer leeren Methode beim Übergeben einer statischen Zeichenfolge gegenüber einer verketteten unterscheidet sich um Größenordnungen (zumindest ohne spezielle Compiler-Optionen). – Max

+0

In jedem Fall würde ich mich nicht darauf verlassen. Ich habe meine IDE so konfiguriert, dass "logd" auf "if" (log.isDebugEnabled()) {log.debug ("yadayada");} und so weiter erweitert wird. –

0

Sie sollten wirklich eine Füllstandsanzeige für Ihre Protokollnachrichten verwenden, Level.SEVERE -> Level.FINEST.

Es gibt vordefinierte Methoden in dem Logger für diesen dh:

Logger.info(msg); 
Logger.finest(msg); // debug/trace message. 

Logger.log(Level.CONFIG, "config message"); 

dies ermöglicht es Ihnen minumim Protokollierungsebene auf der Anwendungsebene und Ein-/Ausschalten diese Nachrichten unter der konfigurierten Ebene mit dem Befehl konfigurieren Zeile, Konfigurationsdateien oder manuell mit LogManager

+0

Sicher, aber wenn Sie eine konstruierte Zeichenfolge übergeben möchten (siehe mein Beispiel), wird die Konstruktion aufgerufen, bevor Sie die Protokollierungsstufe überprüfen. – Max

+0

Sie könnten eine eigene Implementierung von Parametereinfügungen schreiben, die varargs verwendet, um sie bei der Protokollierung zu verwenden, die den aktuellen und gewünschten Protokollpegel überprüft. Überprüfen Sie auch log4j oder slf4j –

5

Haben Sie den Ansatz von slf4j mit {} - Platzhaltern berücksichtigt. Dies ermöglicht eine verzögerte Konstruktion der toString(), was bedeutet, dass log.debug (...) billig ist, wenn die Debug-Protokollierung deaktiviert ist.

+0

Ja, ich habe diesen Ansatz der Übergabe aller Parameter und Konstruieren sie nach der Überprüfung, aber ich hoffte immer noch eine positive Antwort auf die Behandlung dieses auf Compile-Ebene zu erhalten. Dies ist meine bevorzugte Art im Moment. – Max

+1

Betrachten Sie dann die assert-Anweisung, mit der Sie Teile des Codes vollständig deaktivieren können. Leider gibt die API slf4j void zurück, so dass sie nicht verwendet werden können - Sie müssen Ihren eigenen Wrapper rollen. –

0

Ich verstehe, dass der Java-Compiler in der Lage ist, Code-Blöcke zu eliminieren, die durch einen kompilierten Zeitkonstanten-Ausdruck geschützt werden. Also in der Theorie sollten Sie in der Lage sein, dies wie folgt mit etwas zu tun:

public class Logging { 
    public static final boolean ENABLED = true; // change to false 
} 

public class Something 
    .... 

    if (Logging.ENABLED) { 
      logger.debug("hello mum"); 
    } 
} 

Leider müssen Sie jede Klasse neu zu kompilieren, die auf der Logging.ENABLED Flagge hängt, wenn Sie seinen Wert ändern. Also ziehe ich viel folgend:

public class Something 
    .... 

    if (logger.isDebugEnabled()) { 
      logger.debug("hello mum"); 
    } 
} 

was den Vorteil hat, dass man feinkörnige Anpassungen die Protokollierungsstufen bei der Konfiguration oder sogar zur Laufzeit machen kann; z.B. mit einem Debugger, JMX, usw. Auch der Aufwand für den Aufruf von logger.isDebugEnabled() in Log4j ist niedrig genug, dass es unwahrscheinlich ist, dass es auffällt, wenn Sie eine wahnsinnige Menge an Logging in Ihrer Codebasis haben.

2

Es ist möglich, die Java-Klassendateien mit Proguard nachzubearbeiten und die Option -assumenosideeffects zu verwenden, um die Protokollierungsaufrufe zu entfernen. Dies geschieht am häufigsten für Android mit:

-assumenosideeffects class android.util.Log { 
    public static *** d(...); 
    public static *** v(...); 
} 

alle Anrufe Log.d(TAG, "message") zu entfernen, etc ...

+0

Willkommen bei SO.Ihr fragende Stil ist gut mit Code in Ihrer Frage ist gut prectice – khan