5e247bd47371ae3d6d05ecace0ad15158cdac494
[buildd-scripts.git] / bin / analyze_results
1 #! /usr/bin/perl
2 #
3 # analyze_results
4 #
5 # Script to analyze failed build logs. Look for specific regexps to
6 # classify things
7 #
8 #
9 # (c) 2018 Steve McIntyre <steve@einval.com> GPL v2+
10
11 use strict;
12 use warnings;
13 use POSIX qw(strftime);
14 use Data::Dumper;
15
16 my $name = "analyze_results";
17 my $repo = "https://git.einval.com/cgi-bin/gitweb.cgi?p=buildd-scripts.git";
18 my $hostname;
19 my $date;
20 my $time_start = time();
21 my $time_end;
22 my $time_taken;
23 my $num_fail = 0;
24 my $lines_read = 0;
25 my $existing_bugs = 0;
26
27 use constant {
28     ERR_ARCH_MISMATCH      => 1,
29     ERR_INFRA              => 2,
30     ERR_BD_PROBLEM         => 3,
31     ERR_DETECT_WRONG_ARCH  => 4,
32     ERR_CRASH              => 5,
33     ERR_BUILD_PROBLEM      => 6,
34     ERR_TEST_PROBLEM       => 7,
35     ERR_BUILD_TIMEOUT      => 8,
36 };
37
38 my @err_descriptions;
39 $err_descriptions [ERR_ARCH_MISMATCH]     = "Architecture mismatches";
40 $err_descriptions [ERR_INFRA]             = "Infrastructure errors";
41 $err_descriptions [ERR_BD_PROBLEM]        = "Problems with build-deps";
42 $err_descriptions [ERR_DETECT_WRONG_ARCH] = "Builds detected wrong architecture";
43 $err_descriptions [ERR_CRASH]             = "Crashes detected";
44 $err_descriptions [ERR_BUILD_PROBLEM]     = "Problems detected during build phase";
45 $err_descriptions [ERR_TEST_PROBLEM]      = "Problems detected during test phase";
46 $err_descriptions [ERR_BUILD_TIMEOUT]     = "Package builds timed out";
47
48 # Known failure modes to look for
49 my @logcheck = (
50     {
51         # "rchitecture mismatch" -> should never build on this arch
52         # Stop working on this log at this point
53         string   => 'rchitecture mismatch',
54         message  => 'Architecture mismatch',
55         check    => 1,
56         stop     => 1,
57         type     => ERR_ARCH_MISMATCH,
58     },
59     {
60         string   => 'not in arch list or does not match any',
61         message  => 'Architecture mismatch',
62         check    => 1,
63         stop     => 1,
64         type     => ERR_ARCH_MISMATCH,
65     },
66     {
67         # "binary build with no binary artifacts found" -> no packages
68         # built. Why not picked up already above?.
69         # Stop working on this log at this point
70         string   => 'binary build with no binary artifacts found',
71         message  => 'No binaries built',
72         check    => 1,
73         stop     => 1,
74         type     => ERR_ARCH_MISMATCH,
75     },
76     {
77         string   => 'schroot.*File is not owned by user root',
78         message  => 'Schroot setup failure',
79         check    => 1,
80         stop     => 1,
81         type     => ERR_INFRA,
82     },
83     {
84         string   => 'No space left on device',
85         message  => 'Build ran out of disk space',
86         check    => 1,
87         stop     => 1,
88         type     => ERR_INFRA,
89     },
90     {
91         string   => 'The system has no more ptys',
92         message  => 'Build ran out of ptys',
93         check    => 1,
94         stop     => 1,
95         type     => ERR_INFRA,
96     },
97     {
98         string   => 'aarch64-unknown-linux-gnu',
99         message  => 'Wrong arch detected',
100         check    => 1,
101         stop     => 1,
102         type     => ERR_DETECT_WRONG_ARCH,
103     },
104     {
105         string   => 'binutils-aarch64',
106         message  => 'Wrong arch detected',
107         check    => 0,
108         stop     => 1,
109         type     => ERR_DETECT_WRONG_ARCH,
110     },
111     {
112         string   => 'lib.linux-aarch64',
113         message  => 'Wrong arch detected',
114         check    => 1,
115         stop     => 1,
116         type     => ERR_DETECT_WRONG_ARCH,
117     },
118     {
119         # "Bus error" -> alignment bug
120         string   => 'Bus error',
121         message  => 'Alignment problem',
122         check    => 1,
123         stop     => 1,
124         type     => ERR_CRASH,
125     },
126     {
127         # "Segmentation fault" -> code problem
128         string   => 'Segmentation fault',
129         pstring  => 'Setting up (\S+)',
130         message  => 'Segmentation fault when installing RESULT',
131         check    => 1,
132         stop     => 1,
133         type     => ERR_CRASH,
134     },
135     {
136         # "Segmentation fault" -> code problem
137         string   => 'Segmentation fault',
138         message  => 'Segmentation fault',
139         check    => 1,
140         stop     => 1,
141         type     => ERR_CRASH,
142     },
143     {
144         # "Illegal instruction" -> bad build target?
145         string   => 'Illegal instruction',
146         pstring  => 'Setting up (\S+)',
147         message  => 'Illegal instruction when installing RESULT',
148         check    => 1,
149         stop     => 1,
150         type     => ERR_CRASH,
151     },
152     {
153         # "Illegal instruction" -> bad build target?
154         string   => 'Illegal instruction',
155         message  => 'Illegal instruction',
156         check    => 1,
157         stop     => 1,
158         type     => ERR_CRASH,
159     },
160     {
161         # Installing build-deps failed
162         string   => 'dpkg: error processing package (\S+)',
163         message  => 'Build-dep failed to install (RESULT)',
164         check    => 1,
165         stop     => 0,
166         type     => ERR_BD_PROBLEM,
167     },
168     {
169         # Installing build-deps failed
170         string   => 'E: pbuilder-satisfydepends failed.',
171         message  => 'Pbuilder build-deps failed',
172         check    => 1,
173         stop     => 1,
174         type     => ERR_BD_PROBLEM,
175     },
176     {
177         # Installing build-deps failed
178         string   => 'E: Unmet dependencies',
179         message  => 'Build-deps failed',
180         check    => 1,
181         stop     => 1,
182         type     => ERR_BD_PROBLEM,
183     },
184     {
185         # Installing build-deps failed
186         string   => 'unsat-dependency: (\S+)',
187         message  => 'Missing build-dep (RESULT)',
188         check    => 1,
189         stop     => 1,
190         type     => ERR_BD_PROBLEM,
191     },
192     {
193         # Build failed - missing build-dep?
194         string   => 'build dependencies/conflicts unsatisfied',
195         message  => 'Build-deps not satisfiable',
196         check    => 1,
197         stop     => 1,
198         type     => ERR_BD_PROBLEM,
199     },
200     {
201         # Build failed
202         string   => 'dpkg-source: error: unrepresentable changes to source',
203         message  => 'dpkg-source failure',
204         check    => 1,
205         stop     => 1,
206         type     => ERR_BUILD_PROBLEM,
207     },
208     {
209         # Build failed - missing build-dep?
210         string   => 'ld: cannot find',
211         message  => 'Build failure: missing library - missing build-dep?',
212         check    => 1,
213         stop     => 1,
214         type     => ERR_BUILD_PROBLEM,
215     },
216     {
217         # Build failed - missing build-dep?
218         string   => 'fatal error:.*No such file or directory',
219         message  => 'Build failure: missing header - missing build-dep?',
220         check    => 1,
221         stop     => 1,
222         type     => ERR_BUILD_PROBLEM,
223     },
224     {
225         # Build failed - missing build-dep?
226         string   => 'SEVERE: Cannot resolve dependencies',
227         message  => 'Build failure - missing build-dep?',
228         check    => 1,
229         stop     => 1,
230         type     => ERR_BUILD_PROBLEM,
231     },
232     {
233         # Build failed - can't exec something...
234         string   => 'error trying to exec.*execvp: No',
235         message  => 'Build failure (missing binary)',
236         check    => 1,
237         stop     => 1,
238         type     => ERR_BUILD_PROBLEM,
239     },
240     {
241         # Build failed
242         string   => 'BUILD FAIL',
243         message  => 'Build failure (java/javadoc)',
244         check    => 1,
245         stop     => 1,
246         type     => ERR_BUILD_PROBLEM,
247     },
248     {
249         # Build failed
250         string   => 'make.*returned exit code',
251         message  => 'Build failure (other)',
252         check    => 1,
253         stop     => 0,
254         type     => ERR_BUILD_PROBLEM,
255     },
256     {
257         # Build failed
258         string   => '^make.*\*\*\*.* \[debian/rules.*Error \d+$',
259         message  => 'Build failure (other)',
260         check    => 1,
261         stop     => 1,
262         type     => ERR_BUILD_PROBLEM,
263     },
264     {
265         # Build failure
266         string   => 'dh_auto_build:.*returned exit code \d+',
267         message  => 'Build failure (other)',
268         check    => 1,
269         stop     => 1,
270         type     => ERR_BUILD_PROBLEM,
271     },
272     {
273         # Build failure
274         string   => 'dh_auto_clean:.*returned exit code \d+',
275         message  => 'Build failure (clean failed)',
276         check    => 1,
277         stop     => 1,
278         type     => ERR_BUILD_PROBLEM,
279     },
280     {
281         # Build failure
282         string   => 'dh_auto_install:.*returned exit code \d+',
283         message  => 'Build failure (install failed)',
284         check    => 1,
285         stop     => 1,
286         type     => ERR_BUILD_PROBLEM,
287     },
288     {
289         # Build failure
290         string   => 'dh_auto_configure:.*returned exit code \d+',
291         message  => 'Build failure (configure failed)',
292         check    => 1,
293         stop     => 1,
294         type     => ERR_BUILD_PROBLEM,
295     },
296     {
297         # Build failed
298         string   => '^debian/.*recipe for target (\S+) failed',
299         message  => 'Build failure (RESULT)',
300         check    => 1,
301         stop     => 1,
302         type     => ERR_BUILD_PROBLEM,
303     },
304     {
305         # Build failed
306         string   => 'fakeroot debian/rules binary',
307         message  => 'Build failure (other)',
308         check    => 0,
309         stop     => 1,
310         type     => ERR_BUILD_PROBLEM,
311     },
312     {
313         # Test failure
314         string   => 'OSError: \[Errno 13\] Permission denied',
315         message  => 'Python EPERM test failure',
316         check    => 1,
317         stop     => 1,
318         type     => ERR_TEST_PROBLEM,
319     },
320     {
321         # Test failure
322         string   => 'dh_auto_test:.*returned exit code \d+',
323         message  => 'Test failure',
324         check    => 1,
325         stop     => 1,
326         type     => ERR_TEST_PROBLEM,
327     },
328     {
329         # Timeout. pbuilder is too dumb to do this properly :-(
330         string   => 'I: Terminating build process due to timeout',
331         message  => 'Pbuilder build timeout',
332         check    => 1,
333         stop     => 1,
334         type     => ERR_BUILD_TIMEOUT,
335     },
336     {
337         # Timeout from sbuild
338         string   => 'Build killed with signal TERM after \d+ minutes of inactivity',
339         message  => 'Sbuild build timeout',
340         check    => 1,
341         stop     => 1,
342         type     => ERR_BUILD_TIMEOUT,
343     },
344 );
345
346 my %log_results;
347
348 #foreach my $checktmp (@logcheck) {
349 #    my %check = %$checktmp;
350 #    print "looking for \"$check{string}\"\n";
351 #    print "  with log message \"$check{message}\"\n";
352 #    print "  check this regexp: $check{check}\n";
353 #    print "  stop if found: $check{stop}\n";
354 #}
355
356 print "<html>\n";
357 print "<head>\n";
358 print "<title>Build log analysis</title>\n";
359 print "</head>\n";
360 print "<body>\n";
361 print "<h1>Build log analysis</h1>\n";
362 print "<p><a href=\"#summary\">Summary</a></p>\n";
363 print "<h2>Packages</h2>\n";
364 print "<ol>\n";
365
366 foreach my $input (@ARGV) {
367     open (IN, "< $input") or die "Can't read $input: $!\n";
368     $num_fail++;
369     my $stop = 0;
370     my $lineno = 0;
371     my $errors = 0;
372     my $oldline = "";
373     my %file_results;
374     print "<li>Looking at <a href=\"$input\">$input</a>:\n";
375     print "<ul>\n";
376     while (defined (my $line = <IN>) and !$stop) {
377         $lineno++;
378         $lines_read++;
379         foreach my $checktmp (@logcheck) {
380             my %check = %$checktmp;
381             if ($check{check}) {
382                 if (!$stop
383                     and ($line =~ m/$check{string}/)
384                     and (!$check{pstring} or $oldline =~ m/$check{pstring}/)) {
385 #                   print "  Line $lineno: found \"$check{string}\"\n";
386                     my $match = $1;
387                     my $message = $check{message};
388                     $message =~ s,RESULT,$match,g;
389                     $file_results{$message} = $check{type};
390                     if ($check{type} == ERR_BUILD_TIMEOUT and $errors == 0) {
391                         print "  <li>Line $lineno: $message\n";
392                         print "  <li>Build killed by timeout before any errors at line $lineno\n";
393                     } else {
394                         print "  <li>Line $lineno: $message\n";
395                         $errors++;
396                     }
397                     if ($check{stop}) {
398 #                       print "  stopping processing\n";
399                         $stop = 1;
400                     }
401                 }
402             }
403         }
404         $oldline = $line;
405     }
406     close IN;
407     # End of checking this package
408     print "  <li><strong>Found errors: $errors</strong>\n";
409     if (!$errors) {
410         print " (maybe just timed out during build?)\n";
411     }
412
413     # Look for a note for manually-added logfile analysis
414     my $note = $input;
415     $note =~ s,\.log$,.note,;
416     if (-f $note) {
417         open (IN, "< $note") or die "Can't open $note for reading: $!\n";
418         while (defined (my $line = <IN>)) {
419             chomp $line;
420             if ($line =~ m,#(\d+),) {
421                 my $bugno = $1;
422                 $existing_bugs++;
423                 $line =~ s,#(\d+),<a href="https://bugs.debian.org/$1">#$1</a>,g;
424             }
425             print "  <li>$line\n";
426         }
427         close IN;
428     }
429
430     print "</ul>\n";
431     foreach my $key (keys %file_results) {
432         $log_results{$file_results{$key}}{$key} += 1;
433 #       print "now have $log_results{$key} for \"$key\"\n";
434     }
435 }
436 print "</ol>\n";
437
438 print "<a name=\"summary\"</a>\n";
439 print "<h2>Summary of results from $num_fail failed builds:</h2>\n";
440 print "<ul>\n";
441 print "<li>  Found $existing_bugs existing bugs in the Debian BTS</li>\n";
442 foreach my $type (sort keys %log_results) {
443     print "  <h3>$err_descriptions[$type]</h3>\n";
444     my $tmp = $log_results{$type};
445     my %result = %$tmp;
446     foreach my $key (sort { $result{$b} <=> $result{$a} }keys %result) {
447         print "  <li>Found $result{$key} log(s) showing $key\n";
448     }
449 }
450 print "</ul>\n";
451
452 $time_end = time();
453 $time_taken = $time_end - $time_start;
454 $date = strftime "%a %b %e %H:%M:%S %Z %Y", localtime;
455 $hostname = `hostname`;
456
457 print "<hr>\n";
458 print "<p>Log analysis generated on $hostname, $date.\n";
459 print "<br>Output from $name - see <a href=\"$repo\">$repo</a> for source.\n";
460 print "<br>Read $lines_read lines of logs and took $time_taken seconds to complete.\n";
461
462 print "</body>\n";
463 print "</html>\n";