#!/usr/bin/env perl
#Thanks to Darren, MC and Ronald
# See http://ronaldbradford.com/blog/drizzle-query-logging-2009-07-21/
#########################################################################
# Imports
#########################################################################
use strict;
use warnings FATAL => 'all';
use JSON;
use LWP::UserAgent;
use Data::Dumper;
use Getopt::Long;
use File::Tail;
use Digest::
MD5 qw/md5_hex/;
use Sys::Hostname;
#########################################################################
# Main (essentially)
#########################################################################
my $agent_username = 'agent';
my $agent_password = 'mysql';
my $srv_mgr_host = '127.0.0.1';
my $srv_mgr_port = '48080';
my $base_statement_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port.'/v2/rest/instance/mysql/statementsummary/';
my $base_agent_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port. '/v2/rest/instance/mysql/agent/';
my $base_host_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port. '/v2/rest/instance/os/Host/';
my $base_db_server_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port. '/v2/rest/instance/mysql/server/';
my $base_db_server_variables_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port. '/v2/rest/instance/mysql/variables/';
my $base_stmt_example_uri = 'http://' .$agent_username . ':'. $agent_password .
'@'.$srv_mgr_host.':'.$srv_mgr_port. '/v2/rest/instance/mysql/statement/';
my $DEBUG = $ENV{DEBUG}; #TODO: Implement DEBUG
my $parent;
#my $agent_uuid;
my $log_file;
my $server_uuid;
my $counter = 1;
my $uri_type;
my $server_host_uuid;
my $g_dbname;
my $md5_hash;
my $querybase = {};
my $server_display_name;
GetOptions(
#'agentuuid=s' => \$agent_uuid,
'serveruuid=s' => \$server_uuid,
'serverhostuuid=s' => \$server_host_uuid,
'serverdisplayname=s' => \$server_display_name,
'log-file=s' => \$log_file
);
#Sanity check
usage
(1) if ( !
defined ( $log_file ) );
usage
(2) if ( !
defined ( $server_uuid ) );
usage
(3) if ( !
defined ( $server_host_uuid ) );
#init_transport();
init_host();
init_db_server();
init_db_server_variables();
init_stmt_summary();
init_stmt_example();
tail_log();
#########################################################################
# Usage help
#########################################################################
sub usage {
print "\n--log-file=... parameter was missing" if $error_code ==
1;
print "\n--serveruuid=... parameter was missing" if $error_code ==
2;
print "\n--serverhostuuid=... parameter was missing" if $error_code ==
3;
print "\nDEBUG=[1-5] perl worker.pl \\ ";
print "\n --log-file=\"path/to/log/file\" \\ ";
print "\n --serverdisplayname=\"server name\" \\ ";
print "\n --serveruuid=\"22222222-2222-2222-2222-222222222222\" \\ ";
print "\n --serverhostuuid=\"ssh:{11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11}\" \n\n";
}
#########################################################################
#########################################################################
#########################################################################
# At different times we use different uri for the REST API
sub uri {
my $u;
if ( $uri_type eq "stmt_summary" ) {
$u = $base_statement_uri . $server_uuid . "." . $g_dbname . "." . $md5_hash;
} elsif ( $uri_type eq "init_stmt_summary" ) {
$u = $u = $base_statement_uri . $server_uuid;
} elsif ( $uri_type eq "init_transport" ) {
#$u = $base_agent_uri . $agent_uuid;
} elsif ( $uri_type eq "init_host" ) {
$u = $base_host_uri . $server_host_uuid;
} elsif ( $uri_type eq "init_db_server" ) {
$u = $base_db_server_uri . $server_uuid;
} elsif ( $uri_type eq "init_db_server_variables" ) {
$u = $base_db_server_variables_uri . $server_uuid;
} elsif ( $uri_type eq "init_stmt_example" ) {
$u = $base_stmt_example_uri . $server_uuid;
} elsif ( $uri_type eq "stmt_example" ) {
$u = $base_stmt_example_uri . $server_uuid . "." . $g_dbname . "." . $md5_hash;
}
}
# We add a "parent" attribute or not based on what kind of
# data we are sending.
sub make_transform {
my ( %rep ) = @_;
if ( $uri_type eq "stmt_summary" ) {
$rep{parent} = '/instance/mysql/server/' . $server_uuid;
} elsif ( $uri_type eq "init_stmt_summary" ) {
$rep{parent} = '/instance/mysql/server/' . $server_uuid;
} elsif ( $uri_type eq "init_db_server" ) {
$rep{parent} = '/instance/os/Host/' . $server_host_uuid;
} elsif ( $uri_type eq "init_db_server_variables" ) {
$rep{parent} = '/instance/mysql/server/' . $server_uuid;
} elsif ( $uri_type eq "init_stmt_example" ) {
$rep{parent} = '/instance/mysql/statementsummary/' . $server_uuid;
} elsif ( $uri_type eq "stmt_example" ) {
$rep{parent} = '/instance/mysql/statementsummary/' . $server_uuid . "." . $g_dbname . "." . $md5_hash;
} else {
#No Parent
}
# build up the perl hash representation of an inventory transform
my $json = to_json( \%rep, { pretty => 1, utf8 => 1 } );
print Dumper
($json) if $DEBUG >
2;
}
#Did our PUT worked?
sub get_resource {
( my $uri ) = @_;
my $ua = LWP::UserAgent->new;
$ua->agent("MemPut/0.1");
my $req = HTTP::Request->new( GET => $uri );
$req->header( Accept => "application/json" );
# Pass request to the user agent and get a response back
my $res = $ua->request($req);
#print Dumper($res);
# Check the outcome of the response
if ( $res->is_success ) {
print $res->
content if $DEBUG >
1;
print "\n" if $DEBUG >
1;
}
else {
print $res->
status_line,
"\n";
}
}
#Send PUT request to the REST API
sub put_transform {
( my $uri, my $json ) = @_;
my $ua = LWP::UserAgent->new;
$ua->agent("MemPut/0.1");
print "\n\n" .
$uri .
"\n\n\n" if $DEBUG >
4;
my $req = HTTP::Request->new( PUT => $uri );
$req->content_type('application/json');
#if ( defined( $agent_uuid ) ) {
# $req->header( "X-MySQL-Monitor-Agent-UUID" => $agent_uuid );
#}
$req->content($json);
# Pass request to the user agent and get a response back
my $res = $ua->request($req);
#print Dumper($res);
# Check the outcome of the response
if ( $res->is_success ) {
print $res->
content if $DEBUG >
1;
}
else {
print $res->
status_line,
"\n";
}
}
#Send query analyzer related data
sub send_json_data {
# Turn command line into uri and values hash
my %querybase = @_;
my $uri = uri($g_dbname, $md5_hash);
my $json = make_transform( %querybase );
put_transform( $uri, $json );
get_resource($uri);
}
#Simple way to convert literal query into a
#canonical representation
#TODO: Expand this
sub canonicalize {
( my $query ) = @_;
$query =~
s/\ \d\ /\ ? \ /g;
$query =~
s/limit \d+/limit ?/g;
my $canonical_query = $query;
}
#Whenever there is a new line on the log
#This fuction calls assemble_queries()
sub tail_log {
my $file=File::Tail->new(name=>$log_file, maxinterval=>1, reset_tail=>0);
while( defined (my $line=
$file->
read ) ) { print "\n" .
$line .
"\n" if $DEBUG >
3;
assemble_queries( $line );
}
}
#Split the log entry the logging plugin sends.
#Group queries by query text.
#Every $interval number of queries, send them up
sub assemble_queries {
my $interval = 4;
my ($getmicrotime, $session_id, $query_id, $dbname, $query_text,
$query_type, $time_session_conn, $t_exec_time, $exec_time_a_locks,
$rows_returned,
$rows_exam,
$num_tmp_tlbs,
$count_warnings ) =
split(/
(?<!\\
)\,/,
$line );
print "\nLine => " .
$line .
"" if $DEBUG >
4;
my $query = canonicalize($query_text);
print "\nQuery =>" .
$query .
"\n" if $DEBUG >
4;
$querybase->
{$query}->
{database
} =
substr( $dbname,
1,
-1);
$querybase->
{$query}->
{text
} =
substr( $query,
1,
-1);
$querybase->{$query}->{count}++;
$querybase->{$query}->{rows} += $rows_returned;
$querybase->{$query}->{exec_time} += $t_exec_time;
print "Clean query => " .
$querybase->
{$query}->
{text
} .
"\n" if $DEBUG >
4;
if ( defined( $querybase->
{$query}->
{max_rows
} ) ) { $querybase->{$query}->{max_rows} = $rows_returned if ($rows_returned > $querybase->{$query}->{max_rows});
$querybase->{$query}->{min_rows} = $rows_returned if ($rows_returned < $querybase->{$query}->{min_rows});
$querybase->{$query}->{max_exec_time} = $t_exec_time if ($t_exec_time > $querybase->{$query}->{max_exec_time});
$querybase->{$query}->{min_exec_time} = $t_exec_time if ($t_exec_time < $querybase->{$query}->{min_exec_time});
} else {
$querybase->{$query}->{max_rows} = $rows_returned;
$querybase->{$query}->{min_rows} = $rows_returned;
$querybase->{$query}->{max_exec_time} = $t_exec_time;
$querybase->{$query}->{min_exec_time} = $t_exec_time;
}
#print "Counter: " . $counter . "\n";
#print "size of hash: " . keys( %{$querybase->{$query}} ) . ".\n";
#print $query . "\n\n";
if ( ( $counter % $interval ) == 0 ) {
#print STDERR "Writing quan packets ($counter queries sent)\n";
foreach my $query ( keys %
{$querybase} ) { #print "2: " . $query . "\n\n";
my %rep1 =
( values =>
$querybase->
{$query} );
$dbname = $querybase->{$query}->{database};
#print $querybase->{$query}->{text} . "\n";
$md5_hash = md5_hex( $querybase->{$query}->{text} );
$g_dbname = $dbname;
#print "Sending: " . $querybase->{$query}->{text} . "\n";
$uri_type = "stmt_summary";
send_json_data( %rep1 );
##
## Query example
##
delete $querybase->
{$query}->
{max_rows
};
delete $querybase->
{$query}->
{min_rows
};
delete $querybase->
{$query}->
{max_exec_time
};
delete $querybase->
{$query}->
{min_exec_time
};
delete $querybase->
{$query}->
{count
};
$querybase->{$query}->{text} = $query_text;
$querybase->{$query}->{connection_id} = $session_id;
%rep1 =
( values =>
$querybase->
{$query} );
$uri_type = "stmt_example";
$g_dbname = $dbname;
send_json_data( %rep1 );
#print "Deleting: " . $querybase->{$query}->{text} . "\n";
delete( $querybase->
{$query} );
}
}
$counter++;
}
#TODO: This is actually missing on the Service Manager
sub init_transport {
$uri_type = "init_transport";
my $uri = uri();
my %rep = ( attributes =>
{"name"=> "string",
"version" => "string",
"host_id" => "string"
});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json);
get_resource($uri);
## Send initial values
{"name"=> "perl transporter",
"version" => "0.3",
"host_id" => $server_host_uuid
});
$json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
get_resource($uri);
}
#Send basic info related to the drizzle host
sub init_host {
$uri_type = "init_host";
my $uri = uri();
my %rep = ( attributes =>
{"name"=> "string"});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json);
get_resource($uri);
## Send initial values
{"name"=> hostname});
$json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json);
get_resource($uri);
}
#basic info describing the drizzle daemon
sub init_db_server {
$uri_type = "init_db_server";
my $uri = uri();
my %rep = ( attributes =>
{"displayname" => "string",
"server.connected" => "long",
"server.reachable" => "long"
});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json);
get_resource($uri);
## Send initial values
{"displayname" => "drizzle2",
"server.connected" => "1",
"server.reachable" => "1"
});
$json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
get_resource($uri);
}
#This should be all values from show global variables
sub init_db_server_variables{
$uri_type = "init_db_server_variables";
my $uri = uri();
my %rep = ( attributes =>
{"port" => "long",
"version" => "string"
});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
get_resource($uri);
## Send initial values
%rep = (
name => $server_uuid,
{"port" => "9939",
"version" => "7.0.2"
});
$json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
get_resource($uri);
}
#The query analyzer summary table
sub init_stmt_summary{
$uri_type = "init_stmt_summary";
my $uri = uri();
my %rep = ( attributes =>
{"avg_exec_time" => "long",
"count" => "long",
"database" => "string",
"exec_time" => "long",
"max_exec_time" => "long",
"max_rows" => "long",
"min_exec_time" => "long",
"min_rows" => "long",
"query_type" => "string",
"rows" => "long",
"text" => "string",
"text_hash" => "string",
"warnings" => "string"
});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
get_resource($uri);
}
#This shows up on the Query popup -> example tab
sub init_stmt_example{
$uri_type = "init_stmt_example";
my $uri = uri();
my %rep = ( attributes =>
{"comment" => "string",
"connection_id" => "long",
"database" => "string",
"errors" => "long",
"exec_time" => "long",
"explain_plan" => "string",
"query_type" => "string",
"rows" => "long",
"text" => "string",
"warnings" => "string"
});
my $json = make_transform( %rep );
#print Dumper($json);
put_transform( $uri, $json );
#print "\n\nhere\n";
get_resource($uri);
}
1;
__END__
You can use the config.generated-tile-access-timeout property in rest-config.properties to set the maximum amount of time in seconds that the REST API cache will wait for a dynamically generated tile to be made available by the system before it returns with an HTTP 404.
bachelors degree | degree