我必须解析一大堆日志文件,它们采用以下格式。
SOME SQL STATEMENT/QUERY
DB20000I The SQL command completed successfully.
SOME OTHER SQL STATEMENT/QUERY
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command.
编辑1:前3行(包括空行)表示SQL语句成功执行,而后三行表示语句及其引起的异常。 darioo 下面的回复,建议使用grep
而不是Java,可以很好地用于单行SQL语句。
编辑2:但是,SQL语句/查询可能不一定是单行。有时这是一个很大的CREATE PROCEDURE...END PROCEDURE
块。只使用Unix命令可以解决这个问题吗?
现在我需要解析整个日志文件并选择所有出现的对象(SQL语句+错误)并将它们写在一个单独的文件中。
请告诉我该怎么做!
答案 0 :(得分:4)
我的回答将是非基于Java的,因为这是一个可以用更简单的方式解决的问题的典型例子。
您只需要工具grep
。如果您使用的是Windows,则可以找到它here。
假设您的日志位于文件log.txt
中,您问题的解决方案就是一个问题:
grep -hE --before-context 1 "^DB2[0-9]+E" log.txt > filtered.txt
说明:
-h
- 不打印文件名-E
- 正则表达式搜索--before-context 1
- 这将在找到错误消息之前打印一行(如果所有SQL查询都在一行中,这将有效)^DB2[0-9]+E
- 搜索以“DB2”开头的行,有一些数字并以“E”结尾上面的表达式将在名为filtered.txt
的新文件中打印您需要的每一行。
更新:经过一番摸索后,我设法使用标准的* nix实用程序获得了所需的功能。小心,它不漂亮。最后的表达:
grep -nE "^DB2[0-9]+" log.txt | cut -f 1 -d " " | gawk "/E$/{y=$0;print x, y};{x=$0}" | sed -e "s/:DB2[[:digit:]]\+[IE]//g" | gawk "{print \"sed -n \\\"\" $1+1 \",\" $2 \"p\\\" log.txt \"}" | sed -e "s/$/ >> filtered.txt/g" > run.bat
说明:
grep -nE "^DB2[0-9]+" log.txt
- 打印以DB2...
开头的行及其行号。例如:6:DB20000I The SQL command completed successfully. 12:DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command. 19:DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command. 26:DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command. 34:DB20000I The SQL command completed successfully. 41:DB20000I The SQL command completed successfully. 47:DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command. 54:DB20000I The SQL command completed successfully.
cut -f 1 -d " "
- 仅打印“第一列”,即删除错误消息后的所有内容。例如:6:DB20000I 12:DB21034E 19:DB21034E 26:DB21034E 34:DB20000I 41:DB20000I 47:DB21034E 54:DB20000I
gawk "/E$/{y=$0;print x, y};{x=$0}"
- 对于以“E”结尾的每一行(错误行),在它之前打印行,然后打印错误行。例如:6:DB20000I 12:DB21034E 12:DB21034E 19:DB21034E 19:DB21034E 26:DB21034E 41:DB20000I 47:DB21034E
sed -e "s/:DB2[[:digit:]]\+[IE]//g"
- 删除冒号和错误消息,只留下行号。例如:6 12 12 19 19 26 41 47
gawk "{print \"sed -n \\\"\" $1+1 \",\" $2 \"p\\\" log.txt \"}"
- 在sed处理的行上方格式化,并将第一行号递增1。例如:sed -n "7,12p" log.txt sed -n "13,19p" log.txt sed -n "20,26p" log.txt sed -n "42,47p" log.txt
sed -e "s/$/ >> filtered.txt/g"
- 将>> filtered.txt
附加到行,以附加到最终输出文件。例如:sed -n "7,12p" log.txt >> filtered.txt sed -n "13,19p" log.txt >> filtered.txt sed -n "20,26p" log.txt >> filtered.txt sed -n "42,47p" log.txt >> filtered.txt
> run.bat
- 最后,将最后一行打印到名为run.bat
执行此文件后,您想要的内容将显示在filtered.txt
。
更新2 :
这是另一个适用于Ubuntu的版本(以前的版本是在Windows上编写的):
grep -nE "^DB2[0-9]+" log.txt | cut -f 1 -d " " | gawk '/E/{y=$0;print x, y};{x=$0}' | sed -e "s/:DB2[[:digit:]]\+[IE]//g" | gawk '{print "sed -n \""$1+1" ,"$2 "p\" log.txt" }' | sed -e "s/$/ >> filtered.txt/g" > run.sh
以前的版本有两件事情无效:
gawk '/E$/'
无法正常工作(它无法识别E在行尾),所以我只是放/E/
,因为E
不会在其他地方找到了。"
因为不喜欢双引号而被转换为'
gawk;之后,在最后一个gawk表达式中引用被修改答案 1 :(得分:1)
假设您正在寻找一个非空行的块,后跟一个空行,然后是一个非空行的块,其中第一行以DB
开头,然后尝试:
Pattern regex = Pattern.compile(
"(?:.+\\n)+ # Match one or more non-blank lines\n" +
"\\n # Match one blank line\n" +
"DB(?:.+\\n)+ # Match one or more non-blank lines, the first one starting with DB",
Pattern.COMMENTS);
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
// matched text: regexMatcher.group()
// match start: regexMatcher.start()
// match end: regexMatcher.end()
}
这假定每个匹配之间有一个空行,并假定Unix行结尾。如果是DOS / Windows文件,则将\\n
替换为\\r\\n
。
答案 2 :(得分:1)
就个人而言,我会略微区别。我没有找到所有的错误,而是取消了所有的成功。
这样的事情:
(?:.+\r\n)+\r\n+DB2.+I(?:.+\r\n)+
在代码中(只需使用日志的File对象调用processLog):
private void openAndProcessLog(){
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(this);
if (chooser.getSelectedFile() != null) {
processLog(chooser.getSelectedFile());
}
}
private void processLog(File logfile){
String originalLog = readFile(logfile);
String onlyFailures = removeAllSuccessFull(originalLog);
System.out.println(onlyFailures);
}
private String readFile(File file) {
String ret = "";
try {
BufferedReader in = new BufferedReader(
new FileReader(file));
StringWriter out = new StringWriter();
char[] buf = new char[10000];
int n;
while( (n = in.read(buf)) >= 0 ) {
out.write(buf, 0, n);
}
ret = out.toString();
} catch (IOException e) {
}
return ret;
}
private String removeAllSuccessFull(String text) {
String sep = System.getProperty("line.separator");
Pattern regex = Pattern.compile(
"(?:.+"+sep+")+"+sep+"+DB2.+I(?:.+"+sep+")+");
return regex.matcher(text).replaceAll("");
}
答案 3 :(得分:1)
尝试一下:
#!/usr/bin/awk -f
$1 ~ /^DB.*I$/ {lines=""; nl=""; next} # discard successes
$1 ~ /^DB.*E$/ {print lines; print $0; print "-----"; lines=""; next} # print error blocks
$0 !~ /^$/ { lines = lines nl $0; nl="\n" } # accumulate lines in block
如果您不想删除空白行,请删除$0 !~ /^$/
。
像这样运行:
./script.awk inputfile
答案 4 :(得分:-1)
如果你在windows上使用linux shell或cygwin,我建议你使用grep with flags -a(after)和-b(before):
grep -a 2 "The SQL command completed successfully" mylog.log
将在与给定模式匹配的行之后打印2行。
如果您想自己编写,我建议您执行以下操作:
迭代线条,直到遇到符合您图案的线条。然后继续读N行(例如2行)并在某处打印。然后继续阅读。