Regex 如何从日志文件中过滤错误,但过滤错误警报?
目标是获得如下输出,其中包含每个文件的文件名和错误计数Regex 如何从日志文件中过滤错误,但过滤错误警报?,regex,logging,grep,pcre,Regex,Logging,Grep,Pcre,目标是获得如下输出,其中包含每个文件的文件名和错误计数 /var/log/file2.log:5 /var/log/file3.log:7 /var/log/file5.log:3 /var/log/file7.log:2 假设有许多名为“*.log”的日志文件,并且所有文件的格式如下所示 2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.ClassAAAA : real error 2021-03-16 01:01:
/var/log/file2.log:5
/var/log/file3.log:7
/var/log/file5.log:3
/var/log/file7.log:2
假设有许多名为“*.log
”的日志文件,并且所有文件的格式如下所示
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.ClassAAAA : real error
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.ClassAAAA : message
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.LibBB : real error
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.LibBB : message
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.ClassCCCCCC : real error
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.ClassCCCCCC : real error
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.ClassCCCCCC : message
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.ClassD : false alert
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.ClassD : message
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.LibEEE : false alert
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.LibEEE : message
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.LibFFFFF : false alert
2021-03-16 01:01:01.001 ERROR 1234 --- [main] com.example.LibFFFFF : false alert
2021-03-16 01:01:01.001 INFO 1234 --- [main] com.example.LibFFFFF : message
主要问题是,存在一些已知的错误警报,这些警报不应被计算在内
例如,我们希望通过以下命令统计除ClassD
、LibEEE
和LibFFFFF
以外的任何类记录的错误
grep -Pc '^.* ERROR .*((?<!(ClassD|LibEEE|LibFFFFF)).)*$' *.log | grep -v :0
如果有效,则上述示例日志段的计数将为4,分别由ClassAAAA
、LibBB
和classcccc
记录
更新
衷心感谢大家抽出时间分享您的想法。我之所以进入lookbehind的think集合,是因为我想先用“\s*:
”来限定类名,但最终还是忽略了空格和冒号
虽然目标现在可以实现,但好奇的是-在这种情况下可以使用lookback吗?这应该是awk的一项任务,请您尝试以下内容。 使用GNU
awk
中显示的样本编写和测试。您可以将多个文件传递给此命令,它将逐个文件打印(文件名和错误计数与所示示例相同)
说明:添加上述内容的详细说明
awk ' ##Starting awk program from here.
BEGIN{ OFS=":" } ##Setting OGFS to colon in BEGIN section of this program.
FNR==1{ ##Checking condition if this is first line then do following.
if(count){ ##Checking if count is not null then.
print FILENAME,count ##Printing file name with OFS and count value here.
}
count=0 ##Setting count to 0 here.
}
/ERROR/ && !/ClassD|LibEEE|LibFFFFF/{ ##checking condition if line does not contain ClassD, LibEEE and LibFFFFF then do following.
count++ ##Increase count with 1 here.
}
END{ ##Starting END block of this program from here.
if(count){ ##Checking if count is not null then.
print FILENAME,count ##Printing file name with OFS and count value here.
}
}
' *.log ##Passing all .log files to program here.
在PCRE regex lookbehind中,顶层只能有不同长度的模式:
(?可以,但(?不可以,因为替换在捕获组中
实际上,在这里,您可以使用前瞻,其中备选方案的长度无关紧要:
grep-Pc'\sERROR(?)*(ClassD | LibEEE | LibFFFFF))\s'| grep-v:0
看
这个图案很相配
\s
-任何空白
错误
-子字符串
(?!.*(ClassD | LibEEE | LibFFFFF))
-一种负前瞻,它尽可能多地匹配除换行符以外的任何零个或多个字符,后跟组中的一个单词
\s
-任何空白
要打印正确的文件名:
awk '
FNR==1 {
if (c)
print f,c
c=0
f=FILENAME
}
$3=="ERROR" && $7!~/ClassD|LibEEE|LibFFFFF/ {
++c
}
END {if (c) print f,c}
' *.log
或键入更少但占用更多内存:
awk '
$3=="ERROR" && $7!~/ClassD|LibEEE|LibFFFFF/ {
++c[FILENAME]
}
END {for (f in c) print f,c[f]}
' *.log
使用GNU awk作为结束文件:
$ awk '
($3=="ERROR") && $7 !~ /\.(ClassD|Lib(EEE|FFFFF))$/ { c++ }
ENDFILE { printf "%s:%d\n", FILENAME, c; c=0 }
' file*
file:4
预期的匹配是什么?为什么不使用负前瞻而不是负前瞻?那么为什么使用前瞻?使用前瞻:grep-Pc'\sERROR(?。*(ClassD | LibEEE | LibFFFFF))\s'| grep-v:0
look-behind交替应该具有相同的长度。如果您可以只使用LibFFF
而不是LibFFF
来处理,那么^.*ERROR.*(?就可以了。您询问是否可以使用lookbehind。是的,但在像您这样的情况下,使用regex时,lookahead更自然。
awk '
$3=="ERROR" && $7!~/ClassD|LibEEE|LibFFFFF/ {
++c[FILENAME]
}
END {for (f in c) print f,c[f]}
' *.log
$ awk '
($3=="ERROR") && $7 !~ /\.(ClassD|Lib(EEE|FFFFF))$/ { c++ }
ENDFILE { printf "%s:%d\n", FILENAME, c; c=0 }
' file*
file:4