]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/build_tools/error_filter.py
1 # Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 # This source code is licensed under both the GPLv2 (found in the
3 # COPYING file in the root directory) and Apache 2.0 License
4 # (found in the LICENSE.Apache file in the root directory).
6 '''Filter for error messages in test output:
7 - Receives merged stdout/stderr from test on stdin
8 - Finds patterns of known error messages for test name (first argument)
9 - Prints those error messages to stdout
12 from __future__
import absolute_import
13 from __future__
import division
14 from __future__
import print_function
15 from __future__
import unicode_literals
21 class ErrorParserBase(object):
22 def parse_error(self
, line
):
23 '''Parses a line of test output. If it contains an error, returns a
24 formatted message describing the error; otherwise, returns None.
25 Subclasses must override this method.
27 raise NotImplementedError
30 class GTestErrorParser(ErrorParserBase
):
31 '''A parser that remembers the last test that began running so it can print
32 that test's name upon detecting failure.
34 _GTEST_NAME_PATTERN
= re
.compile(r
'\[ RUN \] (\S+)$')
35 # format: '<filename or "unknown file">:<line #>: Failure'
36 _GTEST_FAIL_PATTERN
= re
.compile(r
'(unknown file|\S+:\d+): Failure$')
39 self
._last
_gtest
_name
= 'Unknown test'
41 def parse_error(self
, line
):
42 gtest_name_match
= self
._GTEST
_NAME
_PATTERN
.match(line
)
44 self
._last
_gtest
_name
= gtest_name_match
.group(1)
46 gtest_fail_match
= self
._GTEST
_FAIL
_PATTERN
.match(line
)
48 return '%s failed: %s' % (
49 self
._last
_gtest
_name
, gtest_fail_match
.group(1))
53 class MatchErrorParser(ErrorParserBase
):
54 '''A simple parser that returns the whole line if it matches the pattern.
56 def __init__(self
, pattern
):
57 self
._pattern
= re
.compile(pattern
)
59 def parse_error(self
, line
):
60 if self
._pattern
.match(line
):
65 class CompilerErrorParser(MatchErrorParser
):
67 # format (compile error):
68 # '<filename>:<line #>:<column #>: error: <error msg>'
69 # format (link error):
70 # '<filename>:<line #>: error: <error msg>'
71 # The below regex catches both
72 super(CompilerErrorParser
, self
).__init
__(r
'\S+:\d+: error:')
75 class ScanBuildErrorParser(MatchErrorParser
):
77 super(ScanBuildErrorParser
, self
).__init
__(
78 r
'scan-build: \d+ bugs found.$')
81 class DbCrashErrorParser(MatchErrorParser
):
83 super(DbCrashErrorParser
, self
).__init
__(r
'\*\*\*.*\^$|TEST FAILED.')
86 class WriteStressErrorParser(MatchErrorParser
):
88 super(WriteStressErrorParser
, self
).__init
__(
89 r
'ERROR: write_stress died with exitcode=\d+')
92 class AsanErrorParser(MatchErrorParser
):
94 super(AsanErrorParser
, self
).__init
__(
95 r
'==\d+==ERROR: AddressSanitizer:')
98 class UbsanErrorParser(MatchErrorParser
):
100 # format: '<filename>:<line #>:<column #>: runtime error: <error msg>'
101 super(UbsanErrorParser
, self
).__init
__(r
'\S+:\d+:\d+: runtime error:')
104 class ValgrindErrorParser(MatchErrorParser
):
106 # just grab the summary, valgrind doesn't clearly distinguish errors
107 # from other log messages.
108 super(ValgrindErrorParser
, self
).__init
__(r
'==\d+== ERROR SUMMARY:')
111 class CompatErrorParser(MatchErrorParser
):
113 super(CompatErrorParser
, self
).__init
__(r
'==== .*[Ee]rror.* ====$')
116 class TsanErrorParser(MatchErrorParser
):
118 super(TsanErrorParser
, self
).__init
__(r
'WARNING: ThreadSanitizer:')
121 _TEST_NAME_TO_PARSERS
= {
122 'punit': [CompilerErrorParser
, GTestErrorParser
],
123 'unit': [CompilerErrorParser
, GTestErrorParser
],
124 'release': [CompilerErrorParser
, GTestErrorParser
],
125 'unit_481': [CompilerErrorParser
, GTestErrorParser
],
126 'release_481': [CompilerErrorParser
, GTestErrorParser
],
127 'clang_unit': [CompilerErrorParser
, GTestErrorParser
],
128 'clang_release': [CompilerErrorParser
, GTestErrorParser
],
129 'clang_analyze': [CompilerErrorParser
, ScanBuildErrorParser
],
130 'code_cov': [CompilerErrorParser
, GTestErrorParser
],
131 'unity': [CompilerErrorParser
, GTestErrorParser
],
132 'lite': [CompilerErrorParser
],
133 'lite_test': [CompilerErrorParser
, GTestErrorParser
],
134 'stress_crash': [CompilerErrorParser
, DbCrashErrorParser
],
135 'write_stress': [CompilerErrorParser
, WriteStressErrorParser
],
136 'asan': [CompilerErrorParser
, GTestErrorParser
, AsanErrorParser
],
137 'asan_crash': [CompilerErrorParser
, AsanErrorParser
, DbCrashErrorParser
],
138 'ubsan': [CompilerErrorParser
, GTestErrorParser
, UbsanErrorParser
],
139 'ubsan_crash': [CompilerErrorParser
, UbsanErrorParser
, DbCrashErrorParser
],
140 'valgrind': [CompilerErrorParser
, GTestErrorParser
, ValgrindErrorParser
],
141 'tsan': [CompilerErrorParser
, GTestErrorParser
, TsanErrorParser
],
142 'format_compatible': [CompilerErrorParser
, CompatErrorParser
],
143 'run_format_compatible': [CompilerErrorParser
, CompatErrorParser
],
144 'no_compression': [CompilerErrorParser
, GTestErrorParser
],
145 'run_no_compression': [CompilerErrorParser
, GTestErrorParser
],
146 'regression': [CompilerErrorParser
],
147 'run_regression': [CompilerErrorParser
],
152 if len(sys
.argv
) != 2:
153 return 'Usage: %s <test name>' % sys
.argv
[0]
154 test_name
= sys
.argv
[1]
155 if test_name
not in _TEST_NAME_TO_PARSERS
:
156 return 'Unknown test name: %s' % test_name
159 for parser_cls
in _TEST_NAME_TO_PARSERS
[test_name
]:
160 error_parsers
.append(parser_cls())
162 for line
in sys
.stdin
:
164 for error_parser
in error_parsers
:
165 error_msg
= error_parser
.parse_error(line
)
166 if error_msg
is not None:
170 if __name__
== '__main__':