]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/build_tools/error_filter.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / 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).
5
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
10 '''
11
12 from __future__ import absolute_import
13 from __future__ import division
14 from __future__ import print_function
15 from __future__ import unicode_literals
16
17 import re
18 import sys
19
20
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.
26 '''
27 raise NotImplementedError
28
29
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.
33 '''
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$')
37
38 def __init__(self):
39 self._last_gtest_name = 'Unknown test'
40
41 def parse_error(self, line):
42 gtest_name_match = self._GTEST_NAME_PATTERN.match(line)
43 if gtest_name_match:
44 self._last_gtest_name = gtest_name_match.group(1)
45 return None
46 gtest_fail_match = self._GTEST_FAIL_PATTERN.match(line)
47 if gtest_fail_match:
48 return '%s failed: %s' % (
49 self._last_gtest_name, gtest_fail_match.group(1))
50 return None
51
52
53 class MatchErrorParser(ErrorParserBase):
54 '''A simple parser that returns the whole line if it matches the pattern.
55 '''
56 def __init__(self, pattern):
57 self._pattern = re.compile(pattern)
58
59 def parse_error(self, line):
60 if self._pattern.match(line):
61 return line
62 return None
63
64
65 class CompilerErrorParser(MatchErrorParser):
66 def __init__(self):
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:')
73
74
75 class ScanBuildErrorParser(MatchErrorParser):
76 def __init__(self):
77 super(ScanBuildErrorParser, self).__init__(
78 r'scan-build: \d+ bugs found.$')
79
80
81 class DbCrashErrorParser(MatchErrorParser):
82 def __init__(self):
83 super(DbCrashErrorParser, self).__init__(r'\*\*\*.*\^$|TEST FAILED.')
84
85
86 class WriteStressErrorParser(MatchErrorParser):
87 def __init__(self):
88 super(WriteStressErrorParser, self).__init__(
89 r'ERROR: write_stress died with exitcode=\d+')
90
91
92 class AsanErrorParser(MatchErrorParser):
93 def __init__(self):
94 super(AsanErrorParser, self).__init__(
95 r'==\d+==ERROR: AddressSanitizer:')
96
97
98 class UbsanErrorParser(MatchErrorParser):
99 def __init__(self):
100 # format: '<filename>:<line #>:<column #>: runtime error: <error msg>'
101 super(UbsanErrorParser, self).__init__(r'\S+:\d+:\d+: runtime error:')
102
103
104 class ValgrindErrorParser(MatchErrorParser):
105 def __init__(self):
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:')
109
110
111 class CompatErrorParser(MatchErrorParser):
112 def __init__(self):
113 super(CompatErrorParser, self).__init__(r'==== .*[Ee]rror.* ====$')
114
115
116 class TsanErrorParser(MatchErrorParser):
117 def __init__(self):
118 super(TsanErrorParser, self).__init__(r'WARNING: ThreadSanitizer:')
119
120
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],
148 }
149
150
151 def main():
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
157
158 error_parsers = []
159 for parser_cls in _TEST_NAME_TO_PARSERS[test_name]:
160 error_parsers.append(parser_cls())
161
162 for line in sys.stdin:
163 line = line.strip()
164 for error_parser in error_parsers:
165 error_msg = error_parser.parse_error(line)
166 if error_msg is not None:
167 print(error_msg)
168
169
170 if __name__ == '__main__':
171 sys.exit(main())