[bugzilla-gnome-org-extensions] Add support for "similar traces" and "identical traces".



commit 51cfaccf9fcc26d9c21f89518d2ba2e128466d51
Author: Max Kanat-Alexander <mkanat everythingsolved com>
Date:   Wed Aug 5 05:32:50 2009 -0500

    Add support for "similar traces" and "identical traces".

 code/db_schema-abstract_schema.pl          |    4 +-
 lib/TraceParser/Hooks.pm                   |   22 ++++++++++--
 lib/TraceParser/Trace.pm                   |   51 ++++++++++++++++++----------
 template/en/default/pages/trace.html.tmpl  |   28 +++++++++++++++
 template/en/default/trace/format.html.tmpl |    9 ++++-
 web/style.css                              |    6 ++--
 6 files changed, 92 insertions(+), 28 deletions(-)
---
diff --git a/code/db_schema-abstract_schema.pl b/code/db_schema-abstract_schema.pl
index db7112a..fd3a04d 100644
--- a/code/db_schema-abstract_schema.pl
+++ b/code/db_schema-abstract_schema.pl
@@ -34,8 +34,8 @@ $schema->{trace} = {
                                        COLUMN => 'comment_id',
                                        DELETE => 'CASCADE'}},
         type        => {TYPE => 'varchar(255)', NOTNULL => 1},
-        short_hash  => {TYPE => 'char(22)', NOTNULL => 1},
-        stack_hash  => {TYPE => 'char(22)', NOTNULL => 1},
+        short_hash  => {TYPE => 'char(22)'},
+        stack_hash  => {TYPE => 'char(22)'},
         trace_hash  => {TYPE => 'char(22)', NOTNULL => 1},
         trace_text  => {TYPE => 'LONGTEXT', NOTNULL => 1},
         quality     => {TYPE => 'real', NOTNULL => 1},
diff --git a/lib/TraceParser/Hooks.pm b/lib/TraceParser/Hooks.pm
index 306511b..46928a5 100644
--- a/lib/TraceParser/Hooks.pm
+++ b/lib/TraceParser/Hooks.pm
@@ -38,14 +38,14 @@ sub install_update_db {
     return if $has_traces;
 
     print "Parsing traces from comments...\n";
-    my $total = $dbh->selectrow_array('SELECT COUNT(*) FROM longdescs');
+    my $total = 75000; #$dbh->selectrow_array('SELECT COUNT(*) FROM longdescs');
 
     if ($dbh->isa('Bugzilla::DB::Mysql')) {
         $dbh->{'mysql_use_result'} = 1;
     }
 
     my $sth = $dbh->prepare('SELECT comment_id, thetext FROM longdescs 
-                           ORDER BY comment_id');
+                           ORDER BY comment_id DESC LIMIT 75000');
     $sth->execute();
     my $count = 1;
     my @traces;
@@ -93,7 +93,7 @@ sub format_comment {
     }
     else {
         my $stacktrace = TraceParser::Trace->stacktrace_from_text($$text);
-        $trace->{stacktrace_object} = $stacktrace;
+        $trace->{stack} = $stacktrace;
         $match_text = $stacktrace->text;
     }
 
@@ -114,6 +114,22 @@ sub page {
     return if $page !~ '^trace\.';
     my $trace_id = Bugzilla->cgi->param('trace_id');
     my $trace = TraceParser::Trace->check({ id => $trace_id });
+    $trace->bug->check_is_visible;
+
+    if ($trace->stack_hash) {
+        my $identical_traces = TraceParser::Trace->match(
+            { stack_hash => $trace->stack_hash });
+        my $similar_traces = TraceParser::Trace->match(
+            { short_hash => $trace->short_hash });
+        # Remove identical traces.
+        my %identical = map { $_->id => 1 } @$identical_traces;
+        @$similar_traces = grep { !$identical{$_->id} } @$similar_traces;
+        # Remove this trace from the identical traces.
+        @$identical_traces = grep { $_->id != $trace->id } @$identical_traces;
+        $vars->{similar_traces} = $similar_traces;
+        $vars->{identical_traces} = $identical_traces;
+    }
+
     $vars->{trace} = $trace;
 }
 
diff --git a/lib/TraceParser/Trace.pm b/lib/TraceParser/Trace.pm
index 3a910ac..b0f3ddf 100644
--- a/lib/TraceParser/Trace.pm
+++ b/lib/TraceParser/Trace.pm
@@ -55,13 +55,10 @@ use constant VALIDATORS => {
     trace_hash  => \&_check_hash,
     trace_text  => \&_check_thetext,
     type        => \&_check_type,
-    quality     => \&_check_quality,
 };
 
 use constant REQUIRED_CREATE_FIELDS => qw(
     comment_id
-    short_hash
-    stack_hash
     trace_hash
     trace_text
     type
@@ -70,10 +67,14 @@ use constant REQUIRED_CREATE_FIELDS => qw(
 # This is how long a Base64 MD5 Hash is.
 use constant HASH_SIZE => 22;
 
+# How many functions we should be hashing for the short_hash.
+use constant STACK_SIZE => 5;
+
 use constant TRACE_TYPES => ['GDB', 'Python'];
 
 use constant IGNORE_FUNCTIONS => qw(
    __kernel_vsyscall
+   __libc_start_main
    raise
    abort
    ??
@@ -95,26 +96,42 @@ sub parse_from_text {
     my $trace = $class->stacktrace_from_text($text);
     return undef if !$trace;
 
+    my $crash_thread = $trace->thread_with_crash || $trace->threads->[0];
+    my @frames = @{ $crash_thread->frames };
+    my ($has_crash) = grep { $_->is_crash } @frames;
+
     my @all_functions;
     my $quality = 0;
-    my $crash_thread = $trace->thread_with_crash || $trace->threads->[0];
-    foreach my $frame (@{ $crash_thread->frames }) {
+    my $counting_functions = 0;
+    foreach my $frame (@frames) {
+        if (!$has_crash or $frame->number > $has_crash->number) {
+            $counting_functions++;
+        }
+        next if !$counting_functions;
+
         foreach my $item (qw(args number file line code)) {
             $quality++ if defined $frame->$item && $frame->$item ne '';
         }
+
         my $function = $frame->function;
         if (!grep($_ eq $function, IGNORE_FUNCTIONS)) {
-            push(@all_functions, $frame->function);
+            $function =~ s/^IA__//;
+            push(@all_functions, $function);
             $quality++;
         }
     }
 
-    $quality = $quality / scalar(@{ $crash_thread->frames });
+    $quality = "$quality.0" / scalar(@frames);
 
-    my $max_short_stack = $#all_functions > 4 ? 4 : $#all_functions;
-    my @short_stack = @all_functions[0..$max_short_stack];
-    my $stack_hash = md5_base64(join(',', @all_functions));
-    my $short_hash = md5_base64(join(',', @short_stack));
+    my $stack_hash;
+    my $short_hash;
+    if (@all_functions) {
+        my $max_short_stack = $#all_functions >= STACK_SIZE ? STACK_SIZE 
+                              : $#all_functions;
+        my @short_stack = @all_functions[0..($max_short_stack-1)];
+        $stack_hash = md5_base64(join(',', @all_functions));
+        $short_hash = md5_base64(join(',', @short_stack));
+    }
     my $trace_text = $trace->text;
     my $trace_hash = md5_base64($trace_text);
 
@@ -133,7 +150,7 @@ sub parse_from_text {
 ###############################
 
 sub comment_id  { return $_[0]->{comment_id};  }
-sub full_hash   { return $_[0]->{full_hash};   }
+sub stack_hash  { return $_[0]->{stack_hash};  }
 sub short_hash  { return $_[0]->{short_hash};  }
 sub trace_hash  { return $_[0]->{trace_hash};  }
 sub text        { return $_[0]->{trace_text};  }
@@ -150,12 +167,12 @@ sub bug {
     return $self->{bug};
 }
 
-sub stacktrace_object {
+sub stack {
     my $self = shift;
     my $type = $self->type;
     eval("use $type; 1;") or die $@;
-    $self->{stacktrace_object} ||= $type->parse({ text => $self->trace_text });
-    return $self->{stacktrace_object};
+    $self->{stack} ||= $type->parse({ text => $self->trace_text });
+    return $self->{stack};
 }
 
 ###############################
@@ -165,7 +182,7 @@ sub stacktrace_object {
 sub _check_hash {
     my ($self, $hash) = @_;
     $hash = trim($hash);
-    ThrowCodeError('traceparser_no_hash') if !$hash;
+    return undef if !$hash;
     length($hash) == HASH_SIZE
         or ThrowCodeError('traceparser_bad_hash', { hash => $hash });
     return $hash;
@@ -194,6 +211,4 @@ sub _check_type {
     return $type;
 }
 
-sub _check_quality { return int($_[1]); }
-
 1;
diff --git a/template/en/default/pages/trace.html.tmpl b/template/en/default/pages/trace.html.tmpl
index 68472c1..efb56b1 100644
--- a/template/en/default/pages/trace.html.tmpl
+++ b/template/en/default/pages/trace.html.tmpl
@@ -23,8 +23,36 @@
    title = "Trace $trace.id From Bug $trace.bug.id" 
 %]
 
+[% IF identical_traces.size %]
+  <p>Identical Traces:</p>
+  [% PROCESS trace_list list = identical_traces %]
+[% END %]
+
+[% IF similar_traces.size %]
+  <p>Similar Traces:</p>
+  [% PROCESS trace_list list = similar_traces %]
+[% END %]
+
 <table border="0" cellpadding="0" cellspacing="0"><tr><td><div class="trace">
 <pre>[% trace.text FILTER html %]
 </pre></div></td></tr></table>
 
 [% PROCESS global/footer.html.tmpl %]
+
+[% BLOCK trace_list %]
+  <ul class="trace_list">
+    [% FOREACH this_trace = list %]
+      [% SET bug = this_trace.bug %]
+      <li>
+        <a href="page.cgi?id=trace.html&amp;trace_id=
+                 [%- this_trace.id FILTER url_quote %]">Trace 
+          [% this_trace.id FILTER html %]</a> on
+        [%+ "Bug $bug.id" FILTER bug_link(bug.id) %]
+        (Quality: [% this_trace.quality FILTER html %])
+        [% IF user.can_see_bug(bug) %]
+          [%+ bug.product FILTER html %]
+        [% END %]
+      </li>
+    [% END %]
+  </ul>
+[% END %]
diff --git a/template/en/default/trace/format.html.tmpl b/template/en/default/trace/format.html.tmpl
index 7af617e..4f39dd6 100644
--- a/template/en/default/trace/format.html.tmpl
+++ b/template/en/default/trace/format.html.tmpl
@@ -27,9 +27,8 @@
 <table border="0" cellpadding="0" cellspacing="0"><tr><td>
 <div class="trace">
   [% IF trace.type.match('Python') %]
-    PYTHON TRACE
   [% ELSE %]
-    [% SET st = trace.stacktrace_object %]
+    [% SET st = trace.stack %]
     [% IF st.thread_with_crash %]
       [% threads = [st.thread_with_crash] %]
     [% ELSE %]
@@ -49,6 +48,12 @@
               <span class="frame_number">#[% frame.number FILTER html %]</span>
             [% END %]
             <span class="frame_function">[% frame.function FILTER html %]</span>
+            [% IF frame.library %]
+              <div class="frame_library_container">
+                from 
+                <span class="frame_library">[% frame.library FILTER html %]</span>
+              </div>
+            [% END %]
             [% IF frame.file %]
               <div class="frame_file_container">
                 at <span class="frame_file">[% frame.file FILTER html %]</span>
diff --git a/web/style.css b/web/style.css
index 6b313f0..cf193d9 100644
--- a/web/style.css
+++ b/web/style.css
@@ -31,11 +31,11 @@
   color: #4e9a06;
 }
 
-.frame_file_container {
-  margin-left: 3em;
+.frame_file_container, .frame_library_container {
+  margin-left: 2em;
 }
 
-.frame_file {
+.frame_file, .frame_library {
   font-style: italic;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]