| 

.NET C# Java Javascript Exception

1
Hi,

Angenommen eine Anwendung hat ein MemoryLeak und stürzt irgendwann mit einem OutOfMemoryError ab. Wie bekommt man das am besten in sein Logfile? Beim Kunden läuft das ja schließlich nicht mit einer Konsole auf der man den Fehler sehen könnte.

Mein generischer Ansatz für beliebige Exceptions sieht so wie unten dargestellt aus. Geht es einfacher?

package logging;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This class allows us to log even uncatched exceptions.
* This is thought of like an AirBag. You dont want accidents (direct calls of
* printStackTrace(), or not catching possible Exceptions), but it's good to know that this must
* not end badly.
*/
public class SystemStreamLog extends PrintStream
{
private static final Log LOG = LogFactory.getLog(SystemStreamLog.class);
private PrintStream wrappedStream;

private SystemStreamLog(PrintStream wrap)
{
super(new NullOutputStream());
wrappedStream = wrap;
}

/**
* Overridden to find find and LOG Throwables.
*/
public void println(Object obj)
{
if(obj instanceof Throwable)
{
LOG.fatal("Uncaught Exception", (Throwable)obj);
}
wrappedStream.println(obj);
}

/**
* Replaces the System.err Stream with a special Version that will LOG Exceptions
* even if they have not been catched.
*/
public static void redirectSystemErr()
{
System.setErr(new SystemStreamLog(System.err));
}

/**
* Replaces the System.out Stream with a special Version that will LOG Exceptions
* even if they have not been catched.
* This will normally not be needed, because Exceptions will be output to the System.err, so this
* is just for paranoids who expect programmers to print their Exceptions to System.out.
*/
public static void redirectSystemOut()
{
System.setOut(new SystemStreamLog(System.out));
}

public static void main(String[] args)
{
SystemStreamLog.redirectSystemErr();

//just to create a OutOfMemoryError
List<String> list = new ArrayList<String>();
while(true)
{
list.add("HALLO");
}
}

}
class NullOutputStream extends OutputStream
{
public void write(int b) throws IOException
{}
public void write(byte[] b) throws IOException
{}
public void write(byte[] b, int off, int len) throws IOException
{}
}
16.03.2010
keinhaar 210 2 6
Mir fällt es gerade schwer, genau dein Problem nachzuvollziehen. Was passiert bei deiner OutOfMemoryException und in welcher Reihenfolge? In welchen Punkten funktioniert der Einsatz normaler Logging-Techniken nicht?
LastFreeNickname 18.03.2010
OutOfMemoryError ist wie der Name schon sagt ein Error, den Du normalerweise nicht mit einem catch Block fängst (obwohl das geht). Errors und insbesondere OutOfMemoryError bedeuten üblicherweise, das die Anwendung danach nicht mehr lauffähig ist. Nun würde ich diesen Fall halt gern in meinem Logfile finden. Um das mit "normalen" Logtechniken zu erreichen müsste man überall (main methode, event handler usw.) einen catch block wie diesen einfügen
[code]try
{
}
catch(OutOfMemoryError err)
{
LOG.fatal("Problem",err);
}
}
keinhaar 23.03.2010
6 Antworten
1
Grundsätzlich hilft Logging bei OutOfMemory nur wenn die JVM nicht gleich beendet. Was doch passieren kann. Dann hilft nur Diagnose - was im Kundenkontext schwer wird, aber anders geht es nicht.

Wenn die JVM nicht abstürzt finde ich den genannten Ansatz gut.
Ob es einfacher geht? Mir fallen zwei Dinge ein:
- Große try/catch-Klammer in main-Methode (würde ich aber nicht machen)
- Den UncaughtExceptionHandler nehmen (mein Favorit): http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.UncaughtExceptionHandler.html
23.02.2011
Markus Stäuble 285 7
Der UncaughtExceptionHandler ist eine gute alternative. Danke für den Tip.
keinhaar 23.04.2012
1
Ist zwar kein Errorlog, aber für die Analyse eines Leaks quasi unverzichtbar: einen Heap Dump erstellen lassen. Das geht mit dem VM-Parameter -XX:+HeapDumpOnOutOfMemoryError
(siehe auch hier). Den erstellten Dump findet man dann standardmäßig in der Datei java_pidpid.hprof im Arbeitsverzeichnis der Applikation, oder man gibt per -XX:HeapDumpPath=MYPATH/MYFILE eine Datei dafür an. Für eclipse empfehle ich zur Analyse des Dumps dann den Memory Analyzer.
21.02.2011
Mr. Green 11 1
0
Eine andere Möglichkeit ist der VM zu sagen, dass sie ein log-file mitführen soll. Dann kann man dort auf mögliche Ursachen einer OutOfMemoryException schließen.

Zitat aus IBM Java diagnostic guide:

-Xverbosegclog:<path to file><filename>
Causes verboseGC output to be written to the specified file. If the file cannot be found, verboseGC tries to create the file, and then continues as normal if it is successful. If it cannot create the file (for example, if an invalid filename is passed into the command), it will redirect the output to stderr.
-Xverbosegclog:<path to file><filename, X, Y>
Filename must contain a "#" (hash symbol), which is substituted with a generation identifier, starting at 1. X and Y are integers. This option works similarly to -Xverbosegclog:<path to file><filename>, but, in addition, the verboseGC output is redirected to X files, each containing verboseGC output from Y GC cycles.
28.06.2010
stevetc 111 3
0
Eine alternative Möglichkeit dazu, die Main-Methode und alle Eventhandler mit einem Try-Catch zu versehen wäre ein generischer ASPECT.

Grundlagen:

Aspect-Oriented Programming in Java
AspectJ

Anwendungsbeispiel:

Simplify Exception Logging with AspectJ
public aspect ExceptionLoggingAspect {

before (Exception e): handler(Exception+) && args(e) {
System.err.println("Caught by aspect: " + e.toString());
e.printStackTrace();
}
}


Leider kenn ich mich mit dem Java-Syntax nicht genau aus um das Beispiel so zu modifizieren das es nur sich auf OutOfMemory-Exceptions bezieht aber das solltest du hinbekommen.

Grundlegend erlauben dir Aspecte deinen Code zum einen Modularer zu gestallten, zum anderen, und das ist einer der Hauptgründe für Aspect-Orientierte-Programmierung (AOP), erlauben Sie dir deinen Code umzuschreiben. Der Compiler schreibt für dich deinen Code nach deinen Regeln um.
So kannst du einen Logging-ASPECT bauen der alle Ereignisse loggt. Du kannst einen Parameterprüfungs-ASPECT bzw. Validierungs-ASPECT bauen oder oder oder
30.06.2010
Floyd 14,6k 3 9
0
Errors sind grundsätzlich von der Applikation NICHT abzufangen. Sie zeigen, dass eine Applikation nicht mehr lauffähig ist.

Der Ansatz von stevetc ist aus meiner Sicht der richtige.

Errors sind übrigends keine Exceptions sondern Throwables.
23.02.2011
oopexpert 455 1 8
-3
Du mußt nicht unbedingt überall einen try..catch block einfügen. Genau wie alles andere auch, werden Exceptions aus Subfunktionen an die Elternfunktion durchgereicht. Wird dort die Exception abgefangen, endet das Durchreichen, es sei denn man löst erneut die Exception aus.
Da dein erster Aufruf der Application über die Main-Methode stattfindet, ist dies die letzte Möglichkeit eine Exception selbst zu behandeln.
Verwendest du also nirgends in deiner Application einen try...catch block, solltest du wenigstens in der Main-Methode einen setzen und alle ankommenden Exceptions loggen.
Willst du später doch eine Exception in einer Subfunktion behandeln, ist dies kein Problem, einfach tun ;-) ...kannst ja in der subfunktion erstmal schauen ob du die Exception behandeln willst und falls nicht erneut auslösen, dann wird diese zur Main-Methode weitergereicht.

Grüßle
05.05.2010
Blue 321 1 5
Das beantwortet meine Frage leider überhaupt nicht.
keinhaar 07.05.2010

Stelle deine Java-Frage jetzt!