Java EE Application Server speichern Fehlermeldungen meistens in Logdateien. Im Cluster und besonders in kritischen Situationen können viele Logdateien mit einem insgesamt großen Volumen anfallen. Die Analyse dieser Logdateien kann sehr zeitaufwändig sein.
Es wird ein Hilfstool vorgestellt, welches (nach Anpassung) interessante Logdateiausschnitte übersichtlich zusammenfasst.
Bitte beachten Sie folgende Einschränkungen:
Das Hilfstool "LogfilesExtract" ist nicht für eine laufende Überwachung des Serverbetriebs geeignet.
Verwenden Sie für diesen Zweck Monitoring-Tools wie zum Beispiel
Hyperic HQ oder
Nagios.
Vor dem Einsatz von LogfilesExtract sind Anpassungen erforderlich. LogfilesExtract wurde mit Logfiles von JBoss und Oracle WebLogic getestet, ist aber leicht an andere Server anpassbar.
Der gezeigte Sourcecode entspricht nicht professionellen Anforderungen. Er soll lediglich beispielhaft eine mögliche Vorgehensweise demonstrieren und ist hauptsächlich für Softwareentwickler interessant.
Verbessert werden könnte zum Beispiel: Vorgaben und Regular Expressions aus Properties-Datei laden, alle Regular Expressions vorkompilieren, bessere Fehlerbehandlung, höherere Parallelisierung etc.
Das Ergebnis des Hilfstools ist eine HTML-Seite, die zum Beispiel ausschnittsweise so aussehen kann:
Letztes Datum (Logfile) Erstes Datum (Logfile) Anzahl |
Fehlertext (Achtung: stark gekuerzt) (Herausgefiltert wurden ... Meldungen im Zeitraum von '2007-01-22 13:29h' bis '2007-01-23 16:42h') |
---|---|
2007-01-23 16:24h (MeinServer3.log); 2007-01-22 15:59h (MeinServer1.log); Anzahl=4; |
<Info> <EJB> <AbcXyz> < de.meinefirma.meinprojekt.meinpackage.MeineKlasseY threw exception: java.lang.NullPointerException: at de.meinefirma.meinprojekt.meinpackage.MeineKlasseY.meineMethodeY(MeineKlasseY.java:789) at de.meinefirma.meinprojekt.meinpackage.MeineKlasseX.meineMethodeX(MeineKlasseX.java:456) Caused by: java.lang.NullPointerException: at de.meinefirma.meinprojekt.meinpackage.MeineKlasseA.meineMethodeA(MeineKlasseA.java:123) |
2007-01-22 12:24h (MeinServer2.log); 2007-01-22 11:59h (MeinServer2.log); Anzahl=7; |
<Info> <EJB> <AbcXyz> < de.meinefirma.meinprojekt.meinpackage.MeineKlasseX threw exception: java.lang.IllegalArgumentException: at de.meinefirma.meinprojekt.meinpackage.MeineKlasseX.meineMethodeX(MeineKlasseX.java:42) |
Mehrfach erscheinende Meldungen zusammenfassen
Viele Exceptions erscheinen mehrfach in den Logdateien.
Diese Meldungen werden zu einer Meldung zusammengefasst und es werden die Anzahl der Meldungen und
das Datum und die Uhrzeit des ersten und letzten Auftretens extrahiert.
Hierzu ist keine Anpassung erforderlich.
Kürzung des extrahierten Textes
Bestimme Ausdrücke in den Meldungen sind für einen schnellen Überblick unerwünscht.
Solche im Array "DELETE_STRING_PART_REGEX" durch
"Regular Expressions"
definierten Teilstrings werden ausgeblendet.
(Die "Arrays" befinden sich in der unten gezeigten:
"LogfilesExtract.java".)
(Beispiele finden Sie weiter unten in
"Mögliche Vorgaben für Oracle WebLogic".)
Bestimmte Meldungen komplett ausblenden
Wenn es viele große Logdateien gibt, müssen viele nicht benötigte Meldungen ausgeblendet werden.
Insbesondere Softwareentwickler interessieren sich weniger für administrative Meldungen,
sondern eher für durch Programmierfehler verursachte Exceptions.
Im Array "DELETE_COMPLETE_REGEX" werden Meldungen per
"Regular Expressions"
definiert, die komplett (inklusive Stacktrace) nicht extrahiert werden.
(Bitte beachten Sie die Reihenfolge: Vor dem Vergleich werden die über "DELETE_STRING_PART_REGEX" definierten Teilstrings entfernt.)
(Beispiele finden Sie weiter unten in "Mögliche Vorgaben für Oracle WebLogic".)
Kürzung des Stacktraces
Die oft seitenlangen Stacktraces werden drastisch verkürzt.
Die erste Zeile wird immer extrahiert.
Stacktrace-Zeilen, die mit einem der Strings in "EXTRACT_STACKTRACE_LINE_ALLWAYS" beginnen,
werden alle extrahiert.
Zu Stacktrace-Zeilen, die mit einem der Strings in "EXTRACT_STACKTRACE_LINE_ONCE" beginnen,
wird jeweils eine Zeile aus einer Package-Gruppe extrahiert, deren Package-Prüftiefe durch "PACKAGE_START_PART" definiert wird.
Andere Stacktrace-Zeilen werden ignoriert.
Nur Meldungen extrahieren, in denen bestimmte Schlüsselwörter vorkommen
Eventuell interessieren Sie sich nur für wenige bestimmte Meldungen,
die bestimmte Schlüsselausdrücke enthalten, wie zum Beispiel "Exception:".
Solche Schlüsselwörter definieren Sie in "MUST_HAVE_REGEX_PATTERN".
Bitte beachten Sie: Sobald Sie eines oder mehrere solcher Schlüsselworte definieren, werden nur Meldungen extrahiert,
die mindestens eines der Schlüsselworte enthalten.
Alle anderen Meldungen werden nicht extrahiert.
(Bitte beachten Sie die Reihenfolge: Vor der Schlüsselwortsuche erfolgen die oben genannte Kürzungen.)
Beginn von Meldungen in den Logdateien erkennen und das Datum und die Uhrzeit extrahieren
Damit das Tool den Beginn von Meldungen in den Logdateien identifizieren kann,
müssen im Array "DATETIME_REGEX_PATTERN" entsprechende
"Regular Expressions"
definiert werden.
Sie sollten möglichst mit einem "^"-Zeichen beginnen, damit der Zeilenanfang untersucht wird.
Die entsprechenden Ausdrücke müssen zusätzlich das Datum und die Uhrzeit enthalten
(die dann über "DATE_YYYYMMDD_REGEX_PATTERN", "DATE_DDMMYYYY_REGEX_PATTERN" und "TIME_HHMM_REGEX_PATTERN" extrahiert werden).
Kappung zu langer Zeilen
Die ersten Zeilen werden auf eine Länge von "LEN_MAX_1" begrenzt und weitere Zeilen auf "LEN_MAX_N".
Ihr Projektverzeichnis sieht jetzt so aus:
[\MeinWorkspace\LogfilesExtract] |- [bin] '- [src] '- [logfilesextract] |- LogfilesExtract.java '- TasksConcurrentExecutor.java
Java SE JDK muss installiert sein. Falls das JDK-"bin"-Verzeichnis nicht im "PATH" eingetragen ist, ergänzen Sie es, zum Beispiel so (bitte Pfad anpassen):
set PATH=%PATH%;C:\Program Files\Java\jdk1.6\bin
Öffnen Sie ein Kommandozeilenfenster ('Start' | 'Alle Programme' | 'Zubehör' | 'Eingabeaufforderung') und geben Sie folgende Befehle ein:
cd \MeinWorkspace\LogfilesExtract
javac -d bin src/logfilesextract/LogfilesExtract.java
java -Xmx500M -cp bin logfilesextract/LogfilesExtract C:\JBoss\server\default\log\*.log > LogfilesExtract.html
start LogfilesExtract.html
Statt "C:\JBoss\server\default\log\*.log" müssen Sie einen oder mehrere Pfade zu auf Ihrem Rechner existierenden Logdateien einsetzen.
Außerdem macht die Programmausführung nur Sinn, wenn Sie die Vorgaben an Ihre Gegebenheiten, Umgebungen, Versionen und Bezeichnungen angepasst haben, wie oben beschrieben ist.
package logfilesextract; import java.io.*; import java.util.*; import java.util.regex.*; /** * Doku: http://www.torsten-horn.de/techdocs/jee-logfilesextract.htm * Regex: http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html */ public class LogfilesExtract { static final String HELPTEXT = "Analyse von LogFiles\n" + "Fehler: Pfad[e] und Dateinamen (mit Joker) der LogFiles muessen als Parameter uebergeben werden,\n" + " z.B. \"C:\\Logfiles\\*.*\"\n" + " oder \"C:\\WebLogic\\user_projects\\domains\\meineDomain\\*.log* C:\\WebLogic\\user_projects\\domains\\meineDomain\\meinServer\\*.log*\"\n" + "Beispielaufruf:\n" + " java -Xmx500M -cp ./bin logfilesextract/LogfilesExtract C:\\Logfiles\\*.* > LogfilesExtract.html"; static final Pattern MUST_HAVE_REGEX_PATTERN = Pattern.compile("(fatal|error|exception)"); static final String[] EXTRACT_STACKTRACE_LINE_ALLWAYS = { "at de.meinefirma.meinprojekt.meinpackage.subpackageabc.spezpackage", "at de.meinefirma.meinprojekt.meinpackage.subpackagexyz" }; static final String[] EXTRACT_STACKTRACE_LINE_ONCE = { "at de.meinefirma." }; static final String[] DELETE_STRING_PART_REGEX = { // ... Beispiele siehe unten }; static final String[] DELETE_COMPLETE_REGEX = { // ... Beispiele siehe unten }; static final String[] SPLITT_REGEX_NULLPOINTER_ETC = { "NullPointerException", "IndexOutOfBoundsException", "NoClassDefFoundError", "ClassNotFoundException" }; static final String[] SPLITT_REGEX_DB = { // ... Beispiele siehe unten }; static final String[] SPLITT_REGEX_TIMEOUT = { "Timeout|TimedOut|timed out", "weblogic.kernel.Default .* has been busy for \"\\d*\" seconds working on the request .*, which is more than the configured time .* of \"600\" seconds", }; static final String[] SPLITT_REGEX_SPEZIELL = { "OutOfMemoryError", "StaleObjectStateException: Row was updated or deleted by another transaction", "ERROR de.meinefirma.meinprojekt.meinpackage.subpackageabc.spezpackage1", "ERROR de.meinefirma.meinprojekt.meinpackage.subpackageabc.spezpackage2", "ERROR org.hibernate" }; static final TabellenGruppe[] TABELLEN_GRUPPEN = { new TabellenGruppe("NullPointerExceptions, IndexOutOfBoundsExceptions, NoClassDefFoundError", SPLITT_REGEX_NULLPOINTER_ETC, null), new TabellenGruppe("Datenbank-Exceptions", SPLITT_REGEX_DB, null), new TabellenGruppe("Time-outs und Lockings", SPLITT_REGEX_TIMEOUT, null), new TabellenGruppe("Spezielle Fehler", SPLITT_REGEX_SPEZIELL, null), new TabellenGruppe("Restliche Fehler (uebrig nach obigen RegEx-Filtern)", null, null) }; static final Pattern[] DATETIME_REGEX_PATTERN = { Pattern.compile("^\\d{4}\\-\\d{1,2}\\-\\d{1,2} \\d{1,2}\\:\\d{2}\\:\\d{2}\\,\\d* "), Pattern.compile("^=<\\d*\\.\\d*\\.\\d* \\d*\\:\\d*\\:\\d*\\,\\d*>"), Pattern.compile("^=\\[\\d*\\.\\d*\\.\\d* \\d*\\:\\d*\\:\\d*\\,\\d*\\]"), Pattern.compile("^####<\\d*.\\d*.\\d* \\d*.\\d* Uhr \\S*>") }; static final Pattern DATE_YYYYMMDD_REGEX_PATTERN = Pattern.compile("\\d{4}\\-\\d{1,2}\\-\\d{1,2}"); static final Pattern DATE_DDMMYYYY_REGEX_PATTERN = Pattern.compile("\\d{1,2}\\.\\d{1,2}\\.\\d{4}"); static final Pattern TIME_HHMM_REGEX_PATTERN = Pattern.compile("\\d{1,2}[:\\.]\\d{1,2}"); static final int PACKAGE_START_PART = 4; static final int LEN_MAX_1 = 700; static final int LEN_MAX_N = 140; static final int ZEILEN_MAX = 50; public static void main( String[] args ) throws IOException { if( args.length < 1 ) { System.out.println(HELPTEXT); System.exit(1); } System.out.println( "<html>\n" + "<head><style type='text/css'>body, th, td { font-family: Arial,Helvetica,sans-serif } a:hover { color: green }</style></head>\n" + "<h3>Analyse von Logfiles</h3>\n" ); Map<String,TabellenZeilenInhalt> map = new HashMap<String,TabellenZeilenInhalt>(); // Extrahiere Fehlermeldungen aus Logfiles: long fileSizeSum = extrahiereAusMehrerenPfadenMitJoker( args, map ); TabellenZeilenInhalt[] tabellenZeilenInhaltArr = convertMapToArr( map ); if (tabellenZeilenInhaltArr == null || tabellenZeilenInhaltArr.length == 0) { System.out.println( "<h3>Keine Ergebnisse!</h3>\n</html>\n" ); return; } // Ueberschrift: Summierungen summierungenAll = berechneSummeAnzahlUndDateTimeAeltestesUndJuengstes( tabellenZeilenInhaltArr ); System.out.println("\n<b>Selektiert wurden insgesamt " + tausenderPunkt(summierungenAll.summeAnzahl) + " Meldungen im Zeitraum von '" + summierungenAll.dateTimeAeltestes + "' bis '" + summierungenAll.dateTimeJuengstes + "', Summe der Logfiles: " + bytesKbMb(fileSizeSum) + "</b><br>\n"); // Splitte Fehlermeldungen in mehrere HTML-Tabellen: int idx = 0; for (int j = 0; j < TABELLEN_GRUPPEN.length && tabellenZeilenInhaltArr != null; j++) { TABELLEN_GRUPPEN[j].tabellenInhaltArr = splitte(TABELLEN_GRUPPEN[j].splittRegex, tabellenZeilenInhaltArr); tabellenZeilenInhaltArr = null; int lastIndex = TABELLEN_GRUPPEN[j].tabellenInhaltArr.length - 1; if(lastIndex >= 0 && j < TABELLEN_GRUPPEN.length - 1 && TABELLEN_GRUPPEN[j].tabellenInhaltArr[lastIndex].ueberschrift == null) { tabellenZeilenInhaltArr = TABELLEN_GRUPPEN[j].tabellenInhaltArr[lastIndex].tabellenZeilenInhaltArr; TABELLEN_GRUPPEN[j].tabellenInhaltArr[lastIndex].tabellenZeilenInhaltArr = null; } for (int i = 0; i < TABELLEN_GRUPPEN[j].tabellenInhaltArr.length; i++) { if(TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenZeilenInhaltArr != null && TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenZeilenInhaltArr.length > 0) { TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].summierungen = berechneSummeAnzahlUndDateTimeAeltestesUndJuengstes(TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenZeilenInhaltArr); TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].link = "Tabelle" + ++idx; TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].ueberschrift = "" + idx + ((TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].ueberschrift != null) ? (". Tabelle mit Filter-RegEx \"" + TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].ueberschrift + "\"") : ". Tabelle: Alles ausser per RegEx herausgefiltert"); TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenzeileHtml = konvertiereStringArrayZuHtmlTabelle( TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].link, TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].ueberschrift, TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenZeilenInhaltArr) + "<br>"; TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenZeilenInhaltArr = null; } } } // Erzeuge Inhaltsverzeichnis zu den verschiedenen HTML-Tabellen: System.out.println("<table border=0>"); for (int j = 0; j < TABELLEN_GRUPPEN.length; j++) { if(TABELLEN_GRUPPEN[j].tabellenInhaltArr != null && TABELLEN_GRUPPEN[j].tabellenInhaltArr.length > 0 && TABELLEN_GRUPPEN[j].tabellenInhaltArr[0] != null && TABELLEN_GRUPPEN[j].tabellenInhaltArr[0].tabellenzeileHtml != null) { System.out.println("<tr><td colspan='3'><small><small> </small></small></td></tr>"); System.out.println("<tr><td> </td><td align='center'>Anz.</td>" + "<td><b> " + TABELLEN_GRUPPEN[j].gruppenUeberschrift + "</b></td></tr>"); for (int i = 0; i < TABELLEN_GRUPPEN[j].tabellenInhaltArr.length; i++) { if(TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenzeileHtml != null) { int sumAnz = TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].summierungen.summeAnzahl; String sumAnzStr = tausenderPunkt(sumAnz); if(sumAnz > 100) { sumAnzStr = "<b>" + sumAnzStr + "</b>"; } System.out.println("<tr><td> </td>" + "<td align='center'>" + sumAnzStr + "</td>" + "<td><a href='#" + TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].link + "'>" + TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].ueberschrift + "</a></td></tr>"); } } } } System.out.println("</table><br>"); // Zeige die HTML-Tabellen: System.out.println("<br>\n\n<h4>Tabellen</h4>"); for (int j = 0; j < TABELLEN_GRUPPEN.length; j++) { if(TABELLEN_GRUPPEN[j].tabellenInhaltArr != null) { for (int i = 0; i < TABELLEN_GRUPPEN[j].tabellenInhaltArr.length; i++) { if(TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenzeileHtml != null) { System.out.println(TABELLEN_GRUPPEN[j].tabellenInhaltArr[i].tabellenzeileHtml); } } } } System.out.println("\n</html>\n"); System.exit(0); } static long extrahiereAusMehrerenPfadenMitJoker( String[] filePathesAndNamesArr, Map<String,TabellenZeilenInhalt> map ) throws IOException { long fileSizeSum = 0; System.out.println("<p><small>"); for (int i = 0; i < filePathesAndNamesArr.length; i++) { fileSizeSum += extrahiereAusEinzelnemPfadMitJoker(filePathesAndNamesArr[i], map); } System.out.println("<br></small></p>"); return fileSizeSum; } static long extrahiereAusEinzelnemPfadMitJoker( String filePathAndNames, Map<String,TabellenZeilenInhalt> map ) throws IOException { if(filePathAndNames == null || filePathAndNames.trim().length() <= 0) { return 0; } long fileSizeSum = 0; int n1 = filePathAndNames.lastIndexOf('\\'); int n2 = filePathAndNames.lastIndexOf('/'); int nm = Math.max(n1, n2); if(nm < 1 || nm > filePathAndNames.length() - 2) { return 0; } filePathAndNames = filePathAndNames.trim(); String pathWithoutFilename = filePathAndNames.substring(0, nm); String filenameWithoutPath = filePathAndNames.substring(++nm); nm = filenameWithoutPath.indexOf('*'); String filenameStart = (nm >= 0) ? filenameWithoutPath.substring(0, nm) : filenameWithoutPath; String filenameEnd = (nm >= 0) ? filenameWithoutPath.substring(++nm) : filenameWithoutPath; File[] files = (new File(pathWithoutFilename)).listFiles(); if(files == null || files.length <= 0) { return 0; } for (int k = 0; k < files.length; k++) { if(files[k].isDirectory()) { continue; } String filename = files[k].getName(); if(filename == null || !filename.startsWith(filenameStart) || !filename.endsWith(filenameEnd)) { continue; } fileSizeSum += files[k].length(); // System.out.println(files[k] + "<br>"); BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(files[k]))); extrahiereAusEinzelnemLogfileStream(filename, in, map); in.close(); } return fileSizeSum; } static Map<String,TabellenZeilenInhalt> extrahiereAusEinzelnemLogfileStream( String filename, BufferedReader in, Map<String,TabellenZeilenInhalt> map ) throws IOException { String logLine; String dateTime = null; List<String> extractedLines = null; Set<String> extractedStacktraceLinesSet = null; boolean firstStacktraceLineFound = false; // Lies Zeile aus LogFile: while((logLine = in.readLine()) != null) { if (logLine.trim().length() <= 0) { continue; } // Start-Zeile? boolean isStartLine = false; for (int j=0; j<DATETIME_REGEX_PATTERN.length; j++) { Matcher match = DATETIME_REGEX_PATTERN[j].matcher(logLine); if (match.find()) { isStartLine = true; // Vorher ermittelte Daten speichern: addToMap(filename, dateTime, extractedLines, map); // Neue Daten-Ermittlung starten: extractedLines = null; extractedStacktraceLinesSet = new HashSet<String>(); firstStacktraceLineFound = false; // Datum und Uhrzeit: String dateTimeMatch = logLine.substring(match.start(), match.end()); dateTime = extractDateTime(dateTimeMatch); logLine = logLine.substring(match.end()); break; } } if (!isStartLine && extractedLines == null) { continue; } // Nicht relevanten Text entfernen: for (int j=0; j<DELETE_STRING_PART_REGEX.length; j++) { logLine = logLine.replaceAll(DELETE_STRING_PART_REGEX[j], ""); } logLine = logLine.replaceAll("<>", ""); while(logLine.indexOf(" ") > 0) { logLine = logLine.replaceAll(" ", " "); } while(logLine.indexOf(": :") >= 0) { logLine = logLine.replaceAll(": :", ":"); } while(logLine.indexOf(": :") >= 0) { logLine = logLine.replaceAll(": :", ":"); } logLine = logLine.replaceAll("> <", "> <"); if (logLine == null || logLine.trim().length() <= 0 || logLine.trim().equals(":") || logLine.trim().equals(">")) { continue; } if (isStartLine) { // Nicht relevanten Text entfernen: Diesmal komplette Zeilen/Meldungen: logLine = logLine.trim(); for (int j=0; j<DELETE_COMPLETE_REGEX.length; j++) { if(logLine.matches(DELETE_COMPLETE_REGEX[j])) { logLine = null; break; } } if(logLine == null) { continue; } extractedLines = new ArrayList<String>(); addToExtractedLines(LEN_MAX_1, 0, ' ', null, logLine, extractedLines); } if (!isStartLine && extractedLines != null) { if (!logLine.startsWith("\t") && !logLine.startsWith(" ")) { // Fuege jede nicht eingerueckte Zeile hinzu: addToExtractedLines(LEN_MAX_1, 0, ' ', null, logLine, extractedLines); } else { if (!firstStacktraceLineFound) { // Fuege immer die erste eingerueckte Zeile hinzu: addToExtractedLines(LEN_MAX_1, LEN_MAX_N, '(', " ", logLine, extractedLines); firstStacktraceLineFound = true; } else { // Fuege bestimmte eingerueckte Zeilen immer hinzu: boolean isAdded = false; for (int i=0; i<EXTRACT_STACKTRACE_LINE_ALLWAYS.length; i++) { if(logLine.trim().startsWith(EXTRACT_STACKTRACE_LINE_ALLWAYS[i])) { addToExtractedLines(LEN_MAX_N, 0, ' ', null, logLine, extractedLines); isAdded = true; break; } } if(extractedStacktraceLinesSet != null) { // Fuege bestimmte eingerueckte Zeilen einmal hinzu: for (int i=0; !isAdded && i<EXTRACT_STACKTRACE_LINE_ONCE.length; i++) { if(logLine.trim().startsWith(EXTRACT_STACKTRACE_LINE_ONCE[i])) { int n = 0, idx = 0; while(idx >= 0 && n++ < PACKAGE_START_PART) { idx = logLine.indexOf('.', ++idx); } if(idx > 0) { String s = logLine.substring(0, idx); if (extractedStacktraceLinesSet.add(s)) { addToExtractedLines(LEN_MAX_N, 0, ' ', null, logLine, extractedLines); isAdded = true; } } } } } } } } } // Die zuletzt ermittelten Daten speichern: addToMap(filename, dateTime, extractedLines, map); return map; } static void addToExtractedLines( int cuttingLengthMax, int separatingLengthMax, char marker, String separator, String line, List<String> extractedLines ) { if( line == null || line.trim().length() <= 0 || extractedLines.size() >= ZEILEN_MAX ) { return; } // Verkuerze auf maximale Laenge: if (line.length() > cuttingLengthMax && cuttingLengthMax > 0) { line = line.substring(0, cuttingLengthMax-3) + "..."; } // Fuege z.B. ein Leerzeichen ein, um einen Zeilenumbruch zu ermoeglichen: if (line.length() > separatingLengthMax && separatingLengthMax > 0 && separator != null) { int idx = line.indexOf(marker); if (idx < 0) { idx = separatingLengthMax; } line = line.substring(0, idx) + separator + line.substring(idx); } extractedLines.add(line); } static void addToMap( String filename, String date, List<String> extractedLines, Map<String,TabellenZeilenInhalt> map ) { if(map == null || extractedLines == null || extractedLines.size() <= 0) { return; } // Doppelte Zeilen aus extractedLines-Liste entfernen: Set<String> set = new HashSet<String>(); for (Iterator<String> iterator1 = extractedLines.iterator(); iterator1.hasNext();) { String line = iterator1.next(); if (!set.add(line)) { iterator1.remove(); } } // extractedLines-Liste zu einem String zusammenfassen: StringBuffer sb = new StringBuffer(); boolean firstLine = true; for (Iterator<String> iterator = extractedLines.iterator(); iterator.hasNext();) { if (firstLine) { firstLine = false; } else { sb.append("<br> "); } String line = iterator.next(); // '<' und '>' ersetzen wegen HTML-Ausgabe: line = line.replaceAll("<", "<").replaceAll(">", ">"); sb.append(line); } String key = sb.toString(); // Pruefe, ob "must have" enthalten ist: if( !MUST_HAVE_REGEX_PATTERN.matcher( key.toLowerCase() ).find() ) { return; } // Lies bereits vorhandenen TabellenZeilenInhalt: TabellenZeilenInhalt tabellenZeilenInhalt = map.get(key); if (tabellenZeilenInhalt == null) { tabellenZeilenInhalt = new TabellenZeilenInhalt(); } if(tabellenZeilenInhalt.letztesDatum == null) tabellenZeilenInhalt.letztesDatum = date; if(tabellenZeilenInhalt.letztesLogfile == null) tabellenZeilenInhalt.letztesLogfile = filename; if(tabellenZeilenInhalt.erstesDatum == null) tabellenZeilenInhalt.erstesDatum = date; if(tabellenZeilenInhalt.erstesLogfile == null) tabellenZeilenInhalt.erstesLogfile = filename; if(tabellenZeilenInhalt.anzahlFehler == null) tabellenZeilenInhalt.anzahlFehler = "0"; if (date != null && date.length() > 0) { if (tabellenZeilenInhalt.letztesDatum.compareTo(date) < 0) { tabellenZeilenInhalt.letztesDatum = date; tabellenZeilenInhalt.letztesLogfile = filename; } if (tabellenZeilenInhalt.erstesDatum.compareTo(date) > 0) { tabellenZeilenInhalt.erstesDatum = date; tabellenZeilenInhalt.erstesLogfile = filename; } } tabellenZeilenInhalt.anzahlFehler = "" + (Integer.parseInt(tabellenZeilenInhalt.anzahlFehler) + 1); map.put(key, tabellenZeilenInhalt); } static TabellenZeilenInhalt[] convertMapToArr( Map<String,TabellenZeilenInhalt> map ) { TabellenZeilenInhalt[] result = new TabellenZeilenInhalt[map.size()]; int i = 0; for (Iterator<Map.Entry<String,TabellenZeilenInhalt>> iterator = map.entrySet().iterator(); iterator.hasNext();) { Map.Entry<String,TabellenZeilenInhalt> mapentry = iterator.next(); String msg = mapentry.getKey(); TabellenZeilenInhalt tabellenZeilenInhalt = mapentry.getValue(); if (tabellenZeilenInhalt != null) { tabellenZeilenInhalt.fehlertext = msg + eventuellLogdateiname( tabellenZeilenInhalt.letztesLogfile, tabellenZeilenInhalt.erstesLogfile ); result[i++] = tabellenZeilenInhalt; } } Arrays.sort(result, new Comparator<TabellenZeilenInhalt>() { @Override public int compare(TabellenZeilenInhalt tzi1, TabellenZeilenInhalt tzi2) { int cmp = tzi2.letztesDatum.compareTo(tzi1.letztesDatum); if (cmp != 0) { return cmp; } cmp = tzi2.letztesLogfile.compareTo(tzi1.letztesLogfile); if (cmp != 0) { return cmp; } return tzi2.fehlertext.compareTo(tzi1.fehlertext); } }); return result; } static TabellenInhalt[] splitte( String[] splittRegex, TabellenZeilenInhalt[] tabellenZeilenInhaltArr ) { if(splittRegex == null) { TabellenInhalt tabellenInhalt = new TabellenInhalt(); tabellenInhalt.tabellenZeilenInhaltArr = tabellenZeilenInhaltArr; return new TabellenInhalt[] { tabellenInhalt }; } @SuppressWarnings("unchecked") List<TabellenZeilenInhalt>[] lstArr = new List[splittRegex.length + 1]; Pattern[] splittRegexPattern = new Pattern[splittRegex.length]; int j; for(j = 0; j < splittRegexPattern.length; j++) { splittRegexPattern[j] = Pattern.compile(splittRegex[j].toLowerCase()); } for(j = 0; j < lstArr.length; j++) { lstArr[j] = new ArrayList<TabellenZeilenInhalt>(); } // ------------------------------------------------- // Parallelisierung: Computable<MatchingFinderTask,Integer> computable = new Computable<MatchingFinderTask,Integer>() { @Override public Integer compute( MatchingFinderTask mft ) { int i; for( i = 0; i < mft.regexPatterns.length; i++ ) { Matcher match = mft.regexPatterns[i].matcher( mft.s.toLowerCase() ); if( match.find() ) break; } return new Integer( i ); } }; List<TaskDescription<MatchingFinderTask,Integer>> tasks = new ArrayList<TaskDescription<MatchingFinderTask,Integer>>(); for( int i = 0; i < tabellenZeilenInhaltArr.length; i++ ) { tasks.add( new TaskDescription<MatchingFinderTask,Integer>( computable, new MatchingFinderTask( splittRegexPattern, tabellenZeilenInhaltArr[i].fehlertext ) ) ); } (new TasksConcurrentExecutor<MatchingFinderTask,Integer>( tasks, 8, 3600 )).run(); for( int i = 0; i < tabellenZeilenInhaltArr.length; i++ ) { j = tasks.get( i ).result.intValue(); lstArr[j].add( tabellenZeilenInhaltArr[i] ); } // ------------------------------------------------- List<TabellenInhalt> tabellen = new ArrayList<TabellenInhalt>(); for(j = 0; j < lstArr.length; j++) { if(lstArr[j].size() <= 0) continue; TabellenInhalt tabellenInhalt = new TabellenInhalt(); tabellenInhalt.tabellenZeilenInhaltArr = lstArr[j].toArray( new TabellenZeilenInhalt[lstArr[j].size()] ); if(j < splittRegex.length) tabellenInhalt.ueberschrift = splittRegex[j]; tabellen.add(tabellenInhalt); } return tabellen.toArray(new TabellenInhalt[tabellen.size()]); } static String konvertiereStringArrayZuHtmlTabelle( String linkName, String title, TabellenZeilenInhalt[] tabellenZeilenInhaltArr ) { StringBuffer sb1 = new StringBuffer(); if(linkName != null) { sb1.append("\n<a name='"+ linkName + "'></a>"); } title = (title == null) ? "" : (title + "<br>"); Summierungen summierungen = berechneSummeAnzahlUndDateTimeAeltestesUndJuengstes(tabellenZeilenInhaltArr); sb1.append("\n<table border=1>\n<tr>" + "<th align='left'>Letztes Datum (Logfile)<br>Erstes Datum (Logfile)<br>Anzahl</th>\n" + "<th align='left'>" + title + "(Fehlertexte stark gekuerzt)<br>(" + tausenderPunkt(summierungen.summeAnzahl) + " Meldungen im Zeitraum von '" + summierungen.dateTimeAeltestes + "' bis '" + summierungen.dateTimeJuengstes + "')</th></tr>\n"); for (int i=0; i<tabellenZeilenInhaltArr.length; i++) { StringBuffer sb2 = new StringBuffer(); sb2.append("<tr><td valign='top'>").append(tabellenZeilenInhaltArr[i].letztesDatum).append("<br>(").append(tabellenZeilenInhaltArr[i].letztesLogfile).append(");<br>"); if(tabellenZeilenInhaltArr[i].anzahlFehler != null && Integer.parseInt(tabellenZeilenInhaltArr[i].anzahlFehler) > 1) { sb2.append(tabellenZeilenInhaltArr[i].erstesDatum).append("<br>(").append(tabellenZeilenInhaltArr[i].erstesLogfile).append(");<br>"); } sb2.append("Anzahl=").append(tabellenZeilenInhaltArr[i].anzahlFehler).append(";</td>\n<td valign='top'>") .append(tabellenZeilenInhaltArr[i].fehlertext).append("</td></tr>\n"); sb1.append(sb2.toString()); } sb1.append("</table>\n"); return sb1.toString(); } static Summierungen berechneSummeAnzahlUndDateTimeAeltestesUndJuengstes( TabellenZeilenInhalt[] tabellenZeilenInhaltArr ) { int summeAnzahl = 0; String dateTimeAeltestes = null; for (int i=0; i<tabellenZeilenInhaltArr.length; i++) { if (tabellenZeilenInhaltArr[i].erstesDatum != null && tabellenZeilenInhaltArr[i].erstesDatum.length() > 0 && (dateTimeAeltestes == null || dateTimeAeltestes.compareTo(tabellenZeilenInhaltArr[i].erstesDatum) > 0)) { dateTimeAeltestes = tabellenZeilenInhaltArr[i].erstesDatum; } if (tabellenZeilenInhaltArr[i].anzahlFehler != null && tabellenZeilenInhaltArr[i].anzahlFehler.length() > 0) { summeAnzahl += Integer.parseInt(tabellenZeilenInhaltArr[i].anzahlFehler); } } Summierungen summierungen = new Summierungen(); summierungen.summeAnzahl = summeAnzahl; summierungen.dateTimeAeltestes = dateTimeAeltestes; summierungen.dateTimeJuengstes = tabellenZeilenInhaltArr[0].letztesDatum; return summierungen; } static String eventuellLogdateiname( String letztesLogfile, String erstesLogfile ) { final String[] doNotUse = { "sccLog", "Error_All" }; if( letztesLogfile == null || erstesLogfile == null ) return ""; for( String s : doNotUse ) { if( letztesLogfile.startsWith( s ) || erstesLogfile.startsWith( s ) ) return ""; } StringBuffer sb = new StringBuffer(); int n = Math.min( letztesLogfile.length(), erstesLogfile.length() ); int i = -1; while( ++i < n && letztesLogfile.charAt( i ) == erstesLogfile.charAt( i ) ) sb.append( erstesLogfile.charAt( i ) ); return ( sb.length() == 0 ) ? "" : "<br>(" + sb.toString() + ")"; } static String extractDateTime( String dateTimeMatch ) { String dateTime = null; Matcher match = DATE_YYYYMMDD_REGEX_PATTERN.matcher(dateTimeMatch); if (match.find()) { dateTime = dateTimeMatch.substring(match.start(), match.end()); dateTimeMatch = dateTimeMatch.substring(match.end()); } else { match = DATE_DDMMYYYY_REGEX_PATTERN.matcher(dateTimeMatch); if (match.find()) { dateTime = dateTimeMatch.substring(match.start(), match.end()); dateTime = dateTime.substring(6, 10) + "-" + dateTime.substring(3, 5) + "-" + dateTime.substring(0, 2); dateTimeMatch = dateTimeMatch.substring(match.end()); } } match = TIME_HHMM_REGEX_PATTERN.matcher(dateTimeMatch); if (dateTime != null && match.find()) { String time = dateTimeMatch.substring(match.start(), match.end()); time = time.replace('.', ':'); if(time.indexOf(':') == 1) { time = "0" + time; } dateTime += " " + time + "h"; } return dateTime; } static String bytesKbMb( long bytes ) { return ( bytes > 10000000 ) ? "" + bytes / (1024 * 1024) + " MB" : ( bytes > 10000 ) ? "" + bytes / 1024 + " kB" : ("" + bytes + "Bytes"); } static String tausenderPunkt( int i ) { String s = "" + i; if(i > 1000) { s = s.substring(0, s.length()-3) + "." + s.substring(s.length()-3); } return s; } } class MatchingFinderTask { Pattern[] regexPatterns; String s; public MatchingFinderTask( Pattern[] regexPatterns, String s ) { this.regexPatterns = regexPatterns; this.s = s; } } class Summierungen { int summeAnzahl; String dateTimeAeltestes; String dateTimeJuengstes; } class TabellenZeilenInhalt { String letztesDatum; String letztesLogfile; String erstesDatum; String erstesLogfile; String anzahlFehler; String fehlertext; } class TabellenInhalt { TabellenZeilenInhalt[] tabellenZeilenInhaltArr; String link; String ueberschrift; String tabellenzeileHtml; Summierungen summierungen; } class TabellenGruppe { String gruppenUeberschrift; String[] splittRegex; TabellenInhalt[] tabellenInhaltArr; TabellenGruppe( String gruppenUeberschrift, String[] splittRegex, TabellenInhalt[] tabellenInhaltArr ) { this.gruppenUeberschrift = gruppenUeberschrift; this.splittRegex = splittRegex; this.tabellenInhaltArr = tabellenInhaltArr; } }
package logfilesextract; import java.util.List; import java.util.concurrent.*; /** * Parallele Abarbeitung vieler Tasks. * Aufruf ueber: * (new TasksConcurrentExecutor( taskList, threadCount, timeoutSeconds )).run(); * Ergebnisse finden Sie in den Result-Objekten in den Tasks in der taskList. * Weitere Erlaeuterungen siehe: * http://www.torsten-horn.de/techdocs/java-concurrency.htm#TasksConcurrentExecutor.java */ public class TasksConcurrentExecutor<A,R> implements Runnable { private List<TaskDescription<A,R>> tasks; private int threadCount; private long timeoutSeconds; public TasksConcurrentExecutor( List<TaskDescription<A,R>> tasks, int threadCount, long timeoutSeconds ) { this.tasks = tasks; this.threadCount = threadCount; this.timeoutSeconds = timeoutSeconds; } @Override public void run() { ExecutorService threadPool = Executors.newFixedThreadPool( threadCount ); for( TaskDescription<A,R> td : tasks ) { threadPool.execute( new TaskRunnable<A,R>( td ) ); } threadPool.shutdown(); try { if( !threadPool.awaitTermination( timeoutSeconds, TimeUnit.SECONDS ) ) { threadPool.shutdownNow(); throw new RuntimeException( "Timeout (" + timeoutSeconds + " Sekunden) ueberschritten." ); } } catch( InterruptedException ex ) { throw new RuntimeException( ex ); } } } class TaskRunnable<A,R> implements Runnable { private TaskDescription<A,R> td; public TaskRunnable( TaskDescription<A,R> td ) { this.td = td; } @Override public void run() { // System.out.println( Thread.currentThread().getName() + ": arg=" + td.arg ); td.result = td.computable.compute( td.arg ); // System.out.println( Thread.currentThread().getName() + ": result=" + td.result ); } } /** Task-Beschreibung (Arbeitsmethode, Input-Argument und Ergebnis) */ class TaskDescription<A,R> { Computable<A,R> computable; A arg; R result; public TaskDescription( Computable<A,R> computable, A arg ) { this.computable = computable; this.arg = arg; } } /** Interface fuer die Objekte mit der Task-Arbeitsmethode */ interface Computable<A,R> { R compute( A arg ); }
Wenn es viele große Logdateien gibt, müssen viele nicht benötigte Meldungen ausgeblendet werden. Insbesondere Softwareentwickler interessieren sich weniger für administrative Meldungen, sondern eher für durch Programmierfehler verursachte Exceptions.
Im Folgenden werden Arrays gezeigt, die in obigem LogfilesExtract.java an Stelle der dort genannten Arrays ("DELETE_STRING_PART_REGEX", "DELETE_COMPLETE_REGEX", "DATETIME_REGEX_PATTERN" etc.) eingesetzt werden können.
Allerdings müssen viele Strings an die jeweiligen Gegebenheiten, Umgebungen, Versionen und Bezeichnungen angepasst werden. Sie können also lediglich als Beispiel dienen.
static final String[] DELETE_STRING_PART_REGEX = { "<<WLS Kernel>>", "<<anonymous>>", "<\\S*server\\d*>", "<ExecuteThread: '\\S*' for queue: '\\S*'>", "\\[ExecuteThread: '\\S*' for queue: '\\S*'\\]", "<Main Thread>", "<Thread-\\d*>", "_\\S{5,6}_HomeImpl@\\S{6,7}", "EJB : \\d{13}-\\d{1}$", "EJB = \\d{13}-\\d{1}$", "EJB Exception", "RuntimeException vor Eintritt in den Container entdeckt.", "Der Stacktrace als String wird in dieser neuen RuntimeException weitergereicht.", "Unexpected exception while enlisting XAConnection java.sql.SQLException: Transaction rolled back:", "java.lang.RuntimeException:", "java.rmi.RemoteException:", "javax.transaction.TransactionRolledbackException", "occurred during invocation from home:", "; nested exception is:" }; static final String[] DELETE_COMPLETE_REGEX = { "<Alert> <WebLogicServer> <Server logins have been disabled.>", "<Alert> <WebLogicServer> <Server shutdown has been requested by <WLS Kernel>>", "<Alert> <WebLogicServer> <The disabling of server logins has been requested by <WLS Kernel>>", "<Alert> <WebLogicServer> <The shutdown sequence has been initiated.>", "<Debug> <Common> <Graceful shutdown task> < < RP\\(jms/\\S*\\):parseExceptionMsg \\(\\S*\\) count = 0>", "<Debug> <Common> <Graceful shutdown task> < > RP\\(jms/\\S*\\):parseExceptionMsg \\(\\S*\\) msg = 0:javax.jms.IllegalStateException: \\[J2EE:160050\\]The JMS session pool is shutting down>", "<Debug> <Common>( <\\S*>)? < < RP\\S*:parseExceptionMsg \\(\\S*\\) count = 0>", "<Debug> <J2EE> <Setting Max Session Pool Size \\d*>", "<Debug> <JTA> <ResourceDescriptor\\[\\S*\\]: recover: recovery not completed>", "<Debug> <MessagingBridge> <Messaging bridge debugging RUNTIME! Bridge: \\S* \\(onMessage\\(\\)\\) .*", "<Debug> <RJVM> <Network Configuration Detail for Channel \"\\S*\"", "<Debug> <WTC>( <\\S*>)? <INFO: .*>", "<Info> <Cluster> <Adding \\S* with ID \\S* to cluster: \\S* view.>", "<Info> <Common>( <\\S*>)* <Created \"\\d*\" resources for pool \"\\S*\", out of which \"\\d*\" are available and \"0\" are unavailable.>", "<Info> <Common>( <\\S*>)* <Free resources in pool \"\\S*\" will be tested every \"\\d*\" seconds.>", "<Info> <Common>( <\\S*>)* <The application has disabled periodic testing of free resources in pool \".*\".>", "<Info> <Configuration Management> <The booted configuration \\S* has been backed up at \\S*.>", "<Info> <Connector>( <\\S*>)? <Initializing J2EE Connector Service>", "<Info> <Connector>( <\\S*>)? <J2EE Connector Service initialized successfully>", "<Info> <Connector>( <\\S*>)? <Testing resource adapter \"\\S*\" for viability of connection proxies.>", "<Info> <Connector>( <\\S*>)? <There were no compliance/validation errors found in the resource adapter \\S*>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Module \\S* of application \\S* is transitioning from \\S* to \\S* on server \\S*.>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Module \\S* of application \\S* successfully transitioned from \\S* to \\S* on server \\S*.>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Preparing to suspend.>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Ready to suspend.>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Shutdown complete.>", "<Info> <Deployer>( <\\S*>)? <Graceful shutdown task> <Shutting down.>", "<Info> <Deployer>( <\\S*>)? <Initialization Complete.>", "<Info> <Deployer>( <\\S*>)? <Initializing.>", "<Info> <Deployer>( <\\S*>)? <Module \\S* of application \\S* is transitioning from STATE_\\S* to STATE_\\S* on server \\S*.>", "<Info> <Deployer>( <\\S*>)? <Module \\S* of application \\S* successfully transitioned from STATE_\\S* to STATE_\\S* on server \\S*.>", "<Info> <Deployer>( <\\S*>)? <Resum[inged]*.>", "<Info> <Diagnostics>( <\\S*>)? <Initialized the Diagnostic Accessor Service.>", "<Info> <Diagnostics>( <\\S*>)? <Schedul[inged]*.* data retirement tasks as per configuration.>", "<Info> <Diagnostics>( <\\S*>)? <The Diagnostics subsystem is initializing on Server .*.>", "<Info> <Diagnostics>( <\\S*>)? <The ServerDebug service initialized successfully.>", "<Info> <DRS> <Graceful shutdown task> <Slave for DataIdentifier DataIdentifierID: \\S* unregistered from DRS.>", "<Info> <EJB>( <\\S*>)? <EJB Deployed EJB with JNDI name \\S*.>", "<Info> <EJB>( <\\S*>)? <EJB Deployed Message Driven Bean: \\S*>", "<Info> <EJB>( <\\S*>)? <EJB Deploying file: \\S*>", "<Info> <EJB>( <\\S*>)? <The EJB deployment named: \\S* is being recompiled within the WebLogic Server. Please consult the server logs if there are any errors. It is also possible to run weblogic.\\S* as a stand-alone tool to generate the required classes. The generated source files will be placed in \\S*.>", "<Info> <EJB>( <\\S*>)? <The Message-Driven EJB: \\S* has connected/reconnected to the JMS destination: \\S*.>", "<Info> <EJB>( <\\S*>)? <Graceful shutdown task> <The message-driven beans are being suspended. This may take a minute or two.>", "<Info> <EJB>( <\\S*>)? <Graceful shutdown task> <The message-driven beans have all been suspended.>", "<Info> <EJB>( <\\S*>)? <The message-driven beans are being suspended. This may take a minute or two.>", "<Info> <EJB>( <\\S*>)? <The message-driven beans have all been suspended.>", "<Info> <HTTP>( <\\S*>)? <HTTP log rotation is size based for the Web server: \\S*.>", "<Info> <HTTP>( <\\S*>)? <Initializing HTTP services.>", "<Info> <HTTP>( <\\S*>)? <Initializing Web server \\S*.>", "<Info> <HTTP>( <\\S*>)? <Initializing the Web application container.>", "<Info> <HTTP>( <\\S*>)? <\\S* is the default Web server.>", "<Info> <HTTP>( <\\S*>)? <\\[HTTP \\S*\\] \\S*>", "<Info> <HTTP>( <\\S*>)? <\\[HttpServer \\(defaultWebserver\\) name: \\S*\\] Initialized>", "<Info> <HTTP>( <\\S*>)? <\\[ServletContext\\(id=\\S*,name=\\S*,context-path=\\S*\\)\\] \\S*: .*>", "<Info> <IIOP>( <\\S*>)? <IIOP subsystem enabled.>", "<Info> <J2EE>( <\\S*>)? <Deployed : \\S*>", "<Info> <J2EE>( <\\S*>)? <J2EE service initializing.>", "<Info> <J2EE>( <\\S*>)? <Registered library Extension-Name: .*.>", "<Info> <JDBC>( <\\S*>)? <Connection for[XA ]*pool \"\\S*\" c\\S*ed.>", "<Info> <JDBC>( <\\S*>)* <Connection Pool \\S* using Driver: \".*\", Version: \".*\".>", "<Info> <JDBC>( <\\S*>)? <Connection Pool \".*\" connected to Database: \".*\", Version: .*", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* Connection Pool named .*>", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* Data Source named \\S*, JNDI Name = jdbc/\\S*.>", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* Multi Pool \\S*, algorithm type Load-Balancing.>", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* Multi Pool named \\S*.>", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* Multi Data Source named .*.>", "<Info> <JDBC>( <\\S*>)? <Creat[inged]* TX Data Source named jdbc/\\S* for Pool \\S*.>", "<Info> <JDBC>( <\\S*>)? <Data Source \\S* has been successfully created.>", "<Info> <JDBC>( <\\S*>)? <MultiPool \\S* was created with \\d* connection pools for Load-Balancing.>", "<Info> <JDBC>( <\\S*>)? <Force Suspending the JDBC service.>", "<Info> <JDBC>( <\\S*>)? <Force suspend of the JDBC service completed.>", "<Info> <JDBC>( <\\S*>)? <Graceful shutdown task> <Connection for pool \"\\S*\" closed.>", "<Info> <JDBC>( <\\S*>)? <Graceful shutdown task> <Suspend completed.>", "<Info> <JDBC>( <\\S*>)? <Graceful shutdown task> <Suspending the JDBC service.>", "<Info> <JDBC>( <\\S*>)? <Initialization complete.>", "<Info> <JDBC>( <\\S*>)? <Initialized statement cache of size \"\\d*\" for connection in pool \"\\S*\".>", "<Info> <JDBC>( <\\S*>)? <Initializing the JDBC service.>", "<Info> <JDBC>( <\\S*>)? <MultiPool \"\\S*\" was created with \\d* connection pools for Load-Balancing.>", "<Info> <JDBC>( <\\S*>)? <Resume complete.>", "<Info> <JDBC>( <\\S*>)? <Resuming the JDBC service.>", "<Info> <JDBC>( <\\S*>)? <Shutdown of the JDBC service completed.>", "<Info> <JDBC>( <\\S*>)? <Shutting down the JDBC service.>", "<Info> <JMS>( <\\S*>)? <Default connection factory .* with its JNDI name .* is started.>", "<Info> <JMS>( <\\S*>)? <Deployed \\d* default connection factories.>", "<Info> <JMS>( <\\S*>)? <Distributed destination .* is started.>", "<Info> <JMS>( <\\S*>)? <Graceful shutdown task> <JMS Server \"\\S*\" is deactivated for migration.>", "<Info> <JMS>( <\\S*>)? <Graceful shutdown task> <JMS service is suspended and in standby mode.>", "<Info> <JMS>( <\\S*>)? <Graceful shutdown task> <JMS service is suspending gracefully.>", "<Info> <JMS>( <\\S*>)? <Graceful shutdown task> <JMSServer \"\\S*\" is deactivating for migration.>", "<Info> <JMS>( <\\S*>)? <Graceful shutdown task> <JMSServer \"\\S*\" is suspend[inged]*.>", "<Info> <JMS>( <\\S*>)? <JMS Server \"\\S*\" is deactivated for migration.>", "<Info> <JMS>( <\\S*>)? <JMS server \"\\S*\" is activated.>", "<Info> <JMS>( <\\S*>)? <JMS server \"\\S*\". File store \"\\S*\". The JMS file store directory \"\\S*\" was automatically created in development mode, and its absolute path is \"\\S*\".>", "<Info> <JMS>( <\\S*>)? <JMS server \"\\S*\". Opening file store \"\\S*\", driver version \"\\S*\", synchronous write policy \"\\S*\".>", "<Info> <JMS>( <\\S*>)? <JMS service is active now.>", "<Info> <JMS>( <\\S*>)? <JMS service is initialized and in standby mode.>", "<Info> <JMS>( <\\S*>)? <JMS service is suspended and in standby mode.>", "<Info> <JMS>( <\\S*>)? <JMS service is suspending.>", "<Info> <JMS>( <\\S*>)? <JMS shutdown is complete.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\" configured no session pools.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\" is [de]*activating for migration.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\" is [resuming started suspend ing ed]*.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\", Finished scan of file store \"\\S*\" in directory \"\\S*\". Found \\d* records totalling \\d* bytes.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\", Opening file store \"\\S*\" in directory \"\\S*\". Starting scan of \\d* file[s]* totalling \\S* bytes.>", "<Info> <JMS>( <\\S*>)? <JMSServer \"\\S*\". No persistent store configured.>", "<Info> <JMS>( <\\S*>)? <Undeployed \\d* default connection factories.>", "<Info> <JMS>( <\\S*>)? <User connection factory \".*\" is started.>", "<Info> <JMX>( <\\S*>)? <Established JMX Connectivity with the Administration Server gesadmin at .*.>", "<Info> <JMX>( <\\S*>)? <JMX Connector Server started at service:jmx:.*.>", "<Info> <JTA> <Opening transaction log with driver version \"\\S*\" and synchronous write policy \"\\S*\". For information on synchronous write policies, refer to the weblogic.management.configuration.ServerMBean javadoc or console online help.>", "<Info> <Log Management>( <\\S*>)? <The log file \\S* will be rotated. Reopen the log file if tailing has stopped. This can happen on some platforms like Windows.>", "<Info> <Log Management>( <\\S*>)? <The log file has been rotated to \\S*. Log messages will continue to be logged in \\S*.>", "<Info> <Log Management>( <\\S*>)? <The Server Logging is initialized with Java Logging API implementation.>", "<Info> <Management>( <\\S*>)? <A request has been received to force shut down of the server.>", "<Info> <Management>( <\\S*>)? <Configuration changes for the domain have been saved to the repository.>", "<Info> <Management>( <\\S*>)? <Java system properties are defined as follows:", "<Info> <Management>( <\\S*>)? <The application poller has started for the \\S* server.>", "<Info> <Management>( <\\S*>)? <Version: WebLogic Server .*>", "<Info> <Messaging>( <\\S*>)? <The messaging kernel .*", "<Info> <messaging.interception>( <\\S*>)? <Initializing message interception service>", "<Info> <MessagingBridge> <Bridge \"\\S*\" is configured to disallow degradation of its quality of service in cases where the configured quality of service is unreachable.>", "<Info> <MessagingBridge> <Bridge \"\\S*\" is configured to work in \"Exactly-once\" mode, and it is actually working in \"Exactly-once\" mode.>", "<Info> <MessagingBridge> <Bridge \"\\S*\" is obtaining connections to the two adapters.>", "<Info> <MessagingBridge> <Bridge \\S* successfully found the adapters that are configured for it.>", "<Info> <MessagingBridge> <The bridge \\S* has started transferring messages.>", "<Info> <MessagingBridge> <The messaging bridge \\S* has been successfully deployed.>", "<Info> <MessagingBridge> <The messaging bridge \\S* has successfully shut down.>", "<Info> <RJVM>( <\\S*>)? <Network Configuration for Channel \"\\S*\"", "<Info> <SAFService>( <\\S*>)? <SAF Service has been .*.>", "<Info> <Security>( <\\S*>)? <Initializing Authorizer provider using LDIF template file \\S*.>", "<Info> <Security>( <\\S*>)? <Initializing RoleMapper provider using LDIF template file \\S*.>", "<Info> <Security>( <\\S*>)? <No pre-WLS \\S* Keystore providers are configured for server \\S* for security realm \\S*.>", "<Info> <Security>( <\\S*>)? <Parsing class \\S*.>", "<Info> <Security>( <\\S*>)? <Starting OpenJPA \\S*>", "<Info> <Security>( <\\S*>)? <The \\S* provider has preexisting LDAP data.>", "<Info> <Security>( <\\S*>)? <The (Authorizer|RoleMapper) provider has had its LDIF information loaded from: \\S*>", "<Info> <Server>( <\\S*>)* <Adding address: \\S* to licensed client list>", "<Info> <Server>( <\\S*>)? <Channel Service initialized.>", "<Info> <Server>( <\\S*>)? <Dynamic Listener Service initialized.>", "<Info> <Server>( <\\S*>)? <The administration protocol is \"\\S*\" and is now configured.>", "<Info> <Server>( <\\S*>)? <The protocol \".*\" is now configured.>", "<Info> <Server>( <\\S*>)? <The server \".*\" connected to this server.>", "<Info> <ServletContext-/lang>( <\\S*>)? <JspServlet: .*>", "<Info> <Socket>( <\\S*>)? <Allocating \\d* reader threads.>", "<Info> <Socket>( <\\S*>)? <ListenThread.Default> <Allocating \\d* reader threads.>", "<Info> <Socket>( <\\S*>)? <ListenThread.Default> <Native IO Enabled.>", "<Info> <Socket>( <\\S*>)? <ListenThread.Default> <NTSocketMuxer was built on .*", "<Info> <Socket>( <\\S*>)? <Native IO Enabled.>", "<Info> <Socket>( <\\S*>)? <PosixSocketMuxer was built on .*>", "<Info> <Socket>( <\\S*>)? <System has file descriptor limits of - soft: \\S*, hard: \\S*>", "<Info> <Socket>( <\\S*>)? <Using effective file descriptor limit of: \\S* open sockets/files.>", "<Info> <Store>( <\\S*>)? <Persistent store \\S* opened: directory=.* writePolicy=.*>", "<Info> <WebLogicServer>( <\\S*>)? <ListenThread.Default> <Adding address: \\S* to licensed client list>", "<Info> <WebLogicServer>( <\\S*>)? <Loaded License : \\S*>", "<Info> <WebLogicServer>( <\\S*>)? <Server shutdown is commencing NOW and is irreversible.>", "<Info> <WebLogicServer>( <\\S*>)? <Shutdown has completed.>", "<Info> <WebLogicServer>( <\\S*>)? <Starting WebLogic Server with BEA JRockit\\(R\\) Version .* from BEA Systems, Inc.>", "<Info> <WebLogicServer>( <\\S*>)? <Stopping execute threads.>", "<Info> <WebLogicServer>( <\\S*>)? <WebLogic Server \"\\S*\" version:", "<Info> <WebLogicServer>( <\\S*>)? <\\[STUCK\\] ExecuteThread: '\\S*' for queue: 'weblogic.kernel.Default \\(self-tuning\\)' has become \"unstuck\".>", "<Info> <WebService>( <\\S*>)? <Graceful shutdown task> <Web Service reliable agents are suspended.>", "<Info> <WebService>( <\\S*>)? <The server does not support reliable SOAP messaging.>", "<Info> <WebService>( <\\S*>)? <Web Service reliable agents are [started suspended shut down on the server]*.>", "<Info> <WorkManager>( <\\S*>)? <Creating WorkManager from \\S* WorkManagerMBean for application \\S*>", "<Info> <WorkManager>( <\\S*>)? <Initializing self-tuning thread pool>", "<Info> <XML>( <\\S*>)? <Initializing XMLRegistry.>", "<Notice> <Cluster>( <\\S*>)? <Joining cluster \\S* on \\S*>", "<Notice> <Cluster>( <\\S*>)? <Listening for announcements from cluster .*>", "<Notice> <Cluster>( <\\S*>)? <Waiting to synchronize with other running members of \\S*.>", "<Notice> <HTTP>( <\\S*>)? <Graceful shutdown task> <There are no active sessions. The Web service is ready to suspend.>", "<Notice> <JTA>( <\\S*>)? <Creating new transaction log file \\[\\S*\\].>", "<Notice> <Log Management>( <\\S*>)? <The server initialized the domain log broadcaster successfully. Log messages will now be broadcasted to the domain log.>", "<Notice> <Log Management>( <\\S*>)? <The server log file \\S* is opened. All server side log events will be written to this file.>", "<Notice> <Security>( <\\S*>)? <Loading the identity certificate stored under the alias DemoIdentity from the jks keystore file \\S*.>", "<Notice> <Security>( <\\S*>)? <Loading the private key stored under the alias DemoIdentity from the jks keystore file \\S*.>", "<Notice> <Security>( <\\S*>)? <Loading trusted certificates from the jks keystore file \\S*.>", "<Notice> <Security>( <\\S*>)? <Security initializing using security realm \\S*.>", "<Notice> <Server>( <\\S*>)? <Channel \\S* is now listening on \\S* for protocols .*>", "<Notice> <WebLogicServer>( <\\S*>)? <Following extensions directory contents added to the end of the classpath:.*", "<Notice> <WebLogicServer>( <\\S*>)? <Graceful shutdown task> <Server state changed to SUSPENDING>", "<Notice> <WebLogicServer>( <\\S*>)? <ListenThread.Default> <Thread \"ListenThread.Default\" listening on port \\d*, ip address \\S*>", "<Notice> <WebLogicServer>( <\\S*>)? <Server started in RUNNING mode>", "<Notice> <WebLogicServer>( <\\S*>)? <Server state changed to (STANDBY|STARTING|RUNNING|RESUMING|ADMIN)>", "<Notice> <WebLogicServer>( <\\S*>)? <Started WebLogic \\S* Server \"\\S*\" for domain \"\\S*\" running in \\S* Mode>", "<Notice> <WebLogicServer>( <\\S*>)? <Starting WebLogic \\S* Server \"\\S*\" for domain \"\\S*\">", "<Warning> <Common>( <\\S*>)? <Graceful shutdown task> <Recreated \"\\d*\" out of \"\\d*\" resources for pool \"\\S*\".>", "<Warning> <EJB>( <\\S*>)? <Call-by-reference is not enabled for the EJB '\\S*'. The server will have better performance if it is enabled. To enable call-by-reference, set the enable-call-by-reference element to True in the weblogic-ejb-jar.xml deployment descriptor for this EJB.>", "<Warning> <EJB>( <\\S*>)? <The Remote interface method: '.* throws \\S*' in EJB '\\S*' contains a parameter of type: '\\S*' which is not Serializable. Though the EJB '\\S*' has call-by-reference set to false, this parameter is not Serializable and hence will be passed by reference. A parameter can be passed using call-by-value only if the parameter type is Serializable.>", "<Warning> <JTA>( <\\S*>)? <Graceful shutdown task> <An attempt was made to manually migrate the Transaction Recovery Service of the current server away from it while it is still active.>" }; static final String[] SPLITT_REGEX_NULLPOINTER_ETC = { "NullPointerException", "IndexOutOfBoundsException", "NoClassDefFoundError", "ClassNotFoundException" }; static final String[] SPLITT_REGEX_DB = { "ORA-00001: Unique Constraint .* (violated|verletzt)", "ORA-00018: maximum number of sessions exceeded", "ORA-00018: Höchstzahl der Sessions überschritten", "ORA-00054: resource busy and acquire with NOWAIT specified", "ORA-00060: deadlock", "ORA-00604: Fehler auf rekursiver SQL-Ebene 1", "ORA-00942: Tabelle oder View nicht vorhanden", "ORA-00942: table or view does not exist", "ORA-01001: invalid cursor", "ORA-01001: Ungültiger Cursor", "ORA-01002: fetch out of sequence", "ORA-01002: FETCH auf ungültigen oder geschlossenen Cursor", "ORA-01006: bind variable does not exist", "ORA-01008: not all variables bound", "ORA-01008: Nicht allen Variablen ist ein Wert zugeordnet", "ORA-01033: ORACLE initialization or shutdown in progress", "ORA-01092: ORACLE instance terminated", "ORA-01400: Einfügen von NULL in \\(.*\\) nicht möglich", "ORA-01438: value larger than specified precision allowed", "ORA-01438: Wert größer als die angegebene Gesamststellenzahl, die für diese Spalte zulässig ist", "ORA-01461: can bind a long value only for insert into a long column", "ORA-01461: Ein LONG-Wert kann nur zur Einfügung in eine LONG-Spalte gebunden werden", "ORA-01591: lock held by in-doubt distributed transaction", "ORA-01591: Sperre wird von unterbrochener, verteilter Transaktion .* aufrecht gehalten", "ORA-01722: invalid number", "ORA-02049: timeout: distributed transaction waiting for lock", "ORA-02049: Timeout: verteilte Transaktion wartet auf Sperre", "ORA-02289: Sequence ist nicht vorhanden", "ORA-02290: CHECK-Constraint \\(.*\\) verletzt", "ORA-02291: Integritäts-Constraint \\(.*\\) verletzt - übergeordneter Schlüssel nicht gefunden", "ORA-02292: integrity constraint", "ORA-02292: Integritäts-Constraint .* verletzt", "ORA-03113: end-of-file on communication channel", "ORA-03135: connection lost contact", "ORA-06550: .* PL/SQL: Statement ignored", "ORA-08102: Indexschlüssel nicht gefunden", "ORA-12505, TNS:listener does not currently know of SID given in connect descriptor", "ORA-12528, TNS:listener: all appropriate instances are blocking new connections", "ORA-12805: parallel query server died unexpectedly", "ORA-12899: value too large for column", "ORA-12899: Wert zu groß für Spalte", "ORA-20000: procedure version not found in database", "ORA-20000: step name.* is not outstanding", "ORA-20003: \\(SWERROR\\) Procedure details not found in database for procedure", "ORA-27083: waiting for async I/Os failed", "ORA-29701: unable to connect to cluster manager", "ORA-06512:", " ORA-\\d*", "ResourceDeadException: .*Could not create pool connection.* (.*cannot establish the connection)|(.*Connection refused)|(.*Connection timed out)", "JDBCException.* Getrennte Verbindung", "JDBCException.* Cannot open connection", "JDBCException.* Cannot obtain XAConnection .*weblogic.*Resource.*Exception", "JDBCException.* OALL8 befindet sich in einem inkonsistenten Status", "(JDBCException|SQLException).* E/A-Exception: Socket closed", "(JDBCException|SQLException).* Keine weiteren Daten aus Socket zu lesen", "NestedDatabaseConstraintViolationException: Keine weiteren Daten aus Socket zu lesen", "Keine weiteren Daten aus Socket zu lesen", "SQLException: E/A-Exception: The Network Adapter could not establish the connection", "exception while creating connection .*: E/A-Exception: The Network Adapter could not establish the connection", "exception while creating connection .*: The application requester cannot establish the connection. \\(Connection reset\\)", "HeuristicMixedException: \\(weblogic.jdbc.wrapper.JTSXAResourceImpl, HeuristicHazard, \\(javax.transaction.xa.XAException: Connection has been administratively disabled. Try later.\\)\\)", "SQLException: Connection has been administratively disabled. Try later." }; static final String[] SPLITT_REGEX_TIMEOUT = { "Timeout|TimedOut|timed out", "weblogic.kernel.Default .* has been busy for \"\\d*\" seconds working on the request .*, which is more than the configured time .* of \"600\" seconds", }; static final String[] SPLITT_REGEX_SPEZIELL = { "OutOfMemoryError", "StaleObjectStateException: Row was updated or deleted by another transaction", "ERROR de.meinefirma.meinprojekt.meinpackage.subpackageabc.spezpackage1", "ERROR de.meinefirma.meinprojekt.meinpackage.subpackageabc.spezpackage2", "ERROR org.hibernate" }; static final TabellenGruppe[] TABELLEN_GRUPPEN = { new TabellenGruppe("Nullpointer, IndexOutOfBoundsException, NoClassDefFoundError", SPLITT_REGEX_NULLPOINTER_ETC, null), new TabellenGruppe("Datenbank-Exceptions", SPLITT_REGEX_DB, null), new TabellenGruppe("Time-outs", SPLITT_REGEX_TIMEOUT, null), new TabellenGruppe("Spezielle Fehler", SPLITT_REGEX_SPEZIELL, null), new TabellenGruppe("Restliche Fehler (uebrig nach obigen RegEx-Filtern)", null, null) }; static final Pattern[] DATETIME_REGEX_PATTERN = { Pattern.compile("^\\d{4}\\-\\d{1,2}\\-\\d{1,2} \\d{1,2}\\:\\d{2}\\:\\d{2}\\,\\d* "), Pattern.compile("^=<\\d*\\.\\d*\\.\\d* \\d*\\:\\d*\\:\\d*\\,\\d*>"), Pattern.compile("^=\\[\\d*\\.\\d*\\.\\d* \\d*\\:\\d*\\:\\d*\\,\\d*\\]"), Pattern.compile("^####<\\d*.\\d*.\\d* \\d*.\\d* Uhr \\S*>") };