是否有任何工具可以提取日志文件中出现的堆栈跟踪列表,并且可能会计算唯一的堆栈跟踪列表?
编辑:我会做一些非基于GUI的事情,并在后台运行并提供某种报告。我从很多环境中收集了很多日志,只是想快速浏览一下。
答案 0 :(得分:16)
这是一个快速而又脏的grep表达式...如果你使用log4j这样的记录器,那么异常的第一行通常会包含WARN
或ERROR
,下一行将包含Exception名称和可选的消息,然后后续堆栈跟踪将以下列之一开头:
"\tat"
(tab + at)"Caused by: "
"\t... <some number> more"
(这些行表示堆栈中的帧数未在“由...引起”异常中显示)我们希望获得上述所有行,因此grep表达式为:
grep -P "(WARN|ERROR|^\tat |Exception|^Caused by: |\t... \d+ more)"
它假设一个Exception类总是包含单词Exception
,这可能是也可能不是,但毕竟这是快速而又脏的。
根据具体情况进行调整。
答案 1 :(得分:13)
你可以很容易地自己写这个。这是模式:
"\n\tat "
(即新行,制表符,at
,空白)这是堆栈跟踪之外非常罕见的字符串。现在您需要做的就是找到不以\t
开头的第一行来查找堆栈跟踪的结尾。您可能希望在此之后跳过1-3行来捕获链式异常。
在堆栈跟踪的第一行之前添加几行(比如说10或50)以获得一些上下文。
答案 2 :(得分:10)
我用Python编写了一个工具。它设法分割两个堆栈跟踪,即使它们在日志中相互靠近。
#!/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]
答案 3 :(得分:2)
我提出了以下Groovy脚本。当然,它根据我的需求进行了很大调整,但我希望它可以帮到某些人。
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
}
答案 4 :(得分:1)
这是一个很好的代码 - http://www.techiedelight.com/java-program-search-exceptions-huge-log-file-on-server/
它基本上逐行读取日志文件,并在每一行中搜索关键字“Exception”。一旦找到,它将在单独的输出文件中打印接下来的10行(异常跟踪)。
答案 5 :(得分:0)
我使用Baretail。