Outil pour extraire des traces de pile java à partir de fichiers journaux [fermé]
Existe-t-il un outil qui peut extraire une liste de traces de pile apparaissant dans le fichier journal et probablement compter les traces uniques?
EDIT : Je preffer quelque chose qui n'est pas basé sur L'interface graphique et être exécuté en arrière-plan et donner une sorte de rapport. J'ai beaucoup de journaux rassemblés à partir de plusieurs environnements et je voudrais juste obtenir un aperçu rapide.
6 réponses
Voici une expression grep rapide et sale... si vous utilisez un enregistreur tel que log4j, la première ligne de l'exception contiendra généralement WARN
ou ERROR
, la ligne suivante contiendra le nom de L'Exception et éventuellement un message, puis la trace de pile suivante commencera par l'une des opérations suivantes:
-
"\tat"
(tab + at) "Caused by: "
-
"\t... <some number> more"
(ce sont les lignes qui indiquent le nombre d'images dans la pile non représenté dans un " causé par" exception) - un nom D'Exception (et peut-être un message) avant la pile
Nous voulons obtenir toutes les lignes ci-dessus, donc l'expression grep est:
grep -P "(WARN|ERROR|^\tat |Exception|^Caused by: |\t... \d+ more)"
Il suppose qu'une classe D'Exception contient toujours le mot Exception
qui peut ou non être vrai, mais c'est rapide et sale après tout.
Ajuster au besoin pour votre cas spécifique.
Vous pouvez écrire cela vous-même assez facilement. Voici le modèle:
- Ouvrir le fichier
- recherchez la chaîne
"\n\tat "
(c'est une nouvelle ligne, tab,at
, vide) c'est une chaîne assez rare en dehors des traces de pile.
Maintenant tout ce que vous devez faire est de trouver la première ligne qui ne commence pas avec \t
pour trouver la fin de la trace de la pile. Vous pouvez ignorer 1-3 lignes après cela pour attraper les exceptions enchaînées.
Plus ajoutez quelques lignes (disons 10 ou 50) avant première ligne de la trace de la pile pour obtenir du contexte.
J'ai écrit un outil en Python. Il parvient à diviser deux traces de pile même si elles viennent juste après l'autre dans le journal.
#!/usr/bin/env python
#
# Extracts exceptions from log files.
#
import sys
import re
from collections import defaultdict
REGEX = re.compile("(^\tat |^Caused by: |^\t... \\d+ more)")
# Usually, all inner lines of a stack trace will be "at" or "Caused by" lines.
# With one exception: the line following a "nested exception is" line does not
# follow that convention. Due to that, this line is handled separately.
CONT = re.compile("; nested exception is: *$")
exceptions = defaultdict(int)
def registerException(exc):
exceptions[exc] += 1
def processFile(fileName):
with open(fileName, "r") as fh:
currentMatch = None
lastLine = None
addNextLine = False
for line in fh.readlines():
if addNextLine and currentMatch != None:
addNextLine = False
currentMatch += line
continue
match = REGEX.search(line) != None
if match and currentMatch != None:
currentMatch += line
elif match:
currentMatch = lastLine + line
else:
if currentMatch != None:
registerException(currentMatch)
currentMatch = None
lastLine = line
addNextLine = CONT.search(line) != None
# If last line in file was a stack trace
if currentMatch != None:
registerException(currentMatch)
for f in sys.argv[1:]:
processFile(f)
for item in sorted(exceptions.items(), key=lambda e: e[1], reverse=True):
print item[1], ":", item[0]
Je suis venu avec le script Groovy suivant. Il est, bien sûr, très adapté à mes besoins, mais j'espère qu'il aide quelqu'un.
def traceMap = [:]
// Number of lines to keep in buffer
def BUFFER_SIZE = 100
// Pattern for stack trace line
def TRACE_LINE_PATTERN = '^[\\s\\t]+at .*$'
// Log line pattern between which we try to capture full trace
def LOG_LINE_PATTERN = '^([<#][^/]|\\d\\d).*$'
// List of patterns to replace in final captured stack trace line
// (e.g. replace date and transaction information that may make similar traces to look as different)
def REPLACE_PATTERNS = [
'^\\d+-\\d+\\@.*?tksId: [^\\]]+\\]',
'^<\\w+ \\d+, \\d+ [^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <',
'^####<[^>]+?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <[^>]*?> <',
'<([\\w:]+)?TransaktionsID>[^<]+?</([\\w:]+)?TransaktionsID>',
'<([\\w:]+)?TransaktionsTid>[^<]+?</([\\w:]+)?TransaktionsTid>'
]
new File('.').eachFile { File file ->
if (file.name.contains('.log') || file.name.contains('.out')) {
def bufferLines = []
file.withReader { Reader reader ->
while (reader.ready()) {
def String line = reader.readLine()
if (line.matches(TRACE_LINE_PATTERN)) {
def trace = []
for(def i = bufferLines.size() - 1; i >= 0; i--) {
if (!bufferLines[i].matches(LOG_LINE_PATTERN)) {
trace.add(0, bufferLines[i])
} else {
trace.add(0, bufferLines[i])
break
}
}
trace.add(line)
if (reader.ready()) {
line = reader.readLine()
while (!line.matches(LOG_LINE_PATTERN)) {
trace.add(line)
if (reader.ready()) {
line = reader.readLine()
} else {
break;
}
}
}
def traceString = trace.join("\n")
REPLACE_PATTERNS.each { pattern ->
traceString = traceString.replaceAll(pattern, '')
}
if (traceMap.containsKey(traceString)) {
traceMap.put(traceString, traceMap.get(traceString) + 1)
} else {
traceMap.put(traceString, 1)
}
}
// Keep the buffer of last lines.
bufferLines.add(line)
if (bufferLines.size() > BUFFER_SIZE) {
bufferLines.remove(0)
}
}
}
}
}
traceMap = traceMap.sort { it.value }
traceMap.reverseEach { trace, number ->
println "-- Occured $number times -----------------------------------------"
println trace
}
Voici un bon code qui fait la même chose - http://www.techiedelight.com/java-program-search-exceptions-huge-log-file-on-server/
Il lit essentiellement le fichier journal ligne par ligne et recherche le mot-clé "Exception" dans chaque ligne. Une fois trouvé, il imprimera les 10 lignes suivantes (trace d'exception) dans un fichier de sortie séparé.