Added JSONReportFormatter, a subclass of QueryReportFormatter that does what it says on the tin. WIP as it does not report profile or prepared statement data yet

This commit is contained in:
Brian Fraser fraserb@gmail.com
2013-01-14 13:20:35 -03:00
parent 5e5763f82a
commit 3c63750c9b
4 changed files with 139 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
{
package JSONReportFormatter;
use Mo;
use JSON;
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
extends qw(QueryReportFormatter);
override [qw(rusage date hostname files header profile prepared)] => sub {
return;
};
override event_report => sub {
my ($self, %args) = @_;
return $self->event_report_values(%args);
};
override query_report => sub {
my ($self, %args) = @_;
foreach my $arg ( qw(ea worst orderby groupby) ) {
die "I need a $arg argument" unless defined $arg;
}
my $ea = $args{ea};
my $groupby = $args{groupby};
my $worst = $args{worst};
my $q = $self->Quoter;
my $qv = $self->{QueryReview};
my $qr = $self->{QueryRewriter};
my $query_report_vals = $self->query_report_values(%args);
# Sort the attributes, removing any hidden attributes.
my $attribs = $self->sort_attribs(
($args{select} ? $args{select} : $ea->get_attributes()),
$ea,
);
ITEM:
foreach my $vals ( @$query_report_vals ) {
my $item = $vals->{item};
my $samp_query = $vals->{samp_query};
# ###############################################################
# Print the standard query analysis report.
# ###############################################################
$vals->{event_report} = $self->event_report(
%args,
item => $item,
sample => $ea->results->{samples}->{$item},
rank => $vals->{rank},
reason => $vals->{reason},
attribs => $attribs,
db => $vals->{default_db},
);
if ( $groupby eq 'fingerprint' ) {
if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) {
if ( $item !~ m/^(?:insert|replace)/ ) { # No EXPLAIN
$vals->{for_explain} = "EXPLAIN /*!50100 PARTITIONS*/\n$samp_query\\G\n";
$vals->{explain_report} = $self->explain_report($samp_query, $vals->{default_db});
}
}
else {
my $converted = $qr->convert_to_select($samp_query);
if ( $converted
&& $converted =~ m/^[\(\s]*select/i ) {
$vals->{for_explain} = "EXPLAIN /*!50100 PARTITIONS*/\n$converted\\G\n";
}
}
}
else {
if ( $groupby eq 'tables' ) {
my ( $db, $tbl ) = $q->split_unquote($item);
$vals->{tables_report} = $self->tables_report([$db, $tbl]);
}
}
}
return encode_json($query_report_vals) . "\n";
};
1;
}
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
require "$trunk/bin/pt-query-digest";
my @args = qw(--output json);
my $sample = "$trunk/t/lib/samples";
my $results = "t/pt-query-digest/samples";
ok(
no_diff(
sub { pt_query_digest::main(@args, "$sample/slowlogs/empty") },
"$results/empty_report.txt",
),
'json output for empty log'
);
ok(
no_diff(
sub { pt_query_digest::main(@args, "$sample/slowlogs/slow002.txt") },
"$results/output_json_slow002.txt"
),
'json output for slow002'
);
# --type tcpdump
ok(
no_diff(
sub { pt_query_digest::main(qw(--type tcpdump --limit 10 --watch-server 127.0.0.1:12345),
@args, "$sample/tcpdump/tcpdump021.txt") },
"$results/output_json_tcpdump021.txt",
),
'json output for for tcpdump021',
);
# #############################################################################
# Done.
# #############################################################################
done_testing;
@@ -0,0 +1,2 @@
[{"event_report":{"time_range":"all events occurred at 2007-12-18 11:48:27","variance_to_mean":0,"reason":"top","qps":0,"counts":{"class_cnt":1,"global_cnt":8},"concurrency":0,"checksum":"66825DDC008FFA89","pos_in_log":338,"attributes":{"bool":[["Full_scan","100","0"]],"innodb":[],"num":[["Query_time","95","726ms","726ms","726ms","726ms","726ms",0,"726ms"],["Lock_time","29","91us","91us","91us","91us","91us",0,"91us"],["Rows_sent","0","0","0","0","0","0","0","0"],["Rows_examined","100","61.48k","61.48k","61.48k","61.48k","61.48k","0","61.48k"],["Merge_passes","0","0","0","0","0","0","0","0"],["bytes","25","129","129","129","129","129","0","129"]],"string":[["db",{"min":"db1","max":"db1","unq":{"db1":1},"cnt":1}],["host",{"min":"","max":"","unq":{"":1},"cnt":1}],["user",{"min":"[SQL_SLAVE]","max":"[SQL_SLAVE]","unq":{"[SQL_SLAVE]":1},"cnt":1}]]},"groupby":"fingerprint"},"reason":"top","item":"update d?tuningdetail_?_? n inner join d?gonzo a using(gonzo) set n.column? = a.column?, n.word? = a.word?","samp_query":"update db2.tuningdetail_21_265507 n\n inner join db1.gonzo a using(gonzo) \n set n.column1 = a.column1, n.word3 = a.word3","for_explain":"EXPLAIN /*!50100 PARTITIONS*/\nselect n.column1 = a.column1, n.word3 = a.word3 from db2.tuningdetail_21_265507 n\n inner join db1.gonzo a using(gonzo) \\G\n","tables":[["db2","tuningdetail_21_265507"],["db1","gonzo"]],"rank":1,"default_db":"db1"}]
@@ -0,0 +1,2 @@
[{"event_report":{"time_range":"all events occurred at 2009-12-08 09:23:49.637394","variance_to_mean":0,"reason":"top","qps":0,"counts":{"class_cnt":1,"global_cnt":3},"concurrency":0,"checksum":"AA8E9FA785927259","pos_in_log":0,"attributes":{"bool":[],"innodb":[],"num":[["Query_time","50","286us","286us","286us","286us","286us",0,"286us"],["Rows_affected","0","0","0","0","0","0","0","0"],["bytes","35","35","35","35","35","35","0","35"],["Warning_count","0","0","0","0","0","0","0","0"]],"string":[["Error_no",{"min":"none","max":"none","unq":{"none":1},"cnt":1}],["host",{"min":"127.0.0.1","max":"127.0.0.1","unq":{"127.0.0.1":1},"cnt":1}],["Statement_id",{"min":2,"max":2,"unq":{"2":1},"cnt":1}]]},"groupby":"fingerprint"},"reason":"top","item":"prepare select i from d.t where i=?","samp_query":"PREPARE SELECT i FROM d.t WHERE i=?","for_explain":"EXPLAIN /*!50100 PARTITIONS*/\nSELECT i FROM d.t WHERE i=?\\G\n","tables":[["d","t"]],"rank":1,"default_db":null},{"event_report":{"time_range":"all events occurred at 2009-12-08 09:23:49.637892","variance_to_mean":0,"reason":"top","qps":0,"counts":{"class_cnt":1,"global_cnt":3},"concurrency":0,"checksum":"3F79759E7FA2F117","pos_in_log":1106,"attributes":{"bool":[["No_index_used","100","0"]],"innodb":[],"num":[["Query_time","49","281us","281us","281us","281us","281us",0,"281us"],["Rows_affected","0","0","0","0","0","0","0","0"],["bytes","37","37","37","37","37","37","0","37"],["Warning_count","0","0","0","0","0","0","0","0"]],"string":[["Error_no",{"min":"none","max":"none","unq":{"none":1},"cnt":1}],["host",{"min":"127.0.0.1","max":"127.0.0.1","unq":{"127.0.0.1":1},"cnt":1}],["Statement_id",{"min":"2","max":"2","unq":{"2":1},"cnt":1}]]},"groupby":"fingerprint"},"reason":"top","item":"execute select i from d.t where i=?","samp_query":"EXECUTE SELECT i FROM d.t WHERE i=\"3\"","for_explain":"EXPLAIN /*!50100 PARTITIONS*/\nSELECT i FROM d.t WHERE i=\"3\"\\G\n","tables":[["d","t"]],"rank":2,"default_db":null},{"samp_query":"administrator command: Quit","tables":[],"event_report":{"time_range":"all events occurred at 2009-12-08 09:23:49.638381","variance_to_mean":0,"reason":"top","qps":0,"counts":{"class_cnt":1,"global_cnt":3},"concurrency":0,"checksum":"AA353644DE4C4CB4","pos_in_log":1850,"attributes":{"bool":[],"innodb":[],"num":[["Query_time","0",0,0,0,0,0,0,0],["Rows_affected","0","0","0","0","0","0","0","0"],["bytes","27","27","27","27","27","27","0","27"],["Warning_count","0","0","0","0","0","0","0","0"]],"string":[["Error_no",{"min":"none","max":"none","unq":{"none":1},"cnt":1}],["host",{"min":"127.0.0.1","max":"127.0.0.1","unq":{"127.0.0.1":1},"cnt":1}]]},"groupby":"fingerprint"},"reason":"top","item":"administrator command: Quit","rank":3,"default_db":null}]