Skip to content

Commit

Permalink
Merge pull request #56 from hirose31/feature/virtical-line
Browse files Browse the repository at this point in the history
[WIP] Support a virtical line
  • Loading branch information
kazeburo committed Mar 5, 2014
2 parents b31839c + 7987706 commit 348e4b9
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 1 deletion.
82 changes: 82 additions & 0 deletions lib/GrowthForecast/Data.pm
Expand Up @@ -108,6 +108,20 @@ CREATE TABLE IF NOT EXISTS complex_graphs (
UNIQUE (service_name, section_name, graph_name)
)
EOF

$dbh->do(<<EOF);
CREATE TABLE IF NOT EXISTS vrules (
id INTEGER NOT NULL PRIMARY KEY,
graph_path VARCHAR(255) NOT NULL,
time INT UNSIGNED NOT NULL,
color VARCHAR(255) NOT NULL DEFAULT '#FF0000',
description TEXT
)
EOF
$dbh->do(<<EOF);
CREATE INDEX IF NOT EXISTS time_graph_path on vrules (time, graph_path)
EOF

return;
};
}
Expand Down Expand Up @@ -526,5 +540,73 @@ sub get_all_complex_graph_all {
\@ret;
}

sub update_vrule {
my ($self, $graph_path, $time, $color, $desc) = @_;

$self->dbh->query(
'INSERT INTO vrules (graph_path,time,color,description) values (?,?,?,?)',
$graph_path, $time, $color, $desc
);

my $row = $self->dbh->select_row(
'SELECT * FROM vrules WHERE graph_path = ? AND time = ? AND color = ? AND description = ?',
$graph_path, $time, $color, $desc,
);

return $row;
}

# "$span" is a parameter named "t",
# "$from" and "$to" are paramters same nameed.
sub get_vrule {
my ($self, $span, $from, $to, $graph_path) = @_;

my($from_time, $to_time) = (0, time);
# same rule as GrowthForecast::RRD#calc_period
if ( $span eq 'all' ) {
$from_time = 0;
$to_time = 4294967295; # unsigned int max
} elsif ( $span eq 'c' || $span eq 'sc' ) {
my $from_time = HTTP::Date::str2time($from);
die "invalid from date: $from" unless $from_time;
my $to_time = $to ? HTTP::Date::str2time($to) : time;
die "invalid to date: $to" unless $to_time;
die "from($from) is newer than to($to)" if $from_time > $to_time;
} elsif ( $span eq 'h' || $span eq 'sh' ) {
$from_time = time -1 * 60 * 60 * 2;
} elsif ( $span eq 'n' || $span eq 'sn' ) {
$from_time = time -1 * 60 * 60 * 14;
} elsif ( $span eq 'w' ) {
$from_time = time -1 * 60 * 60 * 24 * 8;
} elsif ( $span eq 'm' ) {
$from_time = time -1 * 60 * 60 * 24 * 35;
} elsif ( $span eq 'y' ) {
$from_time = time -1 * 60 * 60 * 24 * 400;
} elsif ( $span eq '3d' ) {
$from_time = time -1 * 60 * 60 * 24 * 3;
} elsif ( $span eq '8h' ) {
$from_time = time -1 * 8 * 60 * 60;
} elsif ( $span eq '4h' ) {
$from_time = time -1 * 4 * 60 * 60;
} else {
$from_time = time -1 * 60 * 60 * 33; # 33 hours
}

my @vrules = ();

my @gp = split '/', substr($graph_path, 1);

my $rows = $self->dbh->select_all(
'SELECT * FROM vrules WHERE (time BETWEEN ? and ?) AND graph_path in ("/",?,?,?)',
$from_time, $to_time,
"/$gp[0]",
"/$gp[0]/$gp[1]",
"/$gp[0]/$gp[1]/$gp[2]",
);
push @vrules, @$rows;

return @vrules;
}

1;

13 changes: 13 additions & 0 deletions lib/GrowthForecast/Data/MySQL.pm
Expand Up @@ -95,6 +95,19 @@ CREATE TABLE IF NOT EXISTS complex_graphs (
UNIQUE (service_name, section_name, graph_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
EOF

$dbh->do(<<EOF);
CREATE TABLE IF NOT EXISTS vrules (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
graph_path VARCHAR(255) NOT NULL COLLATE utf8_bin,
time INT UNSIGNED NOT NULL,
color VARCHAR(255) NOT NULL DEFAULT '#FF0000',
description TEXT,
PRIMARY KEY (id),
INDEX time_graph_path (time, graph_path)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
EOF

return;
};
}
Expand Down
8 changes: 8 additions & 0 deletions lib/GrowthForecast/RRD.pm
Expand Up @@ -366,6 +366,14 @@ sub graph {
sprintf('PRINT:sumupmin:%%.8lf');
}

for my $vrule ($self->{data}->get_vrule($span, $period, $end, '/'.join('/',@{$datas}{qw(service_name section_name graph_name)}))) {
push @opt, join(":",
'VRULE',
join("", $vrule->{time}, $vrule->{color}),
($args->{vrule_legend} ? ($vrule->{description}||()) : ()),
);
}

my @graphv;
eval {
@graphv = RRDs::graph(map { Encode::encode_utf8($_) } @opt);
Expand Down
132 changes: 131 additions & 1 deletion lib/GrowthForecast/Web.pm
Expand Up @@ -33,6 +33,7 @@ sub rrd {
root_dir => $self->root_dir,
rrdcached => $self->rrdcached,
disable_subtract => $self->disable_subtract,
data => $self->data,
);
$self->{__rrd};
}
Expand Down Expand Up @@ -582,6 +583,12 @@ sub graph_validator {
[['CHOICE', qw/AVERAGE MAX/], 'invalid consolidation function'],
],
},
'vrule_legend' => {
default => 1,
rule => [
[['CHOICE',qw/0 1/],'invalid vrule_legend flag'],
],
},
];
}

Expand Down Expand Up @@ -675,7 +682,8 @@ get '/{method:(?:xport|graph|summary)}/:service_name/:section_name/:graph_name'

if ( $c->args->{method} eq 'graph' ) {
my ($img,$data) = $self->rrd->graph(
$c->stash->{graph}, $result->valid->as_hashref
$c->stash->{graph}, $result->valid->as_hashref,
$self->data,
);
$c->res->content_type('image/png');
$c->res->body($img);
Expand Down Expand Up @@ -1155,5 +1163,127 @@ post '/json/edit/{type:(?:graph|complex)}/:id' => sub {
$c->render_json({ error => 0 });
};

post '/vrule/api/:service_name/:section_name/:graph_name' => sub {
my ( $self, $c ) = @_; $self->add_vrule($c);
};
post '/vrule/api/:service_name/:section_name' => sub {
my ( $self, $c ) = @_; $self->add_vrule($c);
};
post '/vrule/api/:service_name' => sub {
my ( $self, $c ) = @_; $self->add_vrule($c);
};
post '/vrule/api' => sub {
my ( $self, $c ) = @_; $self->add_vrule($c);
};

sub add_vrule {
my ( $self, $c ) = @_;
my $result = $c->req->validator([
'time' => {
default => time(),
rule => [
['INT', 'a INT number is required for "time"']
],
},
'color' => {
default => '#FF0000',
rule => [
[sub{ length($_[1]) == 0 || $_[1] =~ m!^#[0-9A-F]{6}$!i }, 'invalid color format'],
],
},
'description' => {
default => '',
rule => [],
},
]);

if ( $result->has_error ) {
my $res = $c->render_json({
error => 1,
messages => $result->messages
});
$res->status(400);
return $res;
}

my $row;
eval {
my $graph_path = '/'.join('/', $c->args->{service_name}||(), $c->args->{section_name}||(), $c->args->{graph_name}||());
$row = $self->data->update_vrule(
$graph_path,
$result->valid('time'),
$result->valid('color'),
$result->valid('description'),
);
};
if ( $@ ) {
die sprintf "Error:%s %s/%s/%s => %s,%s",
$@, $c->args->{service_name}, $c->args->{section_name}, $c->args->{graph_name},
$result->valid('time'), $result->valid('color');
}

$c->render_json({error=>0, data => $row});
};

get '/vrule/summary/:service_name/:section_name/:graph_name' => sub {
my ( $self, $c ) = @_; $self->summarize_vrule($c);
};
get '/vrule/summary/:service_name/:section_name' => sub {
my ( $self, $c ) = @_; $self->summarize_vrule($c);
};
get '/vrule/summary/:service_name' => sub {
my ( $self, $c ) = @_; $self->summarize_vrule($c);
};
get '/vrule/summary' => sub {
my ( $self, $c ) = @_; $self->summarize_vrule($c);
};

sub summarize_vrule {
my ( $self, $c ) = @_;
my $result = $c->req->validator([
't' => {
default => 'all',
rule => [
[['CHOICE',qw/all y m w 3d s3d d sd 8h s8h 4h s4h h sh n sn c sc/],'invalid drawing term'],
],
},
'from' => {
default => localtime(time-86400*8)->strftime('%Y/%m/%d %T'),
rule => [
[sub{ HTTP::Date::str2time($_[1]) }, 'invalid From datetime'],
],
},
'to' => {
default => localtime()->strftime('%Y/%m/%d %T'),
rule => [
[sub{ HTTP::Date::str2time($_[1]) }, 'invalid To datetime'],
],
},
]);

if ( $result->has_error ) {
my $res = $c->render_json({
error => 1,
messages => $result->messages
});
$res->status(400);
return $res;
}

my $graph_path = '/'.join('/', $c->args->{service_name}||(), $c->args->{section_name}||(), $c->args->{graph_name}||());

my @vrules;
eval {
@vrules = $self->data->get_vrule($result->valid('t'), $result->valid('from'), $result->valid('to'), $graph_path);
};
if ( $@ ) {
die sprintf "Error:%s %s/%s/%s => %s,%s,%s",
$@, $c->args->{service_name}, $c->args->{section_name}, $c->args->{graph_name},
$result->valid('t'), $result->valid('from') , $result->valid('to');
}

$c->render_json(\@vrules);
};

1;

0 comments on commit 348e4b9

Please sign in to comment.