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